Add BIM section plane tool
This commit is contained in:
parent
4638acc04b
commit
e343412468
|
|
@ -1911,11 +1911,102 @@ header {
|
||||||
background: var(--toolbar-bg-active);
|
background: var(--toolbar-bg-active);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tb-btn.disabled,
|
||||||
|
.tb-btn:disabled {
|
||||||
|
cursor: default;
|
||||||
|
opacity: 0.45;
|
||||||
|
transform: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
body[data-viewer-mode="guest"] .bottom-toolbar,
|
body[data-viewer-mode="guest"] .bottom-toolbar,
|
||||||
|
body[data-viewer-mode="guest"] .section-toolbar,
|
||||||
|
body[data-viewer-mode="guest"] .section-overview,
|
||||||
body[data-viewer-mode="guest"] .inspector-restore-tray {
|
body[data-viewer-mode="guest"] .inspector-restore-tray {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.section-toolbar {
|
||||||
|
position: fixed;
|
||||||
|
left: calc(12px + var(--tb-size, 52px) + 10px);
|
||||||
|
bottom: 12px;
|
||||||
|
z-index: 16;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 6px;
|
||||||
|
border: 1px solid var(--toolbar-border);
|
||||||
|
border-radius: var(--tb-radius, 12px);
|
||||||
|
background: color-mix(in srgb, var(--toolbar-bg) 88%, transparent);
|
||||||
|
box-shadow: 0 18px 34px rgba(0, 0, 0, 0.28);
|
||||||
|
backdrop-filter: blur(18px) saturate(124%);
|
||||||
|
-webkit-backdrop-filter: blur(18px) saturate(124%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-toolbar.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-tool-btn {
|
||||||
|
width: 38px;
|
||||||
|
height: 38px;
|
||||||
|
display: inline-grid;
|
||||||
|
place-items: center;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: calc(var(--tb-radius, 12px) - 4px);
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text);
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 120ms ease, border-color 120ms ease, transform 100ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-tool-btn:hover,
|
||||||
|
.section-tool-btn.active {
|
||||||
|
border-color: var(--toolbar-outline, rgba(76, 224, 210, 0.7));
|
||||||
|
background: var(--toolbar-bg-active);
|
||||||
|
color: var(--modal-btn-primary-contrast, #15170f);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-tool-btn:active {
|
||||||
|
transform: translateY(1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-tool-btn svg {
|
||||||
|
display: block;
|
||||||
|
width: 21px;
|
||||||
|
height: 21px;
|
||||||
|
fill: none;
|
||||||
|
stroke: currentColor;
|
||||||
|
stroke-width: 1.8;
|
||||||
|
stroke-linecap: round;
|
||||||
|
stroke-linejoin: round;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-axis-btn {
|
||||||
|
letter-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-overview {
|
||||||
|
position: fixed;
|
||||||
|
left: calc(12px + var(--tb-size, 52px) + 10px);
|
||||||
|
bottom: 66px;
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
z-index: 14;
|
||||||
|
display: none;
|
||||||
|
border: 1px solid var(--toolbar-border);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: color-mix(in srgb, var(--toolbar-bg) 84%, transparent);
|
||||||
|
box-shadow: 0 18px 34px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
body[data-section-mode="active"] .section-overview {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.templates-panel {
|
.templates-panel {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: var(--templates-left, 72px);
|
left: var(--templates-left, 72px);
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,9 @@ const measureButton = document.querySelector('[data-action="measure"]');
|
||||||
const settingsButton = document.querySelector('[data-action="settings"]');
|
const settingsButton = document.querySelector('[data-action="settings"]');
|
||||||
const templatesButton = document.querySelector('[data-action="templates"]');
|
const templatesButton = document.querySelector('[data-action="templates"]');
|
||||||
const shareButton = document.querySelector('[data-action="share"]');
|
const shareButton = document.querySelector('[data-action="share"]');
|
||||||
|
const sectionButton = document.querySelector('[data-action="section"]');
|
||||||
|
const sectionToolbar = document.getElementById("sectionToolbar");
|
||||||
|
const sectionOverviewCanvas = document.getElementById("sectionPlanesOverview");
|
||||||
const projectionToggle = document.querySelector('[data-action="projection"]');
|
const projectionToggle = document.querySelector('[data-action="projection"]');
|
||||||
const treeContainer = document.getElementById("treeContainer");
|
const treeContainer = document.getElementById("treeContainer");
|
||||||
const displayModeControl = document.getElementById("displayModeControl");
|
const displayModeControl = document.getElementById("displayModeControl");
|
||||||
|
|
@ -250,6 +253,11 @@ let measurePlugin = null;
|
||||||
let measureControl = null;
|
let measureControl = null;
|
||||||
let measureActive = false;
|
let measureActive = false;
|
||||||
let activeMeasurementId = null;
|
let activeMeasurementId = null;
|
||||||
|
let sectionPlanesPlugin = null;
|
||||||
|
let activeSectionPlaneId = null;
|
||||||
|
let sectionPlaneCounter = 0;
|
||||||
|
let sectionModeActive = false;
|
||||||
|
let activeSectionAxis = null;
|
||||||
let objectContextModal = null;
|
let objectContextModal = null;
|
||||||
let mathUtil = null;
|
let mathUtil = null;
|
||||||
let selectionState = null; // { ids, modelId, pivotCenter, baseTransforms: Map, transform }
|
let selectionState = null; // { ids, modelId, pivotCenter, baseTransforms: Map, transform }
|
||||||
|
|
@ -454,6 +462,9 @@ const applyRuntimeMode = () => {
|
||||||
if (dropZone) {
|
if (dropZone) {
|
||||||
dropZone.style.pointerEvents = isGuestMode() ? "none" : "";
|
dropZone.style.pointerEvents = isGuestMode() ? "none" : "";
|
||||||
}
|
}
|
||||||
|
if (sectionToolbar && isGuestMode()) {
|
||||||
|
sectionToolbar.classList.add("hidden");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const initializeRuntimeMode = async () => {
|
const initializeRuntimeMode = async () => {
|
||||||
|
|
@ -1171,6 +1182,155 @@ const clearMeasurements = () => {
|
||||||
closeMeasurementModal();
|
closeMeasurementModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getSectionPlaneIds = () => Object.keys(sectionPlanesPlugin?.sectionPlanes || {});
|
||||||
|
|
||||||
|
const getActiveSectionPlane = () => {
|
||||||
|
if (!sectionPlanesPlugin) return null;
|
||||||
|
if (activeSectionPlaneId && sectionPlanesPlugin.sectionPlanes?.[activeSectionPlaneId]) {
|
||||||
|
return sectionPlanesPlugin.sectionPlanes[activeSectionPlaneId];
|
||||||
|
}
|
||||||
|
const firstId = getSectionPlaneIds()[0] || null;
|
||||||
|
activeSectionPlaneId = firstId;
|
||||||
|
return firstId ? sectionPlanesPlugin.sectionPlanes[firstId] : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setAllSectionPlanesActive = (active) => {
|
||||||
|
getSectionPlaneIds().forEach((id) => {
|
||||||
|
const sectionPlane = sectionPlanesPlugin?.sectionPlanes?.[id];
|
||||||
|
if (sectionPlane) {
|
||||||
|
sectionPlane.active = !!active;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSectionCenter = () => {
|
||||||
|
const sceneAABB = viewer?.scene?.aabb;
|
||||||
|
const aabb = Array.isArray(sceneAABB) || ArrayBuffer.isView(sceneAABB)
|
||||||
|
? Array.from(sceneAABB)
|
||||||
|
: null;
|
||||||
|
const center = centerFromAABB(aabb);
|
||||||
|
return center.every((value) => Number.isFinite(value)) ? center : [0, 0, 0];
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCameraSectionDir = () => {
|
||||||
|
const eye = snapshotVec(viewer?.camera?.eye) || [0, 0, 1];
|
||||||
|
const look = snapshotVec(viewer?.camera?.look) || [0, 0, 0];
|
||||||
|
return normalizeVec3([
|
||||||
|
look[0] - eye[0],
|
||||||
|
look[1] - eye[1],
|
||||||
|
look[2] - eye[2],
|
||||||
|
], [0, 0, -1]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const setSectionAxisActive = (axis) => {
|
||||||
|
activeSectionAxis = axis || null;
|
||||||
|
sectionToolbar?.querySelectorAll("[data-section-action]").forEach((btn) => {
|
||||||
|
btn.classList.toggle("active", !!axis && btn.dataset.sectionAction === axis);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const setSectionModeActive = (active) => {
|
||||||
|
sectionModeActive = !!active && !!sectionPlanesPlugin && getSectionPlaneIds().length > 0 && !isGuestMode();
|
||||||
|
sectionButton?.classList.toggle("active", sectionModeActive);
|
||||||
|
sectionToolbar?.classList.toggle("hidden", !sectionModeActive);
|
||||||
|
document.body.dataset.sectionMode = sectionModeActive ? "active" : "";
|
||||||
|
sectionPlanesPlugin?.setOverviewVisible?.(sectionModeActive);
|
||||||
|
if (!sectionModeActive) {
|
||||||
|
setSectionAxisActive(null);
|
||||||
|
sectionPlanesPlugin?.hideControl?.();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateSectionControls = () => {
|
||||||
|
const available = !!sectionPlanesPlugin && !isGuestMode() && activeModels.length > 0;
|
||||||
|
if (sectionButton) {
|
||||||
|
sectionButton.disabled = !available;
|
||||||
|
sectionButton.classList.toggle("disabled", !available);
|
||||||
|
sectionButton.classList.toggle("active", available && sectionModeActive);
|
||||||
|
}
|
||||||
|
if (!available) {
|
||||||
|
sectionToolbar?.classList.add("hidden");
|
||||||
|
document.body.dataset.sectionMode = "";
|
||||||
|
sectionPlanesPlugin?.setOverviewVisible?.(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const createOrUpdateSectionPlane = (axis = "camera") => {
|
||||||
|
if (!sectionPlanesPlugin) {
|
||||||
|
showError("Разрез недоступен в текущей сборке SDK");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!activeModels.length) {
|
||||||
|
showError("Сначала загрузите модель");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
setMeasureActive(false);
|
||||||
|
const dirs = {
|
||||||
|
camera: getCameraSectionDir(),
|
||||||
|
x: [1, 0, 0],
|
||||||
|
y: [0, 1, 0],
|
||||||
|
z: [0, 0, 1],
|
||||||
|
};
|
||||||
|
const dir = dirs[axis] || dirs.camera;
|
||||||
|
const pos = getSectionCenter();
|
||||||
|
let sectionPlane = getActiveSectionPlane();
|
||||||
|
|
||||||
|
if (!sectionPlane) {
|
||||||
|
const id = `sectionPlane-${++sectionPlaneCounter}`;
|
||||||
|
sectionPlane = sectionPlanesPlugin.createSectionPlane({ id, pos, dir });
|
||||||
|
activeSectionPlaneId = sectionPlane.id || id;
|
||||||
|
} else {
|
||||||
|
sectionPlane.pos = pos;
|
||||||
|
sectionPlane.dir = dir;
|
||||||
|
sectionPlane.active = true;
|
||||||
|
activeSectionPlaneId = sectionPlane.id || activeSectionPlaneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
sectionPlanesPlugin.showControl(activeSectionPlaneId);
|
||||||
|
setSectionModeActive(true);
|
||||||
|
setSectionAxisActive(axis);
|
||||||
|
setStatus("Разрез включён");
|
||||||
|
rearmCameraControl();
|
||||||
|
return sectionPlane;
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearSectionPlanes = () => {
|
||||||
|
sectionPlanesPlugin?.clear?.();
|
||||||
|
activeSectionPlaneId = null;
|
||||||
|
setSectionModeActive(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const flipSectionPlanes = () => {
|
||||||
|
if (!getActiveSectionPlane()) {
|
||||||
|
createOrUpdateSectionPlane("camera");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setAllSectionPlanesActive(true);
|
||||||
|
sectionPlanesPlugin?.flipSectionPlanes?.();
|
||||||
|
sectionPlanesPlugin?.showControl?.(activeSectionPlaneId);
|
||||||
|
setSectionModeActive(true);
|
||||||
|
setStatus("Разрез инвертирован");
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleSectionPlanes = () => {
|
||||||
|
if (sectionModeActive) {
|
||||||
|
setAllSectionPlanesActive(false);
|
||||||
|
setSectionModeActive(false);
|
||||||
|
setStatus("Разрез выключен");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (getSectionPlaneIds().length > 0) {
|
||||||
|
setAllSectionPlanesActive(true);
|
||||||
|
activeSectionPlaneId = activeSectionPlaneId || getSectionPlaneIds()[0];
|
||||||
|
sectionPlanesPlugin?.showControl?.(activeSectionPlaneId);
|
||||||
|
setSectionModeActive(true);
|
||||||
|
setStatus("Разрез включён");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
createOrUpdateSectionPlane("camera");
|
||||||
|
};
|
||||||
|
|
||||||
const rebuildNavCube = (sdk) => {
|
const rebuildNavCube = (sdk) => {
|
||||||
if (!navCubeCanvas || !viewer) return;
|
if (!navCubeCanvas || !viewer) return;
|
||||||
const cubeColor = cssValue("--cube-base", "#7b3fff");
|
const cubeColor = cssValue("--cube-base", "#7b3fff");
|
||||||
|
|
@ -1257,6 +1417,7 @@ const updatePanelsVisibility = () => {
|
||||||
projectNameInput.value = "";
|
projectNameInput.value = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
updateSectionControls();
|
||||||
applyRuntimeMode();
|
applyRuntimeMode();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1990,6 +2151,7 @@ const destroyAllModels = ({ preserveMeta = false } = {}) => {
|
||||||
gizmo?.clearTarget();
|
gizmo?.clearTarget();
|
||||||
treeView?.unShowNode?.();
|
treeView?.unShowNode?.();
|
||||||
clearMeasurements();
|
clearMeasurements();
|
||||||
|
clearSectionPlanes();
|
||||||
selectionState = null;
|
selectionState = null;
|
||||||
lastSelection = { ids: [], modelId: null };
|
lastSelection = { ids: [], modelId: null };
|
||||||
activeTransformTarget = null;
|
activeTransformTarget = null;
|
||||||
|
|
@ -2852,7 +3014,7 @@ const initViewer = async () => {
|
||||||
|
|
||||||
const sdk = await import(SDK_URL);
|
const sdk = await import(SDK_URL);
|
||||||
sdkRef = sdk;
|
sdkRef = sdk;
|
||||||
const { Viewer, NavCubePlugin, DistanceMeasurementsPlugin, DistanceMeasurementsMouseControl } = sdk;
|
const { Viewer, NavCubePlugin, DistanceMeasurementsPlugin, DistanceMeasurementsMouseControl, SectionPlanesPlugin } = sdk;
|
||||||
mathUtil = sdk.math;
|
mathUtil = sdk.math;
|
||||||
if (headerEl && homeButton && !homeButton.querySelector(".ue-logo")) {
|
if (headerEl && homeButton && !homeButton.querySelector(".ue-logo")) {
|
||||||
const logoEl = createLogo();
|
const logoEl = createLogo();
|
||||||
|
|
@ -2931,6 +3093,22 @@ const initViewer = async () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SectionPlanesPlugin && sectionOverviewCanvas) {
|
||||||
|
sectionPlanesPlugin = new SectionPlanesPlugin(viewer, {
|
||||||
|
overviewCanvasId: "sectionPlanesOverview",
|
||||||
|
overviewVisible: false,
|
||||||
|
});
|
||||||
|
sectionPlanesPlugin.setOverviewVisible(false);
|
||||||
|
setSectionModeActive(false);
|
||||||
|
} else {
|
||||||
|
console.warn("SectionPlanesPlugin is not available in the loaded SDK build");
|
||||||
|
if (sectionButton) {
|
||||||
|
sectionButton.classList.add("disabled");
|
||||||
|
sectionButton.disabled = true;
|
||||||
|
sectionButton.title = "Разрез недоступен";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (DistanceMeasurementsPlugin && DistanceMeasurementsMouseControl) {
|
if (DistanceMeasurementsPlugin && DistanceMeasurementsMouseControl) {
|
||||||
measurePlugin = new DistanceMeasurementsPlugin(viewer, {
|
measurePlugin = new DistanceMeasurementsPlugin(viewer, {
|
||||||
defaultAxisVisible: false,
|
defaultAxisVisible: false,
|
||||||
|
|
@ -4308,6 +4486,8 @@ const loadProjectSnapshot = async (project) => {
|
||||||
} else if (action === "measure") {
|
} else if (action === "measure") {
|
||||||
if (!measurePlugin || !measureControl) return;
|
if (!measurePlugin || !measureControl) return;
|
||||||
setMeasureActive(!measureActive);
|
setMeasureActive(!measureActive);
|
||||||
|
} else if (action === "section") {
|
||||||
|
toggleSectionPlanes();
|
||||||
} else if (action === "projection") {
|
} else if (action === "projection") {
|
||||||
toggleProjection();
|
toggleProjection();
|
||||||
} else if (action === "share") {
|
} else if (action === "share") {
|
||||||
|
|
@ -4318,6 +4498,21 @@ const loadProjectSnapshot = async (project) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sectionToolbar?.addEventListener("click", (e) => {
|
||||||
|
if (isGuestMode()) return;
|
||||||
|
const btn = e.target.closest("[data-section-action]");
|
||||||
|
if (!btn) return;
|
||||||
|
const action = btn.dataset.sectionAction;
|
||||||
|
if (action === "camera" || action === "x" || action === "y" || action === "z") {
|
||||||
|
createOrUpdateSectionPlane(action);
|
||||||
|
} else if (action === "flip") {
|
||||||
|
flipSectionPlanes();
|
||||||
|
} else if (action === "clear") {
|
||||||
|
clearSectionPlanes();
|
||||||
|
setStatus("Разрез выключен");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function updateTransformInputs(transform) {
|
function updateTransformInputs(transform) {
|
||||||
const empty = {
|
const empty = {
|
||||||
position: ["", "", ""],
|
position: ["", "", ""],
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@500;600;700&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@500;600;700&display=swap" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="./dcViewer.css?v=17">
|
<link rel="stylesheet" href="./dcViewer.css?v=18">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
|
|
@ -107,6 +107,7 @@
|
||||||
<section class="viewer-wrapper">
|
<section class="viewer-wrapper">
|
||||||
<canvas id="viewerCanvas"></canvas>
|
<canvas id="viewerCanvas"></canvas>
|
||||||
<canvas id="navCube"></canvas>
|
<canvas id="navCube"></canvas>
|
||||||
|
<canvas id="sectionPlanesOverview" class="section-overview" width="150" height="150"></canvas>
|
||||||
<div class="drop-hint" id="dropZone">
|
<div class="drop-hint" id="dropZone">
|
||||||
<div class="drop-center">
|
<div class="drop-center">
|
||||||
<div class="drop-plus">+</div>
|
<div class="drop-plus">+</div>
|
||||||
|
|
@ -292,6 +293,14 @@
|
||||||
<path d="m13 7 2 2"></path>
|
<path d="m13 7 2 2"></path>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
<button class="tb-btn" data-action="section" title="Разрез" aria-label="Разрез">
|
||||||
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||||
|
<path d="M4.5 7.25 12 3.5l7.5 3.75L12 11 4.5 7.25Z"></path>
|
||||||
|
<path d="M4.5 16.75 12 20.5l7.5-3.75"></path>
|
||||||
|
<path d="M12 11v9.5"></path>
|
||||||
|
<path d="M6.25 4.5 17.75 19.5"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
<button class="tb-btn" data-action="projection" title="Перспектива / аксонометрия">A</button>
|
<button class="tb-btn" data-action="projection" title="Перспектива / аксонометрия">A</button>
|
||||||
<button class="tb-btn" data-action="share" title="Поделиться моделью" aria-label="Поделиться моделью">
|
<button class="tb-btn" data-action="share" title="Поделиться моделью" aria-label="Поделиться моделью">
|
||||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||||
|
|
@ -308,9 +317,38 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="sectionToolbar" class="section-toolbar hidden" aria-label="Управление разрезом">
|
||||||
|
<button class="section-tool-btn" data-section-action="camera" type="button" title="По камере" aria-label="По камере">
|
||||||
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||||
|
<path d="M4.5 12s2.75-5 7.5-5 7.5 5 7.5 5-2.75 5-7.5 5-7.5-5-7.5-5Z"></path>
|
||||||
|
<path d="M12 14.75A2.75 2.75 0 1 0 12 9.25a2.75 2.75 0 0 0 0 5.5Z"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button class="section-tool-btn section-axis-btn" data-section-action="x" type="button" title="Ось X" aria-label="Ось X">X</button>
|
||||||
|
<button class="section-tool-btn section-axis-btn" data-section-action="y" type="button" title="Ось Y" aria-label="Ось Y">Y</button>
|
||||||
|
<button class="section-tool-btn section-axis-btn" data-section-action="z" type="button" title="Ось Z" aria-label="Ось Z">Z</button>
|
||||||
|
<button class="section-tool-btn" data-section-action="flip" type="button" title="Инвертировать" aria-label="Инвертировать">
|
||||||
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||||
|
<path d="M7.5 7.5h8a3.5 3.5 0 0 1 0 7h-7"></path>
|
||||||
|
<path d="m10.5 4.5-3 3 3 3"></path>
|
||||||
|
<path d="m13.5 19.5 3-3-3-3"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button class="section-tool-btn" data-section-action="clear" type="button" title="Удалить разрез" aria-label="Удалить разрез">
|
||||||
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||||
|
<path d="M5 7h14"></path>
|
||||||
|
<path d="M9 7V5h6v2"></path>
|
||||||
|
<path d="M8 10v8"></path>
|
||||||
|
<path d="M12 10v8"></path>
|
||||||
|
<path d="M16 10v8"></path>
|
||||||
|
<path d="M7 7l1 13h8l1-13"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<input id="fileInput" class="hidden" type="file"
|
<input id="fileInput" class="hidden" type="file"
|
||||||
accept=".xkt,.glb,.gltf,.bim,.las,.laz,.obj,.stl">
|
accept=".xkt,.glb,.gltf,.bim,.las,.laz,.obj,.stl">
|
||||||
|
|
||||||
<script type="module" src="./dcViewer.js?v=22"></script>
|
<script type="module" src="./dcViewer.js?v=23"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue