@vitrosoftware/common-ui-ts 1.1.122 → 1.1.124
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/css/std/controls/checkbox/checkbox.css +4 -0
- package/css/std/controls/checkbox/img/checkbox-indeterminate.svg +4 -0
- package/css/std/controls/date-picker/date-picker.css +1 -25
- package/css/std/controls/dxf-viewer/annotation.css +85 -0
- package/css/std/controls/dxf-viewer/common.css +24 -0
- package/css/std/controls/dxf-viewer/dxf-viewer-index.css +14081 -0
- package/css/std/controls/dxf-viewer/dxf-viewer.css +194 -0
- package/css/std/controls/dxf-viewer/img/cancel-dark-grey.svg +5 -0
- package/css/std/controls/dxf-viewer/img/collapse-bottom.svg +5 -0
- package/css/std/controls/dxf-viewer/img/collapse-up-blue.svg +5 -0
- package/css/std/controls/dxf-viewer/img/delete-active.svg +11 -0
- package/css/std/controls/dxf-viewer/img/delete.svg +11 -0
- package/css/std/controls/dxf-viewer/img/draw-annotation.svg +3 -0
- package/css/std/controls/dxf-viewer/img/invisible-eye.svg +4 -0
- package/css/std/controls/dxf-viewer/img/show-annotation.svg +3 -0
- package/css/std/controls/dxf-viewer/img/sidebar-layers-toggle.svg +6 -0
- package/css/std/controls/dxf-viewer/img/sidebar-notes-toggle.svg +5 -0
- package/css/std/controls/dxf-viewer/img/sidebar-resizer.svg +6 -0
- package/css/std/controls/dxf-viewer/img/sidebar-toggle.svg +7 -0
- package/css/std/controls/dxf-viewer/img/visible-eye.svg +4 -0
- package/css/std/controls/dxf-viewer/img/zoom-in.svg +6 -0
- package/css/std/controls/dxf-viewer/img/zoom-out.svg +5 -0
- package/css/std/controls/dxf-viewer/layer-list.css +104 -0
- package/css/std/controls/dxf-viewer/panel.css +34 -0
- package/css/std/controls/dxf-viewer/prop-inspector.css +102 -0
- package/css/std/controls/dxf-viewer/select.css +111 -0
- package/css/std/controls/dxf-viewer/sidebar.css +190 -0
- package/css/std/controls/dxf-viewer/thumbnail-list.css +65 -0
- package/css/std/controls/dxf-viewer/toolbar.css +117 -0
- package/css/std/controls/dxf-viewer/treeview.css +3 -0
- package/css/std/controls/dxf-viewer/treeview.panel.css +108 -0
- package/css/std/controls/error-message/error-message.css +22 -0
- package/css/std/controls/image-picker/image-picker.css +0 -26
- package/css/std/controls/input/input.css +1 -24
- package/css/std/controls/issue-tile/issue-tile-header.css +1 -0
- package/css/std/controls/login/ntlm-authentication-form.css +9 -12
- package/css/std/controls/lookup-picker/lookup-picker-value-list.css +38 -2
- package/css/std/controls/lookup-picker/lookup-picker.css +1 -25
- package/css/std/controls/table-view/treegrid-context-menu.css +44 -18
- package/css/std/controls/table-view/treegrid-message.css +4 -4
- package/css/std/controls/time-picker/time-picker.css +1 -25
- package/dist/index.css +81 -143
- package/dist/index.js +15137 -489
- package/dist/index.js.map +1 -1
- package/dist/src/controls/Checkbox/Checkbox.d.ts +1 -0
- package/dist/src/controls/DxfViewer/DxfViewer.d.ts +6 -0
- package/dist/src/controls/DxfViewer/DxfViewerContext.d.ts +31 -0
- package/dist/src/controls/DxfViewer/Layer.d.ts +9 -0
- package/dist/src/controls/DxfViewer/LayerList.d.ts +11 -0
- package/dist/src/controls/DxfViewer/Thumbnail.d.ts +7 -0
- package/dist/src/controls/DxfViewer/ThumbnailList.d.ts +6 -0
- package/dist/src/controls/DxfViewer/Viewer.d.ts +6 -0
- package/dist/src/controls/ErrorMessage/ErrorMessage.d.ts +6 -0
- package/dist/src/controls/Login/FormRef.d.ts +3 -0
- package/dist/src/controls/Login/LoginConstants.d.ts +2 -1
- package/dist/src/controls/Login/LoginFormRef.d.ts +2 -2
- package/dist/src/controls/Login/NTLMAuthenticationForm.d.ts +5 -2
- package/dist/src/controls/LookupPicker/LookupPicker.d.ts +2 -0
- package/dist/src/controls/LookupPicker/ValueList.d.ts +2 -0
- package/dist/src/controls/TableView/TableViewConstants.d.ts +11 -0
- package/dist/src/controls/TableView/TreeGridTableViewContextImpl.d.ts +1 -0
- package/dist/src/controls/TreeView/TreeView.d.ts +4 -0
- package/dist/src/controls/TreeView/TreeViewConfig.d.ts +3 -0
- package/dist/src/controls/TreeView/TreeViewConstants.d.ts +2 -1
- package/dist/src/index.d.ts +7 -1
- package/lib/dxf-viewer/BatchingKey.js +91 -0
- package/lib/dxf-viewer/DxfFetcher.js +39 -0
- package/lib/dxf-viewer/DxfScene.js +2695 -0
- package/lib/dxf-viewer/DxfViewer.js +1056 -0
- package/lib/dxf-viewer/DxfWorker.js +229 -0
- package/lib/dxf-viewer/DynamicBuffer.js +100 -0
- package/lib/dxf-viewer/HatchCalculator.js +345 -0
- package/lib/dxf-viewer/LinearDimension.js +323 -0
- package/lib/dxf-viewer/MTextFormatParser.js +211 -0
- package/lib/dxf-viewer/MaterialKey.js +37 -0
- package/lib/dxf-viewer/OrbitControls.js +1253 -0
- package/lib/dxf-viewer/Pattern.js +94 -0
- package/lib/dxf-viewer/RBTree.js +471 -0
- package/lib/dxf-viewer/TextRenderer.js +1038 -0
- package/lib/dxf-viewer/index.js +42 -0
- package/lib/dxf-viewer/math/Matrix2.js +77 -0
- package/lib/dxf-viewer/math/utils.js +59 -0
- package/lib/dxf-viewer/parser/AutoCadColorIndex.js +265 -0
- package/lib/dxf-viewer/parser/DimStyleCodes.js +33 -0
- package/lib/dxf-viewer/parser/DxfArrayScanner.js +143 -0
- package/lib/dxf-viewer/parser/DxfParser.js +980 -0
- package/lib/dxf-viewer/parser/ExtendedDataParse-My.js +91 -0
- package/lib/dxf-viewer/parser/ExtendedDataParser.js +123 -0
- package/lib/dxf-viewer/parser/ParseHelpers.js +142 -0
- package/lib/dxf-viewer/parser/entities/3dface.js +83 -0
- package/lib/dxf-viewer/parser/entities/arc.js +38 -0
- package/lib/dxf-viewer/parser/entities/attdef.js +89 -0
- package/lib/dxf-viewer/parser/entities/attrib.js +34 -0
- package/lib/dxf-viewer/parser/entities/attribute.js +109 -0
- package/lib/dxf-viewer/parser/entities/circle.js +43 -0
- package/lib/dxf-viewer/parser/entities/dimension.js +72 -0
- package/lib/dxf-viewer/parser/entities/ellipse.js +46 -0
- package/lib/dxf-viewer/parser/entities/hatch.js +343 -0
- package/lib/dxf-viewer/parser/entities/insert.js +62 -0
- package/lib/dxf-viewer/parser/entities/leader.js +84 -0
- package/lib/dxf-viewer/parser/entities/line.js +34 -0
- package/lib/dxf-viewer/parser/entities/lwpolyline.js +100 -0
- package/lib/dxf-viewer/parser/entities/mtext.js +54 -0
- package/lib/dxf-viewer/parser/entities/point.js +35 -0
- package/lib/dxf-viewer/parser/entities/polyline.js +92 -0
- package/lib/dxf-viewer/parser/entities/solid.js +40 -0
- package/lib/dxf-viewer/parser/entities/spline.js +70 -0
- package/lib/dxf-viewer/parser/entities/text.js +47 -0
- package/lib/dxf-viewer/parser/entities/vertex.js +62 -0
- package/lib/dxf-viewer/parser/entities/viewport.js +56 -0
- package/lib/dxf-viewer/parser/objects/dictionary.js +29 -0
- package/lib/dxf-viewer/parser/objects/layout.js +35 -0
- package/lib/dxf-viewer/parser/objects/xrecord.js +29 -0
- package/lib/opentype/opentype.module.js +14571 -0
- package/lib/three/CSS2DRenderer.js +235 -0
- package/lib/three/three.module.js +49912 -0
- package/package.json +12 -10
- package/src/controls/BimViewer/js/bim-viewer.js +2 -2
- package/src/controls/DxfViewer/js/dxf-viewer.js +3580 -0
- package/src/controls/PdfViewer/js/pdf-viewer.js +1 -1
- package/css/std/controls/input/img/error-message.svg +0 -6
- package/css/std/controls/lookup-picker/img/error-message.svg +0 -6
- package/css/std/controls/time-picker/img/error-message.svg +0 -6
- /package/css/std/controls/{date-picker → error-message}/img/error-message.svg +0 -0
|
@@ -0,0 +1,3580 @@
|
|
|
1
|
+
import * as three from '/resource/dxfViewer/js/three/three.module.js?version=1.1.124';
|
|
2
|
+
import { Matrix3, Vector2 } from '/resource/dxfViewer/js/three/three.module.js?version=1.1.124';
|
|
3
|
+
import { Batch, DxfViewer, Layer } from '/resource/dxfViewer/js/viewer/DxfViewer.js?version=1.1.124';
|
|
4
|
+
import { Block as SceneBlock } from '/resource/dxfViewer/js/viewer/DxfScene.js?version=1.1.124';
|
|
5
|
+
import { Block } from '/resource/dxfViewer/js/viewer/DxfViewer.js?version=1.1.124';
|
|
6
|
+
import { DxfScene, Entity, ColorCode } from '/resource/dxfViewer/js/viewer/DxfScene.js?version=1.1.124';
|
|
7
|
+
import { TextRenderer, ParseSpecialChars, HAlign, VAlign } from '/resource/dxfViewer/js/viewer/TextRenderer.js?version=1.1.124';
|
|
8
|
+
import { DxfWorker } from '/resource/dxfViewer/js/viewer/DxfWorker.js?version=1.1.124';
|
|
9
|
+
import { DxfFetcher } from '/resource/dxfViewer/js/viewer/DxfFetcher.js?version=1.1.124';
|
|
10
|
+
import DxfParser from '/resource/dxfViewer/js/viewer/parser/DxfParser.js?version=1.1.124';
|
|
11
|
+
import { RenderBatch } from '/resource/dxfViewer/js/viewer/DxfScene.js?version=1.1.124';
|
|
12
|
+
import { DynamicBuffer, NativeType } from '/resource/dxfViewer/js/viewer/DynamicBuffer.js?version=1.1.124';
|
|
13
|
+
import { OrbitControls } from '/resource/dxfViewer/js/viewer/OrbitControls.js?version=1.1.124';
|
|
14
|
+
import { CSS2DRenderer, CSS2DObject } from '/resource/dxfViewer/js/three/three.module.js?version=1.1.124';
|
|
15
|
+
|
|
16
|
+
let treeViewData = [];
|
|
17
|
+
let notes = [];
|
|
18
|
+
let customMeta = {};
|
|
19
|
+
const InstanceType = Object.freeze({
|
|
20
|
+
/** Not instanced. */
|
|
21
|
+
NONE: 0,
|
|
22
|
+
/** Full affine transform per instance. */
|
|
23
|
+
FULL: 1,
|
|
24
|
+
/** Point instances, 2D-translation vector per instance. */
|
|
25
|
+
POINT: 2,
|
|
26
|
+
|
|
27
|
+
/** Number of types. */
|
|
28
|
+
MAX: 3
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
export class VitroBatch {
|
|
33
|
+
/**
|
|
34
|
+
* @param viewer {DxfViewer}
|
|
35
|
+
* @param scene Serialized scene.
|
|
36
|
+
* @param batch Serialized scene batch.
|
|
37
|
+
*/
|
|
38
|
+
constructor(viewer, scene, batch) {
|
|
39
|
+
this.viewer = viewer
|
|
40
|
+
this.key = batch.key
|
|
41
|
+
|
|
42
|
+
if (batch.hasOwnProperty("verticesOffset")) {
|
|
43
|
+
const verticesArray =
|
|
44
|
+
new Float32Array(scene.vertices,
|
|
45
|
+
batch.verticesOffset * Float32Array.BYTES_PER_ELEMENT,
|
|
46
|
+
batch.verticesSize)
|
|
47
|
+
if (this.key.geometryType !== BatchingKey.GeometryType.POINT_INSTANCE ||
|
|
48
|
+
scene.pointShapeHasDot) {
|
|
49
|
+
this.vertices = new three.BufferAttribute(verticesArray, 3)//vitro 2 => 3
|
|
50
|
+
}
|
|
51
|
+
if (this.key.geometryType === BatchingKey.GeometryType.POINT_INSTANCE) {
|
|
52
|
+
this.transforms = new three.InstancedBufferAttribute(verticesArray, 3)//vitro 2 => 3
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (batch.hasOwnProperty("chunks")) {
|
|
57
|
+
this.chunks = []
|
|
58
|
+
for (const rawChunk of batch.chunks) {
|
|
59
|
+
|
|
60
|
+
const verticesArray =
|
|
61
|
+
new Float32Array(scene.vertices,
|
|
62
|
+
rawChunk.verticesOffset * Float32Array.BYTES_PER_ELEMENT,
|
|
63
|
+
rawChunk.verticesSize)
|
|
64
|
+
const indicesArray =
|
|
65
|
+
new Uint16Array(scene.indices,
|
|
66
|
+
rawChunk.indicesOffset * Uint16Array.BYTES_PER_ELEMENT,
|
|
67
|
+
rawChunk.indicesSize)
|
|
68
|
+
this.chunks.push({
|
|
69
|
+
vertices: new three.BufferAttribute(verticesArray, 3),//vitro 2 => 3
|
|
70
|
+
indices: new three.BufferAttribute(indicesArray, 1),
|
|
71
|
+
handle: rawChunk.handle//vitro
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (batch.hasOwnProperty("transformsOffset")) {
|
|
77
|
+
const transformsArray =
|
|
78
|
+
new Float32Array(scene.transforms,
|
|
79
|
+
batch.transformsOffset * Float32Array.BYTES_PER_ELEMENT,
|
|
80
|
+
batch.transformsSize)
|
|
81
|
+
/* Each transform is 3x2 matrix which is split into two 3D vectors which will occupy two
|
|
82
|
+
* attribute slots.
|
|
83
|
+
*/
|
|
84
|
+
const buf = new three.InstancedInterleavedBuffer(transformsArray, 6)
|
|
85
|
+
this.transforms0 = new three.InterleavedBufferAttribute(buf, 3, 0)
|
|
86
|
+
this.transforms1 = new three.InterleavedBufferAttribute(buf, 3, 3)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (this.key.geometryType === BatchingKey.GeometryType.BLOCK_INSTANCE ||
|
|
90
|
+
this.key.geometryType === BatchingKey.GeometryType.POINT_INSTANCE) {
|
|
91
|
+
|
|
92
|
+
const layer = this.viewer.layers.get(this.key.layerName)
|
|
93
|
+
if (layer) {
|
|
94
|
+
this.layerColor = layer.color
|
|
95
|
+
} else {
|
|
96
|
+
this.layerColor = 0
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
GetInstanceType() {
|
|
102
|
+
switch (this.key.geometryType) {
|
|
103
|
+
case BatchingKey.GeometryType.BLOCK_INSTANCE:
|
|
104
|
+
return InstanceType.FULL
|
|
105
|
+
case BatchingKey.GeometryType.POINT_INSTANCE:
|
|
106
|
+
return InstanceType.POINT
|
|
107
|
+
default:
|
|
108
|
+
return InstanceType.NONE
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Create scene objects corresponding to batch data.
|
|
113
|
+
* @param instanceBatch {?Batch} Batch with instance transform. Null for non-instanced object.
|
|
114
|
+
*/
|
|
115
|
+
*CreateObjects(instanceBatch = null) {
|
|
116
|
+
if (this.key.geometryType === BatchingKey.GeometryType.BLOCK_INSTANCE ||
|
|
117
|
+
this.key.geometryType === BatchingKey.GeometryType.POINT_INSTANCE) {
|
|
118
|
+
|
|
119
|
+
if (instanceBatch !== null) {
|
|
120
|
+
throw new Error("Unexpected instance batch specified for instance batch")
|
|
121
|
+
}
|
|
122
|
+
yield* this._CreateBlockInstanceObjects()
|
|
123
|
+
return
|
|
124
|
+
}
|
|
125
|
+
yield* this._CreateObjects(instanceBatch)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
*_CreateObjects(instanceBatch) {
|
|
129
|
+
const color = instanceBatch ?
|
|
130
|
+
instanceBatch._GetInstanceColor(this.key.color) : this.key.color
|
|
131
|
+
|
|
132
|
+
//XXX line type
|
|
133
|
+
const materialFactory =
|
|
134
|
+
this.key.geometryType === BatchingKey.GeometryType.POINTS ||
|
|
135
|
+
this.key.geometryType === BatchingKey.GeometryType.POINT_INSTANCE ?
|
|
136
|
+
this.viewer._GetSimplePointMaterial : this.viewer._GetSimpleColorMaterial
|
|
137
|
+
|
|
138
|
+
const material = materialFactory.call(this.viewer, this.viewer._TransformColor(color),
|
|
139
|
+
instanceBatch?.GetInstanceType() ?? InstanceType.NONE)
|
|
140
|
+
|
|
141
|
+
let objConstructor
|
|
142
|
+
switch (this.key.geometryType) {
|
|
143
|
+
case BatchingKey.GeometryType.POINTS:
|
|
144
|
+
/* This method also called for creating dots for shaped point instances. */
|
|
145
|
+
case BatchingKey.GeometryType.POINT_INSTANCE:
|
|
146
|
+
objConstructor = three.Points
|
|
147
|
+
break
|
|
148
|
+
case BatchingKey.GeometryType.LINES:
|
|
149
|
+
case BatchingKey.GeometryType.INDEXED_LINES:
|
|
150
|
+
objConstructor = three.LineSegments
|
|
151
|
+
break
|
|
152
|
+
case BatchingKey.GeometryType.TRIANGLES:
|
|
153
|
+
case BatchingKey.GeometryType.INDEXED_TRIANGLES:
|
|
154
|
+
objConstructor = three.Mesh
|
|
155
|
+
break
|
|
156
|
+
default:
|
|
157
|
+
throw new Error("Unexpected geometry type:" + this.key.geometryType)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function CreateObject(vertices, chunk) {
|
|
161
|
+
const geometry = instanceBatch ?
|
|
162
|
+
new three.InstancedBufferGeometry() : new three.BufferGeometry()
|
|
163
|
+
geometry.setAttribute("position", vertices)
|
|
164
|
+
instanceBatch?._SetInstanceTransformAttribute(geometry)
|
|
165
|
+
if (chunk.indices) {
|
|
166
|
+
geometry.setIndex(chunk.indices)
|
|
167
|
+
}
|
|
168
|
+
const obj = new objConstructor(geometry, material)
|
|
169
|
+
obj.frustumCulled = false
|
|
170
|
+
obj.matrixAutoUpdate = false
|
|
171
|
+
obj.name = chunk.handle
|
|
172
|
+
return obj
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (this.chunks) {
|
|
176
|
+
for (const chunk of this.chunks) {
|
|
177
|
+
yield CreateObject(chunk.vertices, chunk)
|
|
178
|
+
}
|
|
179
|
+
} else {
|
|
180
|
+
yield CreateObject(this.vertices)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @param geometry {InstancedBufferGeometry}
|
|
186
|
+
*/
|
|
187
|
+
_SetInstanceTransformAttribute(geometry) {
|
|
188
|
+
if (!geometry.isInstancedBufferGeometry) {
|
|
189
|
+
throw new Error("InstancedBufferGeometry expected")
|
|
190
|
+
}
|
|
191
|
+
if (this.key.geometryType === BatchingKey.GeometryType.POINT_INSTANCE) {
|
|
192
|
+
geometry.setAttribute("instanceTransform", this.transforms)
|
|
193
|
+
} else {
|
|
194
|
+
geometry.setAttribute("instanceTransform0", this.transforms0)
|
|
195
|
+
geometry.setAttribute("instanceTransform1", this.transforms1)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
*_CreateBlockInstanceObjects() {
|
|
200
|
+
const blockName = this.key.instanceName ? this.key.instanceName : this.key.blockName
|
|
201
|
+
const block = this.viewer.blocks.get(blockName)
|
|
202
|
+
if (!block) {
|
|
203
|
+
return
|
|
204
|
+
}
|
|
205
|
+
for (const batch of block.batches) {
|
|
206
|
+
yield* batch.CreateObjects(this)
|
|
207
|
+
}
|
|
208
|
+
if (this.hasOwnProperty("vertices")) {
|
|
209
|
+
/* Dots for point shapes. */
|
|
210
|
+
yield* this._CreateObjects()
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* @param defColor {number} Color value for block definition batch.
|
|
216
|
+
* @return {number} RGB color value for a block instance.
|
|
217
|
+
*/
|
|
218
|
+
_GetInstanceColor(defColor) {
|
|
219
|
+
if (defColor === ColorCode.BY_BLOCK) {
|
|
220
|
+
return this.key.color
|
|
221
|
+
} else if (defColor === ColorCode.BY_LAYER) {
|
|
222
|
+
return this.layerColor
|
|
223
|
+
} else {
|
|
224
|
+
return defColor
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/** Key for render batches. */
|
|
229
|
+
export class BatchingKey {
|
|
230
|
+
/**
|
|
231
|
+
* Components order matters for lookup by prefix.
|
|
232
|
+
* @param layerName {?String} Layer name, null if not bound to a layer (e.g. block definition).
|
|
233
|
+
* @param blockName {?String} Block name if applicable. If specified and geometryType is not
|
|
234
|
+
* BLOCK_INSTANCE, the batch is part of block definition. Otherwise it is block instance.
|
|
235
|
+
* @param geometryType {?number} One of BatchingKey.GeometryType.
|
|
236
|
+
* @param color {number} Color ARGB value.
|
|
237
|
+
* @param lineType {?number} Line type ID, null for non-lines. Zero is default type (solid
|
|
238
|
+
* line).
|
|
239
|
+
*/
|
|
240
|
+
constructor(layerName, blockName, geometryType, color, lineType) {
|
|
241
|
+
this.layerName = layerName ?? null
|
|
242
|
+
this.blockName = blockName ?? null
|
|
243
|
+
this.geometryType = geometryType ?? null
|
|
244
|
+
this.color = color
|
|
245
|
+
this.lineType = lineType ?? null
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** Comparator function. Fields lexical order corresponds to the constructor arguments order.
|
|
249
|
+
* Null values are always first.
|
|
250
|
+
*/
|
|
251
|
+
Compare(other) {
|
|
252
|
+
let c = CompareValues(this.layerName, other.layerName)
|
|
253
|
+
if (c !== 0) {
|
|
254
|
+
return c
|
|
255
|
+
}
|
|
256
|
+
c = CompareValues(this.blockName, other.blockName)
|
|
257
|
+
if (c !== 0) {
|
|
258
|
+
return c
|
|
259
|
+
}
|
|
260
|
+
c = CompareValues(this.instanceName, other.instanceName)
|
|
261
|
+
if (c !== 0) {
|
|
262
|
+
return c
|
|
263
|
+
}
|
|
264
|
+
c = CompareValues(this.geometryType, other.geometryType)
|
|
265
|
+
if (c !== 0) {
|
|
266
|
+
return c
|
|
267
|
+
}
|
|
268
|
+
c = CompareValues(this.color, other.color)
|
|
269
|
+
if (c !== 0) {
|
|
270
|
+
return c
|
|
271
|
+
}
|
|
272
|
+
return CompareValues(this.lineType, other.lineType)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
IsIndexed() {
|
|
276
|
+
return this.geometryType === BatchingKey.GeometryType.INDEXED_LINES ||
|
|
277
|
+
this.geometryType === BatchingKey.GeometryType.INDEXED_TRIANGLES ||
|
|
278
|
+
this.geometryType === BatchingKey.GeometryType.POINTS
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
IsInstanced() {
|
|
282
|
+
return this.geometryType === BatchingKey.GeometryType.BLOCK_INSTANCE ||
|
|
283
|
+
this.geometryType === BatchingKey.GeometryType.POINT_INSTANCE
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
BatchingKey.GeometryType = Object.freeze({
|
|
288
|
+
POINTS: 0,
|
|
289
|
+
LINES: 1,
|
|
290
|
+
INDEXED_LINES: 2,
|
|
291
|
+
TRIANGLES: 3,
|
|
292
|
+
INDEXED_TRIANGLES: 4,
|
|
293
|
+
BLOCK_INSTANCE: 5,
|
|
294
|
+
/** Shaped point instances. */
|
|
295
|
+
POINT_INSTANCE: 6
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
/** Comparator function for arbitrary types. Null is always first. This is used just to make some
|
|
299
|
+
* ordering for keys in tree structures, so no locale-aware string comparison.
|
|
300
|
+
*/
|
|
301
|
+
export function CompareValues(v1, v2) {
|
|
302
|
+
if (v1 === null) {
|
|
303
|
+
if (v2 === null) {
|
|
304
|
+
return 0
|
|
305
|
+
}
|
|
306
|
+
return -1
|
|
307
|
+
}
|
|
308
|
+
if (v2 === null) {
|
|
309
|
+
return 1
|
|
310
|
+
}
|
|
311
|
+
if (v1 < v2) {
|
|
312
|
+
return -1
|
|
313
|
+
}
|
|
314
|
+
if (v1 > v2) {
|
|
315
|
+
return 1
|
|
316
|
+
}
|
|
317
|
+
return 0
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const MODEL_SPACE = "*Model_Space"
|
|
321
|
+
const PAPER_SPACE = "*Paper_Space"
|
|
322
|
+
|
|
323
|
+
export function IsSpace(name) {
|
|
324
|
+
return name && (name.indexOf(MODEL_SPACE) == 0 || name.indexOf(PAPER_SPACE) == 0)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
export function IsModelSpace(name) {
|
|
328
|
+
return name && name.indexOf(MODEL_SPACE) == 0
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// JavaScript source code
|
|
332
|
+
//export class VitroBlock extends Block {
|
|
333
|
+
export class VitroBlock extends SceneBlock {
|
|
334
|
+
/** @param data {{}} Raw DXF entity. */
|
|
335
|
+
constructor(data) {
|
|
336
|
+
super(data)
|
|
337
|
+
if (!this.HasEntities()) {
|
|
338
|
+
this.GetEntitiesFromXref(data)
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** Set block flattening flag based on usage statistics.
|
|
343
|
+
* @return {Boolean} New flatten flag state.
|
|
344
|
+
*/
|
|
345
|
+
SetFlatten() {
|
|
346
|
+
if (!this.HasGeometry()) {
|
|
347
|
+
return false
|
|
348
|
+
}
|
|
349
|
+
/* Flatten if a block is used once (pure optimization if shares its layer with other
|
|
350
|
+
* geometry) or if total instanced vertices number is less than a threshold (trade some
|
|
351
|
+
* space for draw calls number).
|
|
352
|
+
*/
|
|
353
|
+
this.flatten = true;//vitro
|
|
354
|
+
return this.flatten
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
HasEntities() {
|
|
359
|
+
return this.data.hasOwnProperty("entities")
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
IsSpace() {
|
|
363
|
+
return IsSpace(this.data.name)
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
async GetEntitiesFromXref(data) {
|
|
367
|
+
if (data.xrefPath) {
|
|
368
|
+
const url = data.xrefPath.replace('.dwg', '.dxf').replace('\\', '/')
|
|
369
|
+
var filename = url.substring(url.lastIndexOf('/') + 1)
|
|
370
|
+
const dxf = window.dxfViewer.xrefMap[filename]
|
|
371
|
+
this.data.entities = []
|
|
372
|
+
for (const entity of dxf.entities) {
|
|
373
|
+
if (!entity.inPaperSpace) {
|
|
374
|
+
this.data.entities.push(entity)
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
export class VitroDxfScene extends DxfScene {
|
|
381
|
+
|
|
382
|
+
constructor(options) {
|
|
383
|
+
super(options)
|
|
384
|
+
|
|
385
|
+
this.origins = new Map()
|
|
386
|
+
/* Indexed by block referense handle, value is Insert. */
|
|
387
|
+
this.inserts = new Map()
|
|
388
|
+
this.bounds = new Map()
|
|
389
|
+
this.overlays = new Map()
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
async Build(dxf, xrefMap, fontFetchers) {
|
|
393
|
+
const header = dxf.header || {}
|
|
394
|
+
|
|
395
|
+
for (const [name, value] of Object.entries(header)) {
|
|
396
|
+
if (name.startsWith("$")) {
|
|
397
|
+
this.vars.set(name.slice(1), value)
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/* Zero angle direction, 0 is +X. */
|
|
402
|
+
this.angBase = this.vars.get("ANGBASE") ?? 0
|
|
403
|
+
/* 0 - CCW, 1 - CW */
|
|
404
|
+
this.angDir = this.vars.get("ANGDIR") ?? 0
|
|
405
|
+
this.pdSize = this.vars.get("PDSIZE") ?? 0
|
|
406
|
+
this.isMetric = (this.vars.get("MEASUREMENT") ?? 1) == 1
|
|
407
|
+
|
|
408
|
+
this._ProcessLayers(dxf, xrefMap)
|
|
409
|
+
|
|
410
|
+
if (dxf.tables && dxf.tables.dimstyle) {
|
|
411
|
+
for (const [, style] of Object.entries(dxf.tables.dimstyle.dimStyles)) {
|
|
412
|
+
this.dimStyles.set(style.name, style)
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (dxf.tables && dxf.tables.style) {
|
|
417
|
+
for (const [, style] of Object.entries(dxf.tables.style.styles)) {
|
|
418
|
+
this.fontStyles.set(style.styleName, style);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
this._ProcessBlocks(dxf, xrefMap)
|
|
423
|
+
|
|
424
|
+
this.textRenderer = new TextRenderer(fontFetchers, this.options.textOptions)
|
|
425
|
+
this.hasMissingChars = false
|
|
426
|
+
await this._FetchFonts(dxf)
|
|
427
|
+
|
|
428
|
+
/* Scan all entities to analyze block usage statistics and create viewport vertices. */
|
|
429
|
+
this.layouts = []
|
|
430
|
+
this.viewports = []
|
|
431
|
+
this._ProcessInserts(dxf)
|
|
432
|
+
this._ProcessEntities(dxf)
|
|
433
|
+
this._ProcessLayouts(dxf)
|
|
434
|
+
|
|
435
|
+
this.scene = this._BuildScene()
|
|
436
|
+
this.scene.layouts = this.layouts
|
|
437
|
+
this.scene.tileMode = dxf.header["$TILEMODE"] || 0
|
|
438
|
+
|
|
439
|
+
delete this.batches
|
|
440
|
+
delete this.layers
|
|
441
|
+
delete this.blocks
|
|
442
|
+
delete this.textRenderer
|
|
443
|
+
delete this.layouts
|
|
444
|
+
delete this.viewports
|
|
445
|
+
delete this.origins
|
|
446
|
+
delete this.bounds
|
|
447
|
+
delete this.overlays
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
_ProcessLayers(dxf, xrefMap) {
|
|
451
|
+
if (xrefMap) {
|
|
452
|
+
for (const [, xref] of Object.entries(xrefMap)) {
|
|
453
|
+
if (xref.tables && xref.tables.layer) {
|
|
454
|
+
this._ProcessLayersMap(xref.tables.layer.layers)
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
if (dxf.tables && dxf.tables.layer) {
|
|
459
|
+
this._ProcessLayersMap(dxf.tables.layer.layers)
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
_ProcessLayersMap(layers) {
|
|
464
|
+
for (const [, layer] of Object.entries(layers)) {
|
|
465
|
+
const ind1 = layer.name.indexOf('|')
|
|
466
|
+
const ind2 = layer.name.lastIndexOf('|')
|
|
467
|
+
if (ind1 === ind2) {
|
|
468
|
+
layer.displayName = ParseSpecialChars(layer.name)
|
|
469
|
+
this.layers.set(layer.name, layer)
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
_ProcessBlocks(dxf, xrefMap) {
|
|
475
|
+
if (xrefMap) {
|
|
476
|
+
for (const [name, xref] of Object.entries(xrefMap)) {
|
|
477
|
+
if (xref.blocks) {
|
|
478
|
+
this._ProcessBlocksMap(xref.blocks, name)
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (dxf.blocks) {
|
|
484
|
+
this._ProcessBlocksMap(dxf.blocks)
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
_ProcessBlocksMap(blocks, xrefName) {
|
|
489
|
+
const prefix = xrefName ? xrefName.substring(0, xrefName.lastIndexOf('.')) : null
|
|
490
|
+
for (const [, block] of Object.entries(blocks)) {
|
|
491
|
+
this.blocks.set(block.name, new VitroBlock(block))
|
|
492
|
+
if (prefix && this._IsOverlay(block)) {
|
|
493
|
+
this.overlays.set(prefix + "|" + block.name, new VitroBlock(block.name))//register overlay
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
_IsOverlay(block) {
|
|
499
|
+
return block.type & 8
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
_ProcessLayouts(dxf) {
|
|
504
|
+
for (const layout of this.layouts) {
|
|
505
|
+
layout.origin = this.origins.get(layout.spaceHandle)
|
|
506
|
+
layout.bounds = this.bounds.get(layout.spaceHandle)
|
|
507
|
+
for (const viewport of this.viewports) {
|
|
508
|
+
if (layout.spaceHandle === viewport.ownerHandle) {
|
|
509
|
+
layout.viewports.set(viewport.status, viewport)
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const blockCtx = layout.block.DefinitionContext()
|
|
514
|
+
const entities = layout.block.data.entities ? layout.block.data.entities : dxf.entities
|
|
515
|
+
for (const viewport of layout.viewports.values()) {
|
|
516
|
+
this._CreateViewportVertices(viewport, entities)
|
|
517
|
+
this._ProcessDxfEntity(viewport, blockCtx)
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
_ProcessEntities(dxf) {
|
|
523
|
+
for (const block of this.blocks.values()) {
|
|
524
|
+
if (block.IsSpace() && block.HasEntities()) {//Process only Spaces next
|
|
525
|
+
const blockCtx = block.DefinitionContext()
|
|
526
|
+
for (const entity of block.data.entities) {
|
|
527
|
+
this._ProcessDxfEntity(entity, blockCtx)
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
this._CreateLayout(dxf, block)
|
|
531
|
+
}
|
|
532
|
+
console.log(`${this.numBlocksFlattened} blocks flattened`)
|
|
533
|
+
|
|
534
|
+
for (const entity of dxf.entities) {
|
|
535
|
+
const blockCtx = this._CreateSpaceBlockConext(entity)
|
|
536
|
+
this._ProcessDxfEntity(entity, blockCtx)
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
_ProcessInserts(dxf) {
|
|
541
|
+
/* Scan all entities to analyze block usage statistics. */
|
|
542
|
+
for (const entity of dxf.entities) {
|
|
543
|
+
if (entity.type === "INSERT") {
|
|
544
|
+
this.inserts.set(entity.handle, entity)
|
|
545
|
+
const block = this.blocks.get(entity.name)
|
|
546
|
+
block?.RegisterInsert(entity)
|
|
547
|
+
|
|
548
|
+
} else if (entity.type == "DIMENSION") {
|
|
549
|
+
if ((entity.block ?? null) !== null) {
|
|
550
|
+
const block = this.blocks.get(entity.block)
|
|
551
|
+
block?.RegisterInsert(entity)
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
for (const block of this.blocks.values()) {
|
|
557
|
+
if (block.HasEntities()) {
|
|
558
|
+
const blockCtx = block.DefinitionContext()
|
|
559
|
+
for (const entity of block.data.entities) {
|
|
560
|
+
if (block.IsSpace()) {
|
|
561
|
+
if (entity.type === "INSERT") {//analyze block usage statistics
|
|
562
|
+
this.inserts.set(entity.handle, entity)
|
|
563
|
+
const blkDef = this.blocks.get(entity.name)
|
|
564
|
+
blkDef?.RegisterInsert(entity)
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
else {//Process only BlockDefinition first
|
|
568
|
+
this._ProcessDxfEntity(entity, blockCtx, block.data)
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
if (block.SetFlatten()) {
|
|
573
|
+
this.numBlocksFlattened++
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
_CreateViewportVertices(viewport, entities) {
|
|
580
|
+
if (viewport.id === 1)//exlude main viewports
|
|
581
|
+
return;
|
|
582
|
+
if (viewport.boundaryHandle) {
|
|
583
|
+
for (const entity of entities) {
|
|
584
|
+
if (entity.handle === viewport.boundaryHandle) {
|
|
585
|
+
viewport.vertices = entity.vertices
|
|
586
|
+
break
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
return
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
const vertex0 = { x: viewport.center.x - viewport.width / 2, y: viewport.center.y - viewport.height / 2, z: viewport.center.z }
|
|
593
|
+
viewport.vertices.push(vertex0)
|
|
594
|
+
const vertex1 = Object.assign({}, vertex0)
|
|
595
|
+
vertex1.y += viewport.height
|
|
596
|
+
viewport.vertices.push(vertex1)
|
|
597
|
+
const vertex2 = Object.assign({}, vertex1)
|
|
598
|
+
vertex2.x += viewport.width
|
|
599
|
+
viewport.vertices.push(vertex2)
|
|
600
|
+
const vertex3 = Object.assign({}, vertex2)
|
|
601
|
+
vertex3.y -= viewport.height
|
|
602
|
+
viewport.vertices.push(vertex3)
|
|
603
|
+
const vertex4 = Object.assign({}, vertex3)
|
|
604
|
+
vertex4.x -= viewport.width
|
|
605
|
+
viewport.vertices.push(vertex4)
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
_CreateLayout(dxf, block) {
|
|
609
|
+
for (const object of dxf.objects) {
|
|
610
|
+
if (object.type === "LAYOUT" && object.spaceHandle === block.data.ownerHandle) {
|
|
611
|
+
const layout = {
|
|
612
|
+
block: block,
|
|
613
|
+
name: object.name,
|
|
614
|
+
space: block.data.name,
|
|
615
|
+
tabOrder: object.tabOrder,
|
|
616
|
+
spaceHandle: object.spaceHandle,
|
|
617
|
+
viewports: new Map()
|
|
618
|
+
}
|
|
619
|
+
for (let i = 1; i < this.layouts.length; i++) {
|
|
620
|
+
if (this.layouts[i].tabOrder > layout.tabOrder) {
|
|
621
|
+
this.layouts.splice(i, 0, layout)
|
|
622
|
+
return
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
this.layouts.push(layout)
|
|
626
|
+
return
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
_CreateSpaceBlockConext(entity) {
|
|
632
|
+
const block = this._FindSpaceBlock(entity.ownerHandle)
|
|
633
|
+
if (block) {
|
|
634
|
+
return block.DefinitionContext()
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
return this.layouts[0].block.DefinitionContext()//if not found -> to Model Space
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
_FindSpaceBlock(ownerHandle) {
|
|
641
|
+
for (const block of this.blocks.values()) {
|
|
642
|
+
if (block.IsSpace() && block.data.ownerHandle === ownerHandle) {
|
|
643
|
+
return block
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
const insert = this.inserts.get(ownerHandle)
|
|
648
|
+
if (insert) {
|
|
649
|
+
return this._FindSpaceBlock(insert.ownerHandle)
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
_IsSpaceContext(blockCtx) {
|
|
654
|
+
return !blockCtx || blockCtx.block.IsSpace()
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
_CreatePointShapeBlock() {//to override to new VitroBlock
|
|
659
|
+
if (this.pointShapeBlock) {
|
|
660
|
+
return
|
|
661
|
+
}
|
|
662
|
+
/* This mimics DXF block entity. */
|
|
663
|
+
this.pointShapeBlock = new VitroBlock({
|
|
664
|
+
name: POINT_SHAPE_BLOCK_NAME,
|
|
665
|
+
position: { x: 0, y: 0 }
|
|
666
|
+
})
|
|
667
|
+
/* Fix block origin at zero. */
|
|
668
|
+
this.pointShapeBlock.offset = new Vector2(0, 0)
|
|
669
|
+
const blockCtx = this.pointShapeBlock.DefinitionContext()
|
|
670
|
+
|
|
671
|
+
const markType = this.pdMode & PdMode.MARK_MASK
|
|
672
|
+
if (markType !== PdMode.DOT && markType !== PdMode.NONE) {
|
|
673
|
+
const vertices = []
|
|
674
|
+
this._CreatePointMarker(vertices, markType)
|
|
675
|
+
const entity = new Entity({
|
|
676
|
+
type: Entity.Type.LINE_SEGMENTS,
|
|
677
|
+
vertices,
|
|
678
|
+
color: ColorCode.BY_BLOCK
|
|
679
|
+
})
|
|
680
|
+
this._ProcessEntity(entity, blockCtx)
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
if (this.pdMode & PdMode.SQUARE) {
|
|
684
|
+
const r = this.pdSize * 0.5
|
|
685
|
+
const vertices = [
|
|
686
|
+
{ x: -r, y: r },
|
|
687
|
+
{ x: r, y: r },
|
|
688
|
+
{ x: r, y: -r },
|
|
689
|
+
{ x: -r, y: -r }
|
|
690
|
+
]
|
|
691
|
+
const entity = new Entity({
|
|
692
|
+
type: Entity.Type.POLYLINE, vertices,
|
|
693
|
+
color: ColorCode.BY_BLOCK,
|
|
694
|
+
shape: true
|
|
695
|
+
})
|
|
696
|
+
this._ProcessEntity(entity, blockCtx)
|
|
697
|
+
}
|
|
698
|
+
if (this.pdMode & PdMode.CIRCLE) {
|
|
699
|
+
const vertices = []
|
|
700
|
+
this._GenerateArcVertices({
|
|
701
|
+
vertices, center: { x: 0, y: 0 },
|
|
702
|
+
radius: this.pdSize * 0.5,
|
|
703
|
+
tessellationAngle: POINT_CIRCLE_TESSELLATION_ANGLE
|
|
704
|
+
})
|
|
705
|
+
const entity = new Entity({
|
|
706
|
+
type: Entity.Type.POLYLINE, vertices,
|
|
707
|
+
color: ColorCode.BY_BLOCK,
|
|
708
|
+
shape: true
|
|
709
|
+
})
|
|
710
|
+
this._ProcessEntity(entity, blockCtx)
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
_ProcessDxfEntity(entity, blockCtx = null, mainEntity = null) {
|
|
715
|
+
let renderEntities
|
|
716
|
+
switch (entity.type) {
|
|
717
|
+
case "LINE":
|
|
718
|
+
renderEntities = this._DecomposeLine(entity, blockCtx)
|
|
719
|
+
break
|
|
720
|
+
case "POLYLINE":
|
|
721
|
+
case "LWPOLYLINE":
|
|
722
|
+
case "LEADER":
|
|
723
|
+
renderEntities = this._DecomposePolyline(entity, blockCtx)
|
|
724
|
+
break
|
|
725
|
+
case "VIEWPORT":
|
|
726
|
+
if (entity.vertices && entity.vertices.length > 0) {
|
|
727
|
+
renderEntities = this._DecomposePolyline(entity, blockCtx)
|
|
728
|
+
}
|
|
729
|
+
else {
|
|
730
|
+
this.viewports.push(entity)//to process later
|
|
731
|
+
return
|
|
732
|
+
}
|
|
733
|
+
break
|
|
734
|
+
case "ARC":
|
|
735
|
+
renderEntities = this._DecomposeArc(entity, blockCtx)
|
|
736
|
+
break
|
|
737
|
+
case "CIRCLE":
|
|
738
|
+
renderEntities = this._DecomposeCircle(entity, blockCtx)
|
|
739
|
+
break
|
|
740
|
+
case "ELLIPSE":
|
|
741
|
+
renderEntities = this._DecomposeEllipse(entity, blockCtx)
|
|
742
|
+
break
|
|
743
|
+
case "POINT":
|
|
744
|
+
renderEntities = this._DecomposePoint(entity, blockCtx)
|
|
745
|
+
break
|
|
746
|
+
case "SPLINE":
|
|
747
|
+
renderEntities = this._DecomposeSpline(entity, blockCtx)
|
|
748
|
+
break
|
|
749
|
+
case "INSERT":
|
|
750
|
+
/* Works with rendering batches without intermediate entities. */
|
|
751
|
+
this._ProcessInsert(entity, blockCtx, mainEntity)
|
|
752
|
+
return
|
|
753
|
+
case "ATTRIB":
|
|
754
|
+
renderEntities = this._DecomposeAttribute(entity, blockCtx)
|
|
755
|
+
break
|
|
756
|
+
case "TEXT":
|
|
757
|
+
renderEntities = this._DecomposeText(entity, blockCtx)
|
|
758
|
+
break
|
|
759
|
+
case "MTEXT":
|
|
760
|
+
renderEntities = this._DecomposeMText(entity, blockCtx)
|
|
761
|
+
break
|
|
762
|
+
case "3DFACE":
|
|
763
|
+
renderEntities = this._Decompose3DFace(entity, blockCtx)
|
|
764
|
+
break
|
|
765
|
+
case "SOLID":
|
|
766
|
+
renderEntities = this._DecomposeSolid(entity, blockCtx)
|
|
767
|
+
break
|
|
768
|
+
case "DIMENSION":
|
|
769
|
+
renderEntities = this._DecomposeDimension(entity, blockCtx)
|
|
770
|
+
break
|
|
771
|
+
default:
|
|
772
|
+
console.log("Unhandled entity type: " + entity.type)
|
|
773
|
+
return
|
|
774
|
+
}
|
|
775
|
+
for (const renderEntity of renderEntities) {
|
|
776
|
+
this._ProcessEntity(renderEntity, blockCtx, mainEntity ? mainEntity : entity)
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/**
|
|
781
|
+
* @param entity {Entity}
|
|
782
|
+
* @param blockCtx {?BlockContext}
|
|
783
|
+
*/
|
|
784
|
+
_ProcessEntity(entity, blockCtx, mainEntity) {//vitro: add @param mainEntity {Entity}
|
|
785
|
+
this._CheckBlockColor(entity, mainEntity)
|
|
786
|
+
switch (entity.type) {
|
|
787
|
+
case Entity.Type.POINTS:
|
|
788
|
+
this._ProcessPoints(entity, blockCtx, mainEntity)
|
|
789
|
+
break
|
|
790
|
+
case Entity.Type.LINE_SEGMENTS:
|
|
791
|
+
this._ProcessPolyline(entity, blockCtx, mainEntity)//vitro: process line as polyline
|
|
792
|
+
break
|
|
793
|
+
case Entity.Type.POLYLINE:
|
|
794
|
+
this._ProcessPolyline(entity, blockCtx, mainEntity)
|
|
795
|
+
break
|
|
796
|
+
case Entity.Type.TRIANGLES:
|
|
797
|
+
this._ProcessTriangles(entity, blockCtx, mainEntity)
|
|
798
|
+
break
|
|
799
|
+
default:
|
|
800
|
+
throw new Error("Unhandled entity type: " + entity.type)
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* @param entity {Entity}
|
|
805
|
+
* @param blockCtx {?BlockContext}
|
|
806
|
+
*/
|
|
807
|
+
_ProcessPoints(entity, blockCtx, mainEntity) {//vitro: add @param mainEntity {Entity}
|
|
808
|
+
const key = new BatchingKey(entity.layer, blockCtx?.name,
|
|
809
|
+
BatchingKey.GeometryType.POINTS, entity.color, 0)
|
|
810
|
+
const batch = this._GetBatch(key)
|
|
811
|
+
const chunk = batch.PushChunk(entity.vertices.length, mainEntity)//vitro
|
|
812
|
+
for (const v of entity.vertices) {
|
|
813
|
+
chunk.PushVertex(this._TransformVertex(v, blockCtx))
|
|
814
|
+
}
|
|
815
|
+
for (let i = 0; i < entity.vertices.length; i++) {
|
|
816
|
+
chunk.PushIndex(i)
|
|
817
|
+
}
|
|
818
|
+
chunk.Finish()
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* @param entity {Entity}
|
|
823
|
+
* @param blockCtx {?BlockContext}
|
|
824
|
+
*/
|
|
825
|
+
_ProcessPolyline(entity, blockCtx, mainEntity) {//vitro: add @param mainEntity {Entity}
|
|
826
|
+
if (entity.vertices.length < 2) {
|
|
827
|
+
return
|
|
828
|
+
}
|
|
829
|
+
/* It is more optimal to render short polylines un-indexed. Also DXF often contains
|
|
830
|
+
* polylines with just two points.
|
|
831
|
+
*/
|
|
832
|
+
const verticesCount = entity.vertices.length
|
|
833
|
+
if (verticesCount == 3 && entity.shape) {//vitro == instead <= and entity.shape (only shapes with 3 vertex - will never work)
|
|
834
|
+
const key = new BatchingKey(entity.layer, blockCtx?.name,
|
|
835
|
+
BatchingKey.GeometryType.LINES, entity.color,
|
|
836
|
+
entity.lineType)
|
|
837
|
+
const batch = this._GetBatch(key)
|
|
838
|
+
let prev = null
|
|
839
|
+
for (const v of entity.vertices) {
|
|
840
|
+
if (prev !== null) {
|
|
841
|
+
batch.PushVertex(this._TransformVertex(prev, blockCtx))
|
|
842
|
+
batch.PushVertex(this._TransformVertex(v, blockCtx))
|
|
843
|
+
}
|
|
844
|
+
prev = v
|
|
845
|
+
}
|
|
846
|
+
if (entity.shape && verticesCount > 2) {
|
|
847
|
+
batch.PushVertex(this._TransformVertex(entity.vertices[verticesCount - 1], blockCtx))
|
|
848
|
+
batch.PushVertex(this._TransformVertex(entity.vertices[0], blockCtx))
|
|
849
|
+
}
|
|
850
|
+
return
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
const key = new BatchingKey(entity.layer, blockCtx?.name,
|
|
854
|
+
BatchingKey.GeometryType.INDEXED_LINES,
|
|
855
|
+
entity.color, entity.lineType)
|
|
856
|
+
const batch = this._GetBatch(key)
|
|
857
|
+
/* Line may be split if exceeds chunk limit. */
|
|
858
|
+
for (const lineChunk of entity._IterateLineChunks()) {
|
|
859
|
+
const chunk = batch.PushChunk(lineChunk.verticesCount, mainEntity)//vitro
|
|
860
|
+
for (const v of lineChunk.vertices) {
|
|
861
|
+
chunk.PushVertex(this._TransformVertex(v, blockCtx))
|
|
862
|
+
}
|
|
863
|
+
for (const idx of lineChunk.indices) {
|
|
864
|
+
chunk.PushIndex(idx)
|
|
865
|
+
}
|
|
866
|
+
chunk.Finish()
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
/**
|
|
871
|
+
* @param entity {Entity}
|
|
872
|
+
* @param blockCtx {?BlockContext}
|
|
873
|
+
*/
|
|
874
|
+
_ProcessTriangles(entity, blockCtx = null, mainEntity = null) {//vitro add mainEntity
|
|
875
|
+
if (entity.vertices.length < 3) {
|
|
876
|
+
return
|
|
877
|
+
}
|
|
878
|
+
if (entity.indices.length % 3 !== 0) {
|
|
879
|
+
console.error("Unexpected size of indices array: " + entity.indices.length)
|
|
880
|
+
return
|
|
881
|
+
}
|
|
882
|
+
const key = new BatchingKey(entity.layer, blockCtx?.name,
|
|
883
|
+
BatchingKey.GeometryType.INDEXED_TRIANGLES,
|
|
884
|
+
entity.color, 0)
|
|
885
|
+
const batch = this._GetBatch(key)
|
|
886
|
+
//XXX splitting into chunks is not yet implemented. Currently used only for text glyphs so
|
|
887
|
+
// should fit into one chunk
|
|
888
|
+
const chunk = batch.PushChunk(entity.vertices.length, mainEntity)
|
|
889
|
+
for (const v of entity.vertices) {
|
|
890
|
+
chunk.PushVertex(this._TransformVertex(v, blockCtx))
|
|
891
|
+
}
|
|
892
|
+
for (const idx of entity.indices) {
|
|
893
|
+
chunk.PushIndex(idx)
|
|
894
|
+
}
|
|
895
|
+
chunk.Finish()
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
_CheckBlockColor(entity, mainEntity) {
|
|
899
|
+
if (entity.color === ColorCode.BY_BLOCK) {
|
|
900
|
+
if (mainEntity && mainEntity.type === "INSERT") {
|
|
901
|
+
const layer = this.layers.get(mainEntity.layer)
|
|
902
|
+
entity.color = layer.color
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
else if (entity.color === ColorCode.BY_LAYER){
|
|
906
|
+
if (mainEntity && this._IsSystemLayer(entity.layer)) {
|
|
907
|
+
const blockLayer = this.layers.get(mainEntity.layer)
|
|
908
|
+
entity.color = blockLayer?.color ?? 0
|
|
909
|
+
} else {
|
|
910
|
+
const layer = this.layers.get(entity.layer)
|
|
911
|
+
entity.color = layer?.color ?? 0
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
|
|
917
|
+
*_DecomposeDimension(entity, blockCtx) {
|
|
918
|
+
if ((entity.block ?? null) !== null && this.blocks.has(entity.block)) {
|
|
919
|
+
const name = entity.name
|
|
920
|
+
entity.name = entity.block
|
|
921
|
+
entity.position = { x: 0, y:0, z: 0 }
|
|
922
|
+
this._ProcessInsert(entity, blockCtx)
|
|
923
|
+
entity.name = name
|
|
924
|
+
return
|
|
925
|
+
}
|
|
926
|
+
super._DecomposeDimension(entity, blockCtx)
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
*_DecomposeAttr(entity, blockCtx) {
|
|
930
|
+
if (entity.invisible) {
|
|
931
|
+
return
|
|
932
|
+
}
|
|
933
|
+
yield* this._DecomposeText(entity, blockCtx)
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
/**
|
|
937
|
+
* Updates batches directly.
|
|
938
|
+
* @param entity
|
|
939
|
+
* @param blockCtx {?BlockContext} Nested block insert when non-null.
|
|
940
|
+
*/
|
|
941
|
+
_ProcessInsert(entity, blockCtx, mainEntity) {
|
|
942
|
+
if (blockCtx && !blockCtx.block.IsSpace() && blockCtx.block.HasEntities()) {
|
|
943
|
+
//XXX handle indirect recursion
|
|
944
|
+
if (blockCtx.name === entity.name) {
|
|
945
|
+
console.warn("Recursive block reference: " + blockCtx.name)
|
|
946
|
+
return
|
|
947
|
+
}
|
|
948
|
+
/* Flatten nested blocks definition. */
|
|
949
|
+
var name = entity.name ? entity.name : entity.block
|
|
950
|
+
const block = this.blocks.get(name)
|
|
951
|
+
if (!block) {
|
|
952
|
+
console.warn("Unresolved nested block reference: " + entity.name)
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
var isOverlay = false
|
|
956
|
+
if (mainEntity && mainEntity.name) {
|
|
957
|
+
const fullName = mainEntity.name + "|" + name
|
|
958
|
+
isOverlay = this.overlays.has(fullName)
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
const nestedCtx = blockCtx.NestedBlockContext(block, entity)
|
|
962
|
+
if (!isOverlay && block.data.entities) {
|
|
963
|
+
for (const subEntity of block.data.entities) {
|
|
964
|
+
this._ProcessDxfEntity(subEntity, nestedCtx, entity)
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
return
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
var name = entity.name ? entity.name : entity.block//vitro
|
|
971
|
+
const block = this.blocks.get(name)
|
|
972
|
+
if (block === null) {
|
|
973
|
+
console.warn("Unresolved block reference in INSERT: " + name)
|
|
974
|
+
return
|
|
975
|
+
}
|
|
976
|
+
if (!block.HasGeometry()) {
|
|
977
|
+
return
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
const layer = this._GetEntityLayer(entity, null)
|
|
981
|
+
const color = this._GetEntityColor(entity, null)
|
|
982
|
+
const lineType = this._GetLineType(entity, null, null)
|
|
983
|
+
//XXX apply extrusion direction
|
|
984
|
+
const transform = block.InstantiationContext().GetInsertionTransform(entity)
|
|
985
|
+
|
|
986
|
+
/* Update bounding box and origin with transformed block bounds corner points. */
|
|
987
|
+
const bounds = block.bounds
|
|
988
|
+
const origin = this._UpdateBounds(new Vector2(bounds.minX, bounds.minY).applyMatrix3(transform), blockCtx)
|
|
989
|
+
this._UpdateBounds(new Vector2(bounds.maxX, bounds.maxY).applyMatrix3(transform), blockCtx)
|
|
990
|
+
this._UpdateBounds(new Vector2(bounds.minX, bounds.maxY).applyMatrix3(transform), blockCtx)
|
|
991
|
+
this._UpdateBounds(new Vector2(bounds.maxX, bounds.minY).applyMatrix3(transform), blockCtx)
|
|
992
|
+
|
|
993
|
+
transform.translate(-origin.x, -origin.y)
|
|
994
|
+
//XXX grid instancing not supported yet
|
|
995
|
+
if (block.flatten) {
|
|
996
|
+
for (const batch of block.batches) {
|
|
997
|
+
this._FlattenBatch(batch, layer, blockCtx.block.data.name, color, lineType, transform, entity)//vitro add entity
|
|
998
|
+
}
|
|
999
|
+
} else {
|
|
1000
|
+
const key = new BatchingKey(layer, blockCtx.block.data.name, BatchingKey.GeometryType.BLOCK_INSTANCE,
|
|
1001
|
+
color, lineType)
|
|
1002
|
+
key.instanceName = entity.name
|
|
1003
|
+
const batch = this._GetBatch(key)
|
|
1004
|
+
batch.PushInstanceTransform(transform)
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
_IsSystemLayer(name) {
|
|
1009
|
+
return name === "0" || name === "Defpoints"
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
/** Flatten block definition batch. It is merged into suitable instant rendering batch. */
|
|
1013
|
+
_FlattenBatch(blockBatch, layerName, blockName, blockColor, blockLineType, transform, entity) {//vitro add entity
|
|
1014
|
+
const layer = this.layers.get(layerName)
|
|
1015
|
+
let color, lineType = 0
|
|
1016
|
+
if (blockBatch.key.color === ColorCode.BY_BLOCK) {
|
|
1017
|
+
color = blockColor
|
|
1018
|
+
} else if (blockBatch.key.color === ColorCode.BY_LAYER) {
|
|
1019
|
+
color = layer?.color ?? 0
|
|
1020
|
+
} else {
|
|
1021
|
+
color = blockBatch.key.color
|
|
1022
|
+
}
|
|
1023
|
+
//XXX line type
|
|
1024
|
+
const key = new BatchingKey(layerName, blockName, blockBatch.key.geometryType, color, lineType)
|
|
1025
|
+
const batch = this._GetBatch(key)
|
|
1026
|
+
batch.Merge(blockBatch, transform, entity)//vitro add entity
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
/** @return {RenderBatch} */
|
|
1030
|
+
_GetBatch(key) {
|
|
1031
|
+
let batch = this.batches.find({ key })
|
|
1032
|
+
if (batch !== null) {
|
|
1033
|
+
return batch
|
|
1034
|
+
}
|
|
1035
|
+
batch = new VitroRenderBatch(key)
|
|
1036
|
+
this.batches.insert(batch)
|
|
1037
|
+
if (key.blockName !== null && !key.IsInstanced()) {
|
|
1038
|
+
/* Block definition batch. */
|
|
1039
|
+
const block = this.blocks.get(key.blockName)
|
|
1040
|
+
if (block) {
|
|
1041
|
+
block.batches.push(batch)
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
return batch
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
/** Resolve entity color.
|
|
1048
|
+
*
|
|
1049
|
+
* @param entity
|
|
1050
|
+
* @param blockCtx {?BlockContext}
|
|
1051
|
+
* @return {number} RGB color value. For block entity it also may be one of ColorCode values
|
|
1052
|
+
* which are resolved on block instantiation.
|
|
1053
|
+
*/
|
|
1054
|
+
_GetEntityColor(entity, blockCtx = null) {
|
|
1055
|
+
let color = ColorCode.BY_LAYER
|
|
1056
|
+
if (entity.colorIndex === 0) {
|
|
1057
|
+
color = ColorCode.BY_BLOCK
|
|
1058
|
+
} else if (entity.colorIndex === 256) {
|
|
1059
|
+
color = ColorCode.BY_LAYER
|
|
1060
|
+
} else if (entity.hasOwnProperty("color")) {
|
|
1061
|
+
color = entity.color
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
if (!this._IsSpaceContext(blockCtx)) {//vitro
|
|
1065
|
+
return color
|
|
1066
|
+
}
|
|
1067
|
+
if (color === ColorCode.BY_LAYER || color === ColorCode.BY_BLOCK) {
|
|
1068
|
+
/* BY_BLOCK is not useful when not in block so replace it by layer as well. */
|
|
1069
|
+
if (entity.hasOwnProperty("layer")) {
|
|
1070
|
+
const layer = this.layers.get(entity.layer)
|
|
1071
|
+
if (layer) {
|
|
1072
|
+
return layer.color
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
} else {
|
|
1076
|
+
return color
|
|
1077
|
+
}
|
|
1078
|
+
/* Fallback to black. */
|
|
1079
|
+
return 0
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
/** @return {?string} Layer name, null for block entity. */
|
|
1083
|
+
_GetEntityLayer(entity, blockCtx = null) {
|
|
1084
|
+
if (entity.hasOwnProperty("layer")) {
|
|
1085
|
+
return entity.layer
|
|
1086
|
+
}
|
|
1087
|
+
return "0"
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
/**
|
|
1091
|
+
* Apply all necessary final transforms to a vertex before just before storing it in a rendering
|
|
1092
|
+
* batch.
|
|
1093
|
+
* @param v {{x: number, y: number}}
|
|
1094
|
+
* @param blockCtx {BlockContext}
|
|
1095
|
+
* @return {{x: number, y: number}}
|
|
1096
|
+
*/
|
|
1097
|
+
_TransformVertex(v, blockCtx = null) {
|
|
1098
|
+
if (!this._IsSpaceContext(blockCtx)) {
|
|
1099
|
+
/* Block definition in block coordinates. So it should not touch bounds and origin. */
|
|
1100
|
+
return blockCtx.TransformVertex(v)
|
|
1101
|
+
}
|
|
1102
|
+
const origin = this._UpdateBounds(v, blockCtx)
|
|
1103
|
+
return { x: v.x - origin.x, y: v.y - origin.y }
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
/*
|
|
1107
|
+
* @param blockCtx {BlockContext}
|
|
1108
|
+
* @param v {{x,y}} Vertex to extend bounding box with and set origin.
|
|
1109
|
+
*/
|
|
1110
|
+
_UpdateBounds(v, blockCtx) {
|
|
1111
|
+
const handle = blockCtx.block.data.ownerHandle
|
|
1112
|
+
var bounds = this.bounds.get(handle)
|
|
1113
|
+
if (!bounds) {
|
|
1114
|
+
bounds = { minX: v.x, maxX: v.x, minY: v.y, maxY: v.y }
|
|
1115
|
+
this.bounds.set(handle, bounds)
|
|
1116
|
+
} else {
|
|
1117
|
+
if (v.x < bounds.minX) {
|
|
1118
|
+
bounds.minX = v.x
|
|
1119
|
+
} else if (v.x > bounds.maxX) {
|
|
1120
|
+
bounds.maxX = v.x
|
|
1121
|
+
}
|
|
1122
|
+
if (v.y < bounds.minY) {
|
|
1123
|
+
bounds.minY = v.y
|
|
1124
|
+
} else if (v.y > bounds.maxY) {
|
|
1125
|
+
bounds.maxY = v.y
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
var origin = this.origins.get(handle)
|
|
1129
|
+
if (!origin) {
|
|
1130
|
+
origin = { x: v.x, y: v.y }
|
|
1131
|
+
//origin = { x: 0, y: 0 }//vitro
|
|
1132
|
+
this.origins.set(handle, origin)
|
|
1133
|
+
}
|
|
1134
|
+
return origin
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
}
|
|
1138
|
+
export class VitroDxfWorker extends DxfWorker {
|
|
1139
|
+
|
|
1140
|
+
/** @return {Object} DxfScene serialized scene. */
|
|
1141
|
+
async _Load(url, fonts, options, progressCbk) {
|
|
1142
|
+
let fontFetchers
|
|
1143
|
+
if (fonts) {
|
|
1144
|
+
fontFetchers = this._CreateFontFetchers(fonts, progressCbk)
|
|
1145
|
+
} else {
|
|
1146
|
+
fontFetchers = []
|
|
1147
|
+
}
|
|
1148
|
+
const dxf = await new DxfFetcher(url).Fetch(progressCbk)
|
|
1149
|
+
if (progressCbk) {
|
|
1150
|
+
progressCbk("prepare", 0, null)
|
|
1151
|
+
}
|
|
1152
|
+
const dxfScene = new VitroDxfScene(options)
|
|
1153
|
+
if (options.buildScene === true) {
|
|
1154
|
+
await dxfScene.Build(dxf, options.xrefMap, fontFetchers)
|
|
1155
|
+
}
|
|
1156
|
+
return {
|
|
1157
|
+
scene: options.buildScene === true ? dxfScene.scene : undefined,
|
|
1158
|
+
dxf: options.retainParsedDxf === true ? dxf : undefined
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
}
|
|
1163
|
+
export const DrawMode = {
|
|
1164
|
+
ANNOTATIONS: 1
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
const MessageLevel = Object.freeze({
|
|
1168
|
+
INFO: "info",
|
|
1169
|
+
WARN: "warn",
|
|
1170
|
+
ERROR: "error"
|
|
1171
|
+
})
|
|
1172
|
+
|
|
1173
|
+
|
|
1174
|
+
export class Viewer extends DxfViewer {
|
|
1175
|
+
|
|
1176
|
+
constructor(domContainer, options = null) {
|
|
1177
|
+
|
|
1178
|
+
if (!options) {
|
|
1179
|
+
options = DxfViewer.DefaultOptions
|
|
1180
|
+
options.autoResize = true
|
|
1181
|
+
options.colorCorrection = true
|
|
1182
|
+
options.clearColor = new three.Color("#fff")
|
|
1183
|
+
options.buildScene = true
|
|
1184
|
+
options.retainParsedDxf = true
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
super(domContainer, options)
|
|
1188
|
+
this.canvas.addEventListener("mousemove", this._OnPointerEvent.bind(this))
|
|
1189
|
+
document.addEventListener("keydown", this.OnKeyDown)
|
|
1190
|
+
|
|
1191
|
+
/* Indexed by space name, value is scene instance. */
|
|
1192
|
+
this.spaces = new Map();
|
|
1193
|
+
|
|
1194
|
+
this.objects = []
|
|
1195
|
+
this.objectMap = new Map()
|
|
1196
|
+
this.selectedObjects = []
|
|
1197
|
+
this.drawMode = null
|
|
1198
|
+
this.drawables = []
|
|
1199
|
+
this.drawablePlugins = []
|
|
1200
|
+
this.xrefMap = new Map()
|
|
1201
|
+
|
|
1202
|
+
var mainFont = "/resource/dxfViewer/assets/fonts/Roboto-LightItalic.ttf";
|
|
1203
|
+
var aux1Font = "/resource/dxfViewer/assets/fonts/NotoSansDisplay-SemiCondensedLightItalic.ttf";
|
|
1204
|
+
var aux2Font = "/resource/dxfViewer/assets/fonts/HanaMinA.ttf";
|
|
1205
|
+
var aux3Font = "/resource/dxfViewer/assets/fonts/NanumGothic-Regular.ttf";
|
|
1206
|
+
window.fonts = [mainFont, aux1Font, aux2Font, aux3Font]
|
|
1207
|
+
|
|
1208
|
+
const Subscribe = eventName => {
|
|
1209
|
+
this.Subscribe(eventName, e => this.Emit("dxf-" + eventName, e))
|
|
1210
|
+
}
|
|
1211
|
+
for (const eventName of ["loaded", "cleared", "destroyed", "resized", "pointerdown",
|
|
1212
|
+
"pointerup", "viewChanged", "message", "added"]) {
|
|
1213
|
+
Subscribe(eventName)
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
Destroy() {
|
|
1218
|
+
super.Destroy();
|
|
1219
|
+
|
|
1220
|
+
this.objects = null
|
|
1221
|
+
this.objectMap = null
|
|
1222
|
+
this.selectedObjects = null
|
|
1223
|
+
this.drawables = null
|
|
1224
|
+
this.drawablePlugins = null
|
|
1225
|
+
this.xrefMap = null
|
|
1226
|
+
|
|
1227
|
+
window.dxfViewer = null
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
|
|
1231
|
+
async Load(url, xrefList) {
|
|
1232
|
+
window.isLoading = true
|
|
1233
|
+
window.error = null
|
|
1234
|
+
try {
|
|
1235
|
+
if (xrefList) {
|
|
1236
|
+
await this.loadXrefList(xrefList)
|
|
1237
|
+
}
|
|
1238
|
+
await this.LoadInternal({
|
|
1239
|
+
url,
|
|
1240
|
+
xrefList: xrefList,
|
|
1241
|
+
fonts: window.fonts,
|
|
1242
|
+
progressCbk: this.OnProgress.bind(window),
|
|
1243
|
+
workerFactory: null
|
|
1244
|
+
})
|
|
1245
|
+
} catch (error) {
|
|
1246
|
+
console.warn(error)
|
|
1247
|
+
window.error = error.toString()
|
|
1248
|
+
} finally {
|
|
1249
|
+
window.isLoading = false
|
|
1250
|
+
window.progressText = null
|
|
1251
|
+
window.progress = null
|
|
1252
|
+
window.curProgressPhase = null
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
async loadXrefList(xrefList) {
|
|
1257
|
+
for (const xref of xrefList) {
|
|
1258
|
+
var fileName = xref.substring(xref.lastIndexOf('/') + 1)
|
|
1259
|
+
const prefix = fileName.substring(0, fileName.lastIndexOf('.'))
|
|
1260
|
+
|
|
1261
|
+
const worker = new VitroDxfWorker()
|
|
1262
|
+
const { scene, dxf } = await worker.Load(xref, window.fonts, { retainParsedDxf: true, buildScene: false })
|
|
1263
|
+
//add file prefix to layers
|
|
1264
|
+
if (dxf.tables && dxf.tables.layer) {
|
|
1265
|
+
for (const [, layer] of Object.entries(dxf.tables.layer.layers)) {
|
|
1266
|
+
layer.name = this._GetXrefLayerName(layer.name, prefix)
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
//add file prefix to entities layer name
|
|
1270
|
+
if (dxf.entities) {
|
|
1271
|
+
this._ProcessXrefEntities(dxf.entities, prefix)
|
|
1272
|
+
}
|
|
1273
|
+
if (dxf.blocks) {
|
|
1274
|
+
for (const [, block] of Object.entries(dxf.blocks)) {
|
|
1275
|
+
if (block.entities) {
|
|
1276
|
+
this._ProcessXrefEntities(block.entities, prefix)
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
this.xrefMap[fileName] = dxf
|
|
1282
|
+
await worker.Destroy()
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
_ProcessXrefEntities(entities, prefix) {
|
|
1287
|
+
for (const entity of entities) {
|
|
1288
|
+
entity.layer = this._GetXrefLayerName(entity.layer, prefix)
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
_GetXrefLayerName(name, prefix) {
|
|
1293
|
+
if (name != "Defpoints" && name != "0") {
|
|
1294
|
+
return prefix + "|" + name
|
|
1295
|
+
}
|
|
1296
|
+
return name
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
|
|
1300
|
+
async LoadInternal({ url, fonts = null, progressCbk = null, workerFactory = null }) {
|
|
1301
|
+
if (url === null || url === undefined) {
|
|
1302
|
+
throw new Error("`url` parameter is not specified")
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
this._EnsureRenderer()
|
|
1306
|
+
|
|
1307
|
+
this.Clear()
|
|
1308
|
+
|
|
1309
|
+
this.worker = this.CreateDxfWorker(workerFactory)// new DxfWorker(workerFactory ? workerFactory() : null)
|
|
1310
|
+
this.options.xrefMap = this.xrefMap
|
|
1311
|
+
const { scene, dxf } = await this.worker.Load(url, fonts, this.options, progressCbk)
|
|
1312
|
+
this.scene = scene
|
|
1313
|
+
this.dxf = dxf
|
|
1314
|
+
await this.worker.Destroy()
|
|
1315
|
+
this.worker = null
|
|
1316
|
+
|
|
1317
|
+
this.hasMissingChars = scene.hasMissingChars
|
|
1318
|
+
|
|
1319
|
+
for (const layer of scene.layers) {
|
|
1320
|
+
this.layers.set(layer.name, new Layer(layer.name, layer.displayName, layer.color))
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
/* Load all blocks on the first pass. */
|
|
1324
|
+
for (const batch of scene.batches) {
|
|
1325
|
+
if (batch.key.blockName !== null &&
|
|
1326
|
+
batch.key.geometryType !== BatchingKey.GeometryType.BLOCK_INSTANCE &&
|
|
1327
|
+
batch.key.geometryType !== BatchingKey.GeometryType.POINT_INSTANCE) {
|
|
1328
|
+
|
|
1329
|
+
let block = this.blocks.get(batch.key.blockName)
|
|
1330
|
+
if (!block) {
|
|
1331
|
+
block = new Block()
|
|
1332
|
+
this.blocks.set(batch.key.blockName, block)
|
|
1333
|
+
}
|
|
1334
|
+
block.PushBatch(new VitroBatch(this, scene, batch))
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
console.log(`DXF scene:
|
|
1339
|
+
${scene.batches.length} batches,
|
|
1340
|
+
${this.layers.size} layers,
|
|
1341
|
+
${this.blocks.size} blocks,
|
|
1342
|
+
vertices ${scene.vertices.byteLength} B,
|
|
1343
|
+
indices ${scene.indices.byteLength} B
|
|
1344
|
+
transforms ${scene.transforms.byteLength} B`);
|
|
1345
|
+
|
|
1346
|
+
for (const layout of scene.layouts) {
|
|
1347
|
+
const space = this.CreateSpace(layout);
|
|
1348
|
+
this.LoadBatches();
|
|
1349
|
+
this.Render();
|
|
1350
|
+
this._Emit("loaded", { space });
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
this.SwitchSpace(scene.layouts[0]);
|
|
1354
|
+
|
|
1355
|
+
if (this.hasMissingChars) {
|
|
1356
|
+
this._Message("Some characters cannot be properly displayed due to missing fonts",
|
|
1357
|
+
MessageLevel.WARN)
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
if (!scene.tileMode) {
|
|
1361
|
+
this.SwitchSpace(scene.layouts[1])
|
|
1362
|
+
return
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
Render() {
|
|
1367
|
+
if (!this.spaceName)
|
|
1368
|
+
return
|
|
1369
|
+
|
|
1370
|
+
this._EnsureRenderer()
|
|
1371
|
+
const isPaperSpace = !IsModelSpace(this.spaceName)
|
|
1372
|
+
this.renderer.clear()
|
|
1373
|
+
this.renderer.autoClear = false
|
|
1374
|
+
this.renderer.setScissorTest(isPaperSpace)
|
|
1375
|
+
|
|
1376
|
+
const space = this.GetSpace()
|
|
1377
|
+
if (!space || !space.camera || !space.controls)
|
|
1378
|
+
return
|
|
1379
|
+
this.camera = space.camera
|
|
1380
|
+
|
|
1381
|
+
if (this.controls)
|
|
1382
|
+
this.controls.enabled = false
|
|
1383
|
+
this.controls = space.controls
|
|
1384
|
+
this.controls.enabled = true
|
|
1385
|
+
|
|
1386
|
+
let isFirstRenderVieports = false;
|
|
1387
|
+
if (isPaperSpace)//render viewports for current space (layout)
|
|
1388
|
+
{
|
|
1389
|
+
isFirstRenderVieports = this.RenderVieports(space);
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
//render current space entities (viewport borders (for layouts) and etc.)
|
|
1393
|
+
this.renderer.setViewport(0, 0, this.canvasWidth, this.canvasHeight);
|
|
1394
|
+
this.renderer.setScissor(0, 0, this.canvasWidth, this.canvasHeight);
|
|
1395
|
+
this.renderer.render(space.scene, this.camera)
|
|
1396
|
+
|
|
1397
|
+
if (isFirstRenderVieports) {
|
|
1398
|
+
this.DoFakeZoomToRedrawScene()
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
CreateDxfWorker(workerFactory) {
|
|
1403
|
+
return new VitroDxfWorker(workerFactory ? workerFactory() : null)
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
_LoadBatch(scene, batch) {
|
|
1407
|
+
if (!IsSpace(batch.key.blockName) &&
|
|
1408
|
+
batch.key.geometryType !== BatchingKey.GeometryType.BLOCK_INSTANCE &&
|
|
1409
|
+
batch.key.geometryType !== BatchingKey.GeometryType.POINT_INSTANCE) {
|
|
1410
|
+
/* Block definition. */
|
|
1411
|
+
return
|
|
1412
|
+
}
|
|
1413
|
+
if (batch.key.blockName !== this.spaceName)
|
|
1414
|
+
return;
|
|
1415
|
+
const objects = new VitroBatch(this, scene, batch).CreateObjects()
|
|
1416
|
+
|
|
1417
|
+
const layer = this.layers.get(batch.key.layerName)
|
|
1418
|
+
|
|
1419
|
+
const space = this.GetSpace()
|
|
1420
|
+
for (const obj of objects) {
|
|
1421
|
+
space.scene.add(obj)
|
|
1422
|
+
this._Emit("added", { obj })
|
|
1423
|
+
if (layer) {
|
|
1424
|
+
layer.PushObject(obj)
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
OnProgress(phase, size, totalSize) {
|
|
1430
|
+
if (phase !== window.curProgressPhase) {
|
|
1431
|
+
switch (phase) {
|
|
1432
|
+
case "font":
|
|
1433
|
+
window.progressText = "Fetching fonts..."
|
|
1434
|
+
break
|
|
1435
|
+
case "fetch":
|
|
1436
|
+
window.progressText = "Fetching file..."
|
|
1437
|
+
break
|
|
1438
|
+
case "parse":
|
|
1439
|
+
window.progressText = "Parsing file..."
|
|
1440
|
+
break
|
|
1441
|
+
case "prepare":
|
|
1442
|
+
window.progressText = "Preparing rendering data..."
|
|
1443
|
+
break
|
|
1444
|
+
}
|
|
1445
|
+
window.curProgressPhase = phase
|
|
1446
|
+
}
|
|
1447
|
+
if (totalSize === null) {
|
|
1448
|
+
window.progress = -1
|
|
1449
|
+
} else {
|
|
1450
|
+
window.progress = size / totalSize
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
Emit(eventName, event) {
|
|
1455
|
+
if (eventName == "dxf-added") {
|
|
1456
|
+
this.AddObject(event.detail.obj)
|
|
1457
|
+
}
|
|
1458
|
+
else if (eventName == "dxf-destroyed") {
|
|
1459
|
+
this.Destroy()
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
SetSize(width, height) {
|
|
1464
|
+
if (!this.camera) {
|
|
1465
|
+
this.camera = this.CreateCamera();
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
super.SetSize(width, height)
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
LoadBatches() {
|
|
1472
|
+
for (const batch of this.scene.batches) {
|
|
1473
|
+
this._LoadBatch(this.scene, batch)
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
SceneToCanvasCoord(v) {
|
|
1478
|
+
var width = this.canvasWidth, height = this.canvasHeight;
|
|
1479
|
+
var widthHalf = width / 2, heightHalf = height / 2;
|
|
1480
|
+
var pos = v.clone();
|
|
1481
|
+
pos.project(this.camera);
|
|
1482
|
+
|
|
1483
|
+
pos.x = (pos.x + 1) * widthHalf;
|
|
1484
|
+
pos.y = (pos.y + 1) * heightHalf;
|
|
1485
|
+
pos.z = 0;
|
|
1486
|
+
return pos
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
SwitchSpace(layout) {
|
|
1490
|
+
this.Cancel()
|
|
1491
|
+
this.spaceName = layout.space
|
|
1492
|
+
var space = this.GetSpace()
|
|
1493
|
+
if (!space) {
|
|
1494
|
+
space = this.CreateSpace(layout)
|
|
1495
|
+
|
|
1496
|
+
this.LoadBatches()
|
|
1497
|
+
this._Emit("loaded", { space })
|
|
1498
|
+
}
|
|
1499
|
+
this.Render()
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
CreateSpace(layout, camera) {
|
|
1503
|
+
var scene = new three.Scene()
|
|
1504
|
+
if (!camera) {
|
|
1505
|
+
camera = this.CreateCamera();
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
this.camera = camera
|
|
1509
|
+
if (layout.bounds) {
|
|
1510
|
+
this.FitView(layout.bounds.minX - layout.origin.x, layout.bounds.maxX - layout.origin.x,
|
|
1511
|
+
layout.bounds.minY - layout.origin.y, layout.bounds.maxY - layout.origin.y)
|
|
1512
|
+
} else {
|
|
1513
|
+
this._Message("Empty document space", MessageLevel.WARN)
|
|
1514
|
+
}
|
|
1515
|
+
const controls = this.CreateControls()
|
|
1516
|
+
|
|
1517
|
+
const space = { scene: scene, camera: camera, controls: controls, layout: layout }
|
|
1518
|
+
this.spaces.set(layout.space, space)
|
|
1519
|
+
this.spaceName = layout.space
|
|
1520
|
+
return space
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
CreateCamera() {
|
|
1524
|
+
const camera = new three.OrthographicCamera(-1, 1, 1, -1, 0.1, 2);
|
|
1525
|
+
camera.position.z = 1
|
|
1526
|
+
camera.position.x = 0
|
|
1527
|
+
camera.position.y = 0
|
|
1528
|
+
return camera
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
Clear() {
|
|
1532
|
+
this._EnsureRenderer()
|
|
1533
|
+
if (this.worker) {
|
|
1534
|
+
this.worker.Destroy(true)
|
|
1535
|
+
this.worker = null
|
|
1536
|
+
}
|
|
1537
|
+
if (this.controls) {
|
|
1538
|
+
this.controls.dispose()
|
|
1539
|
+
this.controls = null
|
|
1540
|
+
}
|
|
1541
|
+
for (const space of this.spaces.values()) {
|
|
1542
|
+
space.scene.clear()
|
|
1543
|
+
}
|
|
1544
|
+
for (const layer of this.layers.values()) {
|
|
1545
|
+
layer.Dispose()
|
|
1546
|
+
}
|
|
1547
|
+
this.spaces.clear()
|
|
1548
|
+
this.layers.clear()
|
|
1549
|
+
this.blocks.clear()
|
|
1550
|
+
this.materials.each(e => e.material.dispose())
|
|
1551
|
+
this.materials.clear()
|
|
1552
|
+
this.SetView({ x: 0, y: 0 }, 2)
|
|
1553
|
+
this._Emit("cleared")
|
|
1554
|
+
this.Render()
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
DoFakeZoomToRedrawScene() {//todo to refactor
|
|
1558
|
+
let wheelEvent = new WheelEvent('wheel', {
|
|
1559
|
+
deltaY: 1,
|
|
1560
|
+
deltaMode: 0
|
|
1561
|
+
})
|
|
1562
|
+
this.canvas.dispatchEvent(wheelEvent)
|
|
1563
|
+
wheelEvent = new WheelEvent('wheel', {
|
|
1564
|
+
deltaY: -1,
|
|
1565
|
+
deltaMode: 0,
|
|
1566
|
+
position: [0, 0, 0]
|
|
1567
|
+
})
|
|
1568
|
+
this.canvas.dispatchEvent(wheelEvent)
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
RenderVieports(space) {
|
|
1572
|
+
var modelSpace = this.GetSpace("*Model_Space")
|
|
1573
|
+
const modelScene = modelSpace.scene
|
|
1574
|
+
let isFirstRender = false;
|
|
1575
|
+
//create temporary scenes with viewport borders to calculate viewport position and size
|
|
1576
|
+
for (var viewport of space.layout.viewports.values()) {
|
|
1577
|
+
var tmpScene = new three.Scene()
|
|
1578
|
+
const points = [];
|
|
1579
|
+
for (const vertex of viewport.vertices) {
|
|
1580
|
+
points.push(this.TransformVertex(vertex, space));
|
|
1581
|
+
}
|
|
1582
|
+
var geom = new three.BufferGeometry().setFromPoints(points);
|
|
1583
|
+
var line = new three.LineSegments(geom, new three.LineBasicMaterial({ color: 0xff00ff }));
|
|
1584
|
+
tmpScene.add(line);//viewport border
|
|
1585
|
+
|
|
1586
|
+
if (!viewport.camera) {
|
|
1587
|
+
isFirstRender = true;
|
|
1588
|
+
viewport.camera = this.CreateCamera();
|
|
1589
|
+
const center = this.TransformVertex(viewport.viewCenter, modelSpace)
|
|
1590
|
+
center.x += viewport.viewTarget.x
|
|
1591
|
+
center.y += viewport.viewTarget.y
|
|
1592
|
+
center.z += viewport.viewTarget.z
|
|
1593
|
+
const width = viewport.viewHeight * viewport.width / viewport.height
|
|
1594
|
+
this.SetView(center, width, viewport.viewHeight, viewport.camera)
|
|
1595
|
+
viewport.camera.rotation.set(0, 0, -viewport.twist / 180 * Math.PI)
|
|
1596
|
+
}
|
|
1597
|
+
this.renderer.render(tmpScene, viewport.camera)
|
|
1598
|
+
|
|
1599
|
+
//calculate viewport position and size
|
|
1600
|
+
var box = new three.Box3().setFromObject(line)
|
|
1601
|
+
var vmin = this.SceneToCanvasCoord(box.min)
|
|
1602
|
+
var vmax = this.SceneToCanvasCoord(box.max)
|
|
1603
|
+
|
|
1604
|
+
viewport.x = vmin.x
|
|
1605
|
+
viewport.y = vmin.y
|
|
1606
|
+
viewport.width = vmax.x - vmin.x
|
|
1607
|
+
viewport.height = Math.abs(vmax.y - vmin.y)
|
|
1608
|
+
}
|
|
1609
|
+
this.renderer.clear()//clear temporary scenes
|
|
1610
|
+
|
|
1611
|
+
for (var viewport of space.layout.viewports.values()) //render each viewport - clipped modelScene (main scene) using viewport position and size and his camera
|
|
1612
|
+
{
|
|
1613
|
+
if (viewport.camera) {
|
|
1614
|
+
this.renderer.setViewport(viewport.x, viewport.y, viewport.width, viewport.height)
|
|
1615
|
+
this.renderer.setScissor(viewport.x, viewport.y, viewport.width, viewport.height)
|
|
1616
|
+
this.renderer.render(modelScene, viewport.camera)
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
return isFirstRender
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
GetSpace(name) {
|
|
1624
|
+
name = name || this.spaceName
|
|
1625
|
+
return this.spaces.get(name)
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
GetSpaceByHandle(handle) {
|
|
1629
|
+
for (const space of this.spaces.values()) {
|
|
1630
|
+
if (space.layout.spaceHandle === handle) {
|
|
1631
|
+
return space
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
return null
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
|
|
1639
|
+
GetLayoutBySpaceHandle(spaceHandle) {
|
|
1640
|
+
for (const layout of this.scene.layouts) {
|
|
1641
|
+
if (spaceHandle === layout.spaceHandle) {
|
|
1642
|
+
return layout;
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
return null
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
|
|
1650
|
+
GetOrigin(layout) {
|
|
1651
|
+
return layout.origin
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
CreateControls() {
|
|
1655
|
+
if (this.controls)
|
|
1656
|
+
this.controls.enabled = false
|
|
1657
|
+
const controls = this.controls = new OrbitControls(this.camera, this.canvas)
|
|
1658
|
+
controls.enableRotate = false
|
|
1659
|
+
controls.mouseButtons = {
|
|
1660
|
+
RIGHT: three.MOUSE.PAN,
|
|
1661
|
+
MIDDLE: three.MOUSE.DOLLY
|
|
1662
|
+
}
|
|
1663
|
+
controls.touches = {
|
|
1664
|
+
ONE: three.TOUCH.PAN,
|
|
1665
|
+
TWO: three.TOUCH.DOLLY_PAN
|
|
1666
|
+
}
|
|
1667
|
+
controls.zoomSpeed = 3
|
|
1668
|
+
controls.mouseZoomSpeedFactor = 0.05
|
|
1669
|
+
controls.target = new three.Vector3(this.camera.position.x, this.camera.position.y, 0)
|
|
1670
|
+
controls.addEventListener("change", () => {
|
|
1671
|
+
this._Emit("viewChanged")
|
|
1672
|
+
this.Render()
|
|
1673
|
+
})
|
|
1674
|
+
controls.update()
|
|
1675
|
+
return controls
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
SetView(center, width, height = null, camera = null) {
|
|
1679
|
+
const cam = camera ? camera : this.camera
|
|
1680
|
+
if (!cam) {
|
|
1681
|
+
return;
|
|
1682
|
+
}
|
|
1683
|
+
if (!height) {
|
|
1684
|
+
const aspect = this.canvasWidth / this.canvasHeight
|
|
1685
|
+
height = width / aspect
|
|
1686
|
+
}
|
|
1687
|
+
cam.left = -width / 2
|
|
1688
|
+
cam.right = width / 2
|
|
1689
|
+
cam.top = height / 2
|
|
1690
|
+
cam.bottom = -height / 2
|
|
1691
|
+
cam.zoom = 1
|
|
1692
|
+
cam.position.set(center.x, center.y, 1)
|
|
1693
|
+
cam.rotation.set(0, 0, 0)
|
|
1694
|
+
cam.updateMatrix()
|
|
1695
|
+
cam.updateProjectionMatrix()
|
|
1696
|
+
this._Emit("viewChanged")
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
TransformVertex(v, space) {
|
|
1700
|
+
return new three.Vector3(v.x - space.layout.origin.x, v.y - space.layout.origin.y, v.z)
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
SelectObj(event) {
|
|
1704
|
+
var raycaster = new three.Raycaster();
|
|
1705
|
+
raycaster.params.Line.threshold = 15;
|
|
1706
|
+
|
|
1707
|
+
var mouse = new three.Vector2();
|
|
1708
|
+
var e = event.detail.domEvent
|
|
1709
|
+
const canvasRect = event.target.getBoundingClientRect()
|
|
1710
|
+
const canvasCoord = { x: e.clientX - canvasRect.left, y: e.clientY - canvasRect.top }
|
|
1711
|
+
mouse.x = (canvasCoord.x / this.renderer.domElement.clientWidth) * 2 - 1;
|
|
1712
|
+
mouse.y = - (canvasCoord.y / this.renderer.domElement.clientHeight) * 2 + 1;
|
|
1713
|
+
mouse.z = 0;
|
|
1714
|
+
|
|
1715
|
+
raycaster.setFromCamera(mouse, this.camera);
|
|
1716
|
+
var intersects = raycaster.intersectObjects(this.objects, true);
|
|
1717
|
+
if (intersects && intersects.length > 0) {
|
|
1718
|
+
let selectedIndex = 0
|
|
1719
|
+
if (intersects[selectedIndex].object.name) {
|
|
1720
|
+
const name = intersects[selectedIndex].object.name
|
|
1721
|
+
const objectList = this.objectMap.get(name)
|
|
1722
|
+
if (objectList) {
|
|
1723
|
+
this.SetSelected(objectList)
|
|
1724
|
+
return name
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
return null
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
GetSelectHandle() {
|
|
1732
|
+
if (this.selectedObjects && this.selectedObjects.length > 0) {
|
|
1733
|
+
return selectedObjects[0].name
|
|
1734
|
+
}
|
|
1735
|
+
return null
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
HighlightColor(color, factor = 0.3) {
|
|
1739
|
+
color.r += factor;
|
|
1740
|
+
if (color.r > 1)
|
|
1741
|
+
color.r -= 1;
|
|
1742
|
+
if (color.r < 0)
|
|
1743
|
+
color.r += 1;
|
|
1744
|
+
color.g += factor;
|
|
1745
|
+
if (color.g > 1)
|
|
1746
|
+
color.g -= 1;
|
|
1747
|
+
if (color.g < 0)
|
|
1748
|
+
color.g += 1;
|
|
1749
|
+
color.b += factor;
|
|
1750
|
+
if (color.b > 1)
|
|
1751
|
+
color.b -= 1;
|
|
1752
|
+
if (color.b < 0)
|
|
1753
|
+
color.b += 1;
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
|
|
1757
|
+
SetSelected(objectList) {
|
|
1758
|
+
if (this.selectedObjects && this.selectedObjects.length > 0) {
|
|
1759
|
+
for (const object of this.selectedObjects) {
|
|
1760
|
+
const drawable = this.GetDrawable(object.name);
|
|
1761
|
+
if (!(drawable && drawable.drawMode === DrawMode.ANNOTATIONS)) {
|
|
1762
|
+
if (object.material.uniforms) {
|
|
1763
|
+
object.material.uniforms.color.value = object.color;
|
|
1764
|
+
}
|
|
1765
|
+
else {
|
|
1766
|
+
object.material.color = object.color;
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
this.selectedObjects = objectList
|
|
1773
|
+
if (this.selectedObjects && this.selectedObjects.length > 0) {
|
|
1774
|
+
for (const object of this.selectedObjects) {
|
|
1775
|
+
const drawable = this.GetDrawable(object.name);
|
|
1776
|
+
if (!(drawable && drawable.drawMode === DrawMode.ANNOTATIONS)) {
|
|
1777
|
+
let mat_wire = object.material.clone();
|
|
1778
|
+
if (object.material.uniforms) {
|
|
1779
|
+
object.color = object.material.uniforms.color.value;
|
|
1780
|
+
this.HighlightColor(mat_wire.uniforms.color.value);
|
|
1781
|
+
}
|
|
1782
|
+
else {
|
|
1783
|
+
object.color = object.material.color;
|
|
1784
|
+
this.HighlightColor(mat_wire.color);
|
|
1785
|
+
}
|
|
1786
|
+
object.material = mat_wire;
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
this.Render()
|
|
1791
|
+
const id = this.GetSelectedHandle()
|
|
1792
|
+
this._Emit("selected", { id })
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
GetSelectedHandle() {
|
|
1796
|
+
if (this.selectedObjects && this.selectedObjects.length > 0) {
|
|
1797
|
+
return this.selectedObjects[0].name
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
return null
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
AddObject(obj) {
|
|
1804
|
+
this.objects.push(obj)
|
|
1805
|
+
const name = obj.name
|
|
1806
|
+
if (name) {
|
|
1807
|
+
let objectList = this.objectMap.get(name)
|
|
1808
|
+
if (!objectList) {
|
|
1809
|
+
objectList = []
|
|
1810
|
+
this.objectMap.set(name, objectList)
|
|
1811
|
+
}
|
|
1812
|
+
objectList.push(obj)
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
ZoomTo(input, offset) {
|
|
1817
|
+
const object = Array.isArray(input) ? input[0] : input //todo to calc boundingBox of all objects
|
|
1818
|
+
offset = offset || 1.25;
|
|
1819
|
+
|
|
1820
|
+
const boundingBox = new three.Box3();
|
|
1821
|
+
// get bounding box of object - this will be used to setup controls and camera
|
|
1822
|
+
boundingBox.setFromObject(object);
|
|
1823
|
+
|
|
1824
|
+
const center = boundingBox.getCenter(new three.Vector3());
|
|
1825
|
+
const size = boundingBox.getSize(new three.Vector3());
|
|
1826
|
+
this.FitView(boundingBox.min.x, boundingBox.max.x, boundingBox.min.y, boundingBox.max.y)
|
|
1827
|
+
this.controls.target.copy(center);
|
|
1828
|
+
|
|
1829
|
+
this.controls.update()
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
ZoomToDrawable(spaceHandle, id) {
|
|
1833
|
+
const space = this.GetSpaceByHandle(spaceHandle)
|
|
1834
|
+
var layout = null
|
|
1835
|
+
if (!space) {//space has not been loaded yet
|
|
1836
|
+
layout = this.GetLayoutBySpaceHandle(spaceHandle)
|
|
1837
|
+
}
|
|
1838
|
+
else {
|
|
1839
|
+
layout = space.layout
|
|
1840
|
+
}
|
|
1841
|
+
if (layout) {
|
|
1842
|
+
if (this.spaceName != layout.space) {
|
|
1843
|
+
this.SwitchSpace(layout)
|
|
1844
|
+
}
|
|
1845
|
+
const drawable = this.GetDrawable(id)
|
|
1846
|
+
if (drawable?.drawMode === DrawMode.ANNOTATIONS) {//this is annotation
|
|
1847
|
+
this.ZoomTo(drawable.objects)
|
|
1848
|
+
return drawable
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
return null
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
RemoveFromScene(scene, objects) {
|
|
1855
|
+
for (const object of objects) {
|
|
1856
|
+
scene.remove(object);
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
GetDrawable(id) {
|
|
1861
|
+
for (const drawable of this.drawables) {
|
|
1862
|
+
if (drawable.id == id) {
|
|
1863
|
+
return drawable
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
return null
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
VisibleDrawable(drawMode, visible) {
|
|
1870
|
+
var isDirty = false
|
|
1871
|
+
for (const drawable of this.drawables) {
|
|
1872
|
+
if (drawable.drawMode === drawMode) {
|
|
1873
|
+
for (const object of drawable.objects) {
|
|
1874
|
+
object.visible = visible;
|
|
1875
|
+
isDirty = true
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
if (isDirty) {
|
|
1880
|
+
this.Render()
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
DeleteDrawable(id) {
|
|
1885
|
+
const drawable = this.GetDrawable(id)
|
|
1886
|
+
if (drawable) {
|
|
1887
|
+
const space = drawable.space
|
|
1888
|
+
this.RemoveFromScene(space.scene, drawable.objects)
|
|
1889
|
+
const index = this.drawables.indexOf(drawable);
|
|
1890
|
+
|
|
1891
|
+
if (index !== - 1) {
|
|
1892
|
+
this.drawables.splice(index, 1)
|
|
1893
|
+
}
|
|
1894
|
+
const currentSpace = this.GetSpace()
|
|
1895
|
+
if (space === currentSpace) {
|
|
1896
|
+
this.Render()
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
Cancel() {
|
|
1902
|
+
this.SetSelected(null)
|
|
1903
|
+
for (const plugin of this.drawablePlugins) {
|
|
1904
|
+
plugin.Cancel()
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
RegisterDrawablePlugin(plugin) {
|
|
1909
|
+
this.drawablePlugins.push(plugin)
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
OnKeyDown = event => {
|
|
1913
|
+
this.DoKeyDown(event)
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
DoKeyDown(event) {
|
|
1917
|
+
if (event.keyCode == 27) {//ESC
|
|
1918
|
+
this.Cancel()
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1922
|
+
FindDxfEntity(id) {
|
|
1923
|
+
if (!this.dxf) {
|
|
1924
|
+
return null
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
let entity = this.FindEntityInList(id, this.dxf.entities)
|
|
1928
|
+
if (!entity && this.dxf.blocks) {
|
|
1929
|
+
for (const [, block] of Object.entries(this.dxf.blocks)) {
|
|
1930
|
+
entity = this.FindEntityInList(id, block.entities)
|
|
1931
|
+
if (entity) {
|
|
1932
|
+
break
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
return entity
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
FindEntityInList(id, entities) {
|
|
1941
|
+
if (entities) {
|
|
1942
|
+
for (const entity of entities) {
|
|
1943
|
+
if (id === entity.handle) {
|
|
1944
|
+
return entity
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
return null
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
ZoomIn(scale) {
|
|
1953
|
+
const centerX = this.canvasWidth / 2 * window.devicePixelRatio;
|
|
1954
|
+
const centerY = this.canvasHeight / 2 * window.devicePixelRatio;
|
|
1955
|
+
scale = scale ? scale : Math.pow(0.95, 3);
|
|
1956
|
+
this.controls.zoomIn(scale, new three.Vector2(centerX, centerY));
|
|
1957
|
+
this.controls.update();
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
ZoomOut(scale) {
|
|
1961
|
+
const centerX = this.canvasWidth / 2 * window.devicePixelRatio;
|
|
1962
|
+
const centerY = this.canvasHeight / 2 * window.devicePixelRatio;
|
|
1963
|
+
scale = scale ? scale : Math.pow(0.95, 3);
|
|
1964
|
+
this.controls.zoomOut(scale, new three.Vector2(centerX, centerY));
|
|
1965
|
+
this.controls.update();
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
export class Drawable {
|
|
1969
|
+
constructor(options) {
|
|
1970
|
+
|
|
1971
|
+
this.viewer = options.viewer
|
|
1972
|
+
this.drawMode = null
|
|
1973
|
+
this.idPrefix = ""
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
Create() {
|
|
1977
|
+
this.viewer.Cancel()
|
|
1978
|
+
|
|
1979
|
+
this.objects = []
|
|
1980
|
+
this.viewer.drawableSpace = this.viewer.GetSpace()
|
|
1981
|
+
|
|
1982
|
+
this.id = this.CreateId()
|
|
1983
|
+
this.viewer.drawMode = this.drawMode
|
|
1984
|
+
this.viewer.Subscribe("pointerdown", this.OnPointerDown)
|
|
1985
|
+
this.viewer.Subscribe("mousemove", this.OnMouseMove)
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
Add(spaceHandle, id) {
|
|
1989
|
+
const space = this.viewer.GetSpaceByHandle(spaceHandle)
|
|
1990
|
+
if (!space) {
|
|
1991
|
+
return false
|
|
1992
|
+
}
|
|
1993
|
+
this.viewer.drawableSpace = space
|
|
1994
|
+
this.objects = []
|
|
1995
|
+
this.id = id || this.CreateId()
|
|
1996
|
+
this.viewer.drawMode = this.drawMode
|
|
1997
|
+
return true
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
Cancel() {
|
|
2001
|
+
this.CancelDraw()
|
|
2002
|
+
this.Finish()
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
|
|
2006
|
+
OnPointerDown = event => {
|
|
2007
|
+
if (event.detail.domEvent.button == 0) {
|
|
2008
|
+
this.DoLeftPointerDown(event)
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
DoLeftPointerDown(event) {
|
|
2013
|
+
if (!this.IsValidDrawMode()) {
|
|
2014
|
+
return false
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
return true
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
OnMouseMove = event => {
|
|
2021
|
+
this.DoMouseMove(event)
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
DoMouseMove(event) {
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
CancelDraw(){
|
|
2028
|
+
if (this.RemoveCancelledObjects()) {
|
|
2029
|
+
const drawMode = this.drawMode
|
|
2030
|
+
this.viewer._Emit("drawCancelled", { drawMode })
|
|
2031
|
+
}
|
|
2032
|
+
if (this.IsValidDrawMode()) {
|
|
2033
|
+
this.viewer.drawMode = null
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
RemoveCancelledObjects() {
|
|
2038
|
+
if (!this.IsValidDrawMode()) {
|
|
2039
|
+
return false
|
|
2040
|
+
}
|
|
2041
|
+
if (!this.objects || this.objects.length == 0) {
|
|
2042
|
+
return false
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
this.viewer.RemoveFromScene(this.viewer.drawableSpace.scene, this.objects)
|
|
2046
|
+
this.objects = []
|
|
2047
|
+
|
|
2048
|
+
this.RenderIfNeeded()
|
|
2049
|
+
this.viewer.drawableSpace = null
|
|
2050
|
+
|
|
2051
|
+
return true
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
RenderIfNeeded() {
|
|
2055
|
+
const currentSpace = this.viewer.GetSpace()
|
|
2056
|
+
if (this.viewer.drawableSpace == currentSpace) {
|
|
2057
|
+
this.viewer.Render()
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
CreateId() {
|
|
2062
|
+
const uuid = self.crypto.randomUUID();
|
|
2063
|
+
return this.idPrefix + uuid
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
IsValidDrawMode() {
|
|
2067
|
+
return this.viewer.drawMode === this.drawMode
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
|
|
2071
|
+
Finish() {
|
|
2072
|
+
this.viewer.Unsubscribe("mousemove", this.OnMouseMove)
|
|
2073
|
+
this.viewer.Unsubscribe("pointerdown", this.OnPointerDown)
|
|
2074
|
+
document.removeEventListener("keydown", this.OnKeyDown)
|
|
2075
|
+
if (this.IsValidDrawMode()) {
|
|
2076
|
+
this.viewer.drawMode = null
|
|
2077
|
+
}
|
|
2078
|
+
this.objects = []
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
CreateVector(pt) {
|
|
2082
|
+
return new three.Vector3(pt.x, pt.y, 0)
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
AddDrawableObjectToScene(object) {
|
|
2086
|
+
const space = this.viewer.GetSpace()
|
|
2087
|
+
space.scene.add(object);
|
|
2088
|
+
this.objects.push(object)
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
AddToAllViewerObjects() {
|
|
2092
|
+
for (const object of this.objects) {
|
|
2093
|
+
this.viewer.AddObject(object)
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
AddAndFinish(drawable) {
|
|
2098
|
+
this.viewer.drawables.push(drawable)
|
|
2099
|
+
this.viewer._Emit("drawableCreated", drawable)
|
|
2100
|
+
|
|
2101
|
+
this.AddToAllViewerObjects()
|
|
2102
|
+
this.Finish()
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
const ID_PREFIX = "anno_"
|
|
2107
|
+
|
|
2108
|
+
export class Annotation extends Drawable {
|
|
2109
|
+
constructor(options) {
|
|
2110
|
+
|
|
2111
|
+
super(options);
|
|
2112
|
+
this.idPrefix = ID_PREFIX;
|
|
2113
|
+
this.color = options.color;
|
|
2114
|
+
this.drawMode = DrawMode.ANNOTATIONS;
|
|
2115
|
+
this.labelRenderer = this.InitLabelRenderer();
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
Create() {
|
|
2119
|
+
super.Create();
|
|
2120
|
+
this.FirstPoint = this.SecondPoint = null;
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2123
|
+
Add(spaceHandle, firstPoint, secondPoint, id, color) {
|
|
2124
|
+
if (!super.Add(spaceHandle, id)) {
|
|
2125
|
+
return null;
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2128
|
+
this.FirstPoint = firstPoint;
|
|
2129
|
+
this.SecondPoint = secondPoint;
|
|
2130
|
+
this.color = color;
|
|
2131
|
+
return this.UpdateAndAdd();
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
DoLeftPointerDown(event) {
|
|
2135
|
+
if (!super.DoLeftPointerDown()) {
|
|
2136
|
+
return;
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2139
|
+
if (!this.FirstPoint) {
|
|
2140
|
+
this.FirstPoint = this.SecondPoint = this.CreateVector(event.detail.position);
|
|
2141
|
+
this.Update();
|
|
2142
|
+
}
|
|
2143
|
+
else {
|
|
2144
|
+
this.SecondPoint = this.CreateVector(event.detail.position);
|
|
2145
|
+
this.UpdateAndAdd();
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
UpdateAndAdd() {
|
|
2150
|
+
this.Update();
|
|
2151
|
+
|
|
2152
|
+
const firstPoint = this.FirstPoint;
|
|
2153
|
+
const secondPoint = this.SecondPoint;
|
|
2154
|
+
const space = this.viewer.drawableSpace;
|
|
2155
|
+
const id = this.id;
|
|
2156
|
+
const objects = this.objects;
|
|
2157
|
+
const drawMode = this.drawMode;
|
|
2158
|
+
var annotation = { drawMode, id, firstPoint, secondPoint, space, objects };
|
|
2159
|
+
|
|
2160
|
+
this.AddAndFinish(annotation);
|
|
2161
|
+
return annotation;
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
DoMouseMove(event) {
|
|
2165
|
+
this.SecondPoint = this.CreateVector(event.detail.position);
|
|
2166
|
+
this.Update();
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
Update() {
|
|
2170
|
+
if (!this.FirstPoint || !this.SecondPoint) {
|
|
2171
|
+
return
|
|
2172
|
+
}
|
|
2173
|
+
const points = [];
|
|
2174
|
+
points.push(this.FirstPoint)
|
|
2175
|
+
let pt = this.FirstPoint.clone()
|
|
2176
|
+
pt.x = this.SecondPoint.x
|
|
2177
|
+
points.push(pt)
|
|
2178
|
+
points.push(pt)
|
|
2179
|
+
points.push(this.SecondPoint)
|
|
2180
|
+
points.push(this.SecondPoint)
|
|
2181
|
+
pt = this.FirstPoint.clone()
|
|
2182
|
+
pt.y = this.SecondPoint.y
|
|
2183
|
+
points.push(pt)
|
|
2184
|
+
points.push(pt)
|
|
2185
|
+
points.push(this.FirstPoint)
|
|
2186
|
+
var geom = new three.BufferGeometry().setFromPoints(points);
|
|
2187
|
+
if (this.objects.length > 0) {
|
|
2188
|
+
this.objects[0].geometry.dispose()
|
|
2189
|
+
this.objects[0].geometry = geom
|
|
2190
|
+
}
|
|
2191
|
+
else {
|
|
2192
|
+
const material = new three.LineBasicMaterial({ color: this.color })
|
|
2193
|
+
const object = new three.LineSegments(geom, material);
|
|
2194
|
+
object.name = this.id
|
|
2195
|
+
|
|
2196
|
+
if (!this.id.includes(this.idPrefix)) {
|
|
2197
|
+
this.InitLabel(object);
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2200
|
+
this.AddDrawableObjectToScene(object)
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2203
|
+
this.RenderIfNeeded()
|
|
2204
|
+
}
|
|
2205
|
+
|
|
2206
|
+
InitLabel(annotation) {
|
|
2207
|
+
const id = this.id;
|
|
2208
|
+
const labelDiv = document.createElement('div');
|
|
2209
|
+
labelDiv.className = 'vitro-marker-label';
|
|
2210
|
+
labelDiv.textContent = id;
|
|
2211
|
+
labelDiv.style.backgroundColor = this.color;
|
|
2212
|
+
labelDiv.style.backgroundColor = this.color;
|
|
2213
|
+
if (this.onLabelClick) {
|
|
2214
|
+
labelDiv.onclick = () => this.onLabelClick(id);
|
|
2215
|
+
}
|
|
2216
|
+
|
|
2217
|
+
const label = new CSS2DObject(labelDiv);
|
|
2218
|
+
label.position.copy(this.FirstPoint);
|
|
2219
|
+
label.center.set(0.5, 0.5);
|
|
2220
|
+
annotation.add(label);
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
UpdateLabelPosition() {
|
|
2224
|
+
if (this.labelRenderer && window.dxfViewer.GetSpace()) {
|
|
2225
|
+
this.labelRenderer.render(window.dxfViewer.GetSpace().scene, window.dxfViewer.GetSpace().camera);
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
|
|
2229
|
+
RemoveLabels() {
|
|
2230
|
+
if (this.labelRenderer) {
|
|
2231
|
+
$(this.labelRenderer.domElement).html(null);
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
InitLabelRenderer() {
|
|
2236
|
+
const labelRenderer = new CSS2DRenderer();
|
|
2237
|
+
labelRenderer.setSize($('#canvasContainer').innerWidth(), $('#canvasContainer').innerHeight());
|
|
2238
|
+
labelRenderer.domElement.style.position = 'absolute';
|
|
2239
|
+
labelRenderer.domElement.style.top = '0px';
|
|
2240
|
+
labelRenderer.domElement.style.pointerEvents = 'none';
|
|
2241
|
+
document.getElementById('canvasContainer').appendChild(labelRenderer.domElement);
|
|
2242
|
+
|
|
2243
|
+
return labelRenderer;
|
|
2244
|
+
}
|
|
2245
|
+
|
|
2246
|
+
UpdateLabelRendererSize() {
|
|
2247
|
+
this.labelRenderer.setSize(this.viewer.canvasWidth, this.viewer.canvasHeight);
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
/** Fetches and parses DXF file. */
|
|
2252
|
+
export class VitroDxfFetcher extends DxfFetcher {
|
|
2253
|
+
|
|
2254
|
+
async SyncFetch() {
|
|
2255
|
+
//const response = fetch(this.url)
|
|
2256
|
+
const dxf = await SyncFetchDxf(this.url)
|
|
2257
|
+
/*
|
|
2258
|
+
const reader = response.body.getReader()
|
|
2259
|
+
//XXX streaming parsing is not supported in dxf-parser for now (its parseStream() method
|
|
2260
|
+
// just accumulates chunks in a string buffer before parsing. Fix it later.
|
|
2261
|
+
let buffer = ""
|
|
2262
|
+
let decoder = new TextDecoder("utf-8")
|
|
2263
|
+
while(true) {
|
|
2264
|
+
const {done, value} = reader.read()
|
|
2265
|
+
if (done) {
|
|
2266
|
+
buffer += decoder.decode(new ArrayBuffer(0), {stream: false})
|
|
2267
|
+
break
|
|
2268
|
+
}
|
|
2269
|
+
buffer += decoder.decode(value, {stream: true})
|
|
2270
|
+
}
|
|
2271
|
+
*/
|
|
2272
|
+
const parser = new DxfParser()
|
|
2273
|
+
return parser.parseSync(buffer)
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2276
|
+
async SyncFetchDxf(url) {
|
|
2277
|
+
const response = await fetch(url)
|
|
2278
|
+
const txt = await response.json()
|
|
2279
|
+
return txt
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
const INDEXED_CHUNK_SIZE = 0x10000
|
|
2283
|
+
|
|
2284
|
+
export class VitroRenderBatch extends RenderBatch {
|
|
2285
|
+
constructor(key) {
|
|
2286
|
+
super(key)
|
|
2287
|
+
}
|
|
2288
|
+
|
|
2289
|
+
PushVertex(v) {
|
|
2290
|
+
const idx = this.vertices.Push(v.x)
|
|
2291
|
+
this.vertices.Push(v.y)
|
|
2292
|
+
this.vertices.Push(0)//vitro
|
|
2293
|
+
return idx
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
PushChunk(verticesCount, entity = null) {
|
|
2297
|
+
if (verticesCount > INDEXED_CHUNK_SIZE) {
|
|
2298
|
+
throw new Error("Vertices count exceeds chunk limit: " + verticesCount)
|
|
2299
|
+
}
|
|
2300
|
+
/* Find suitable chunk with minimal remaining space to fill them as fully as possible. */
|
|
2301
|
+
let curChunk = null
|
|
2302
|
+
//vitro - always create new chunk
|
|
2303
|
+
let curSpace = 0
|
|
2304
|
+
for (const chunk of this.chunks) {
|
|
2305
|
+
const space = INDEXED_CHUNK_SIZE - chunk.vertices.GetSize() / 3 //vitro 3 instead 2
|
|
2306
|
+
if (space < verticesCount) {
|
|
2307
|
+
continue
|
|
2308
|
+
}
|
|
2309
|
+
if (entity && entity.handle && chunk.handle != entity.handle) {//vitro
|
|
2310
|
+
continue
|
|
2311
|
+
}
|
|
2312
|
+
if (curChunk === null || space < curSpace) {
|
|
2313
|
+
curChunk = chunk
|
|
2314
|
+
curSpace = space
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
|
|
2318
|
+
if (curChunk === null) {
|
|
2319
|
+
curChunk = this._NewChunk(verticesCount)
|
|
2320
|
+
if (entity && entity.handle) {//vitro
|
|
2321
|
+
curChunk.handle = entity.handle
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
return new IndexedChunkWriter(curChunk, verticesCount)
|
|
2325
|
+
}
|
|
2326
|
+
|
|
2327
|
+
/** Merge other batch into this one. They should have the same geometry type. Instanced batches
|
|
2328
|
+
* are disallowed.
|
|
2329
|
+
*
|
|
2330
|
+
* @param batch {RenderBatch}
|
|
2331
|
+
* @param transform {?Matrix3} Optional transform to apply for merged vertices.
|
|
2332
|
+
*/
|
|
2333
|
+
Merge(batch, transform = null, entity = null) {//vitro add entity
|
|
2334
|
+
if (this.key.geometryType !== batch.key.geometryType) {
|
|
2335
|
+
throw new Error("Rendering batch merging geometry type mismatch: " +
|
|
2336
|
+
`${this.key.geometryType} !== ${batch.key.geometryType}`)
|
|
2337
|
+
}
|
|
2338
|
+
if (this.key.IsInstanced()) {
|
|
2339
|
+
throw new Error("Attempted to merge instanced batch")
|
|
2340
|
+
}
|
|
2341
|
+
if (this.key.IsIndexed()) {
|
|
2342
|
+
/* Merge chunks. */
|
|
2343
|
+
for (const chunk of batch.chunks) {
|
|
2344
|
+
const verticesSize = chunk.vertices.size
|
|
2345
|
+
const chunkWriter = this.PushChunk(verticesSize / 3, entity)//vitro 2 => 3
|
|
2346
|
+
for (let i = 0; i < verticesSize; i += 3) {//vitro 2 => 3
|
|
2347
|
+
const v = new Vector2(chunk.vertices.Get(i), chunk.vertices.Get(i + 1))
|
|
2348
|
+
if (transform) {
|
|
2349
|
+
v.applyMatrix3(transform)
|
|
2350
|
+
}
|
|
2351
|
+
chunkWriter.PushVertex(v)
|
|
2352
|
+
}
|
|
2353
|
+
const numIndices = chunk.indices.size
|
|
2354
|
+
for (let i = 0; i < numIndices; i++) {
|
|
2355
|
+
chunkWriter.PushIndex(chunk.indices.Get(i))
|
|
2356
|
+
}
|
|
2357
|
+
chunkWriter.Finish()
|
|
2358
|
+
}
|
|
2359
|
+
} else {
|
|
2360
|
+
const n = batch.vertices.size
|
|
2361
|
+
for (let i = 0; i < n; i += 3) {//vitro 2 => 3
|
|
2362
|
+
const v = new Vector2(batch.vertices.Get(i), batch.vertices.Get(i + 1))
|
|
2363
|
+
if (transform) {
|
|
2364
|
+
v.applyMatrix3(transform)
|
|
2365
|
+
}
|
|
2366
|
+
this.PushVertex(v)
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
|
|
2371
|
+
_NewChunk(initialCapacity) {
|
|
2372
|
+
const chunk = new IndexedChunk(initialCapacity)
|
|
2373
|
+
this.chunks.push(chunk)
|
|
2374
|
+
return chunk
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2378
|
+
class IndexedChunk {
|
|
2379
|
+
constructor(initialCapacity) {
|
|
2380
|
+
if (initialCapacity < 16) {
|
|
2381
|
+
initialCapacity = 16
|
|
2382
|
+
}
|
|
2383
|
+
/* Average two indices per vertex. */
|
|
2384
|
+
this.indices = new DynamicBuffer(NativeType.UINT16, initialCapacity * 2)
|
|
2385
|
+
/* Two components per vertex. */
|
|
2386
|
+
this.vertices = new DynamicBuffer(NativeType.FLOAT32, initialCapacity * 2)
|
|
2387
|
+
}
|
|
2388
|
+
|
|
2389
|
+
Serialize(buffers) {
|
|
2390
|
+
const chunk = {}
|
|
2391
|
+
{
|
|
2392
|
+
const size = this.vertices.GetSize()
|
|
2393
|
+
chunk.verticesOffset = buffers.verticesOffset
|
|
2394
|
+
chunk.verticesSize = size
|
|
2395
|
+
this.vertices.CopyTo(buffers.vertices, buffers.verticesOffset)
|
|
2396
|
+
buffers.verticesOffset += size
|
|
2397
|
+
}
|
|
2398
|
+
{
|
|
2399
|
+
const size = this.indices.GetSize()
|
|
2400
|
+
chunk.indicesOffset = buffers.indicesOffset
|
|
2401
|
+
chunk.indicesSize = size
|
|
2402
|
+
this.indices.CopyTo(buffers.indices, buffers.indicesOffset)
|
|
2403
|
+
buffers.indicesOffset += size
|
|
2404
|
+
}
|
|
2405
|
+
chunk.handle = this.handle
|
|
2406
|
+
return chunk
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
|
|
2410
|
+
|
|
2411
|
+
class IndexedChunkWriter {
|
|
2412
|
+
constructor(chunk, verticesCount) {
|
|
2413
|
+
this.chunk = chunk
|
|
2414
|
+
this.verticesCount = verticesCount
|
|
2415
|
+
this.verticesOffset = this.chunk.vertices.GetSize() / 3 //vitro 2 => 3
|
|
2416
|
+
this.numVerticesPushed = 0
|
|
2417
|
+
}
|
|
2418
|
+
|
|
2419
|
+
PushVertex(v) {
|
|
2420
|
+
if (this.numVerticesPushed === this.verticesCount) {
|
|
2421
|
+
throw new Error()
|
|
2422
|
+
}
|
|
2423
|
+
this.chunk.vertices.Push(v.x)
|
|
2424
|
+
this.chunk.vertices.Push(v.y)
|
|
2425
|
+
this.chunk.vertices.Push(0)//vitro
|
|
2426
|
+
this.numVerticesPushed++
|
|
2427
|
+
}
|
|
2428
|
+
|
|
2429
|
+
PushIndex(idx) {
|
|
2430
|
+
if (idx < 0 || idx >= this.verticesCount) {
|
|
2431
|
+
throw new Error(`Index out of range: ${idx}/${this.verticesCount}`)
|
|
2432
|
+
}
|
|
2433
|
+
this.chunk.indices.Push(idx + this.verticesOffset)
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2436
|
+
Finish() {
|
|
2437
|
+
if (this.numVerticesPushed !== this.verticesCount) {
|
|
2438
|
+
throw new Error(`Not all vertices pushed: ${this.numVerticesPushed}/${this.verticesCount}`)
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
}window.initDxfViewer = function(context) {var labelDlgAddNote = 'Add Note';
|
|
2442
|
+
var labelExpand = 'Развернуть';
|
|
2443
|
+
var labelCollapse = 'Свернуть';
|
|
2444
|
+
var labelBtnDelete = 'Удалить';
|
|
2445
|
+
function initPropertySetsResizable() {
|
|
2446
|
+
$('#propInspector').resizable({
|
|
2447
|
+
handles: "w",
|
|
2448
|
+
minWidth: 150
|
|
2449
|
+
});
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
|
|
2453
|
+
function showPropertyInspector(pickResult) {
|
|
2454
|
+
// var objectId = pickResult.entity.id;
|
|
2455
|
+
// TODO - only for Test
|
|
2456
|
+
var objectId = '0K1IpmnK10iuhGzDjMLoJt';
|
|
2457
|
+
|
|
2458
|
+
var metaObject = customMeta[objectId];
|
|
2459
|
+
|
|
2460
|
+
if(metaObject) {
|
|
2461
|
+
setPropertySets(metaObject);
|
|
2462
|
+
} else {
|
|
2463
|
+
console.log('No object meta-data');
|
|
2464
|
+
return false;
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
|
|
2468
|
+
function setPropertySets(metaObject) {
|
|
2469
|
+
const html = [];
|
|
2470
|
+
var propertySets = metaObject.propertySets;
|
|
2471
|
+
|
|
2472
|
+
html.push('<div class="element-attributes">');
|
|
2473
|
+
if (!metaObject) {
|
|
2474
|
+
html.push('<p class="subsubtitle">No object selected</p>');
|
|
2475
|
+
} else {
|
|
2476
|
+
html.push('<table class="xeokit-table">');
|
|
2477
|
+
html.push('<tr><td class="td1">Name:</td><td class="td2">' + metaObject.name + '</td></tr>');
|
|
2478
|
+
if (metaObject.type) {
|
|
2479
|
+
html.push('<tr><td class="td1">Class:</td><td class="td2">' + metaObject.type + '</td></tr>');
|
|
2480
|
+
}
|
|
2481
|
+
html.push('<tr><td class="td1">UUID:</td><td class="td2">' + metaObject.id + '</td></tr>');
|
|
2482
|
+
html.push('</table>');
|
|
2483
|
+
if (!propertySets || propertySets.length === 0) {
|
|
2484
|
+
html.push('<p class="subtitle xeokit-no-prop-set-warning">No properties sets found for this object.</p>');
|
|
2485
|
+
html.push('</div>');
|
|
2486
|
+
} else {
|
|
2487
|
+
html.push('</div>');
|
|
2488
|
+
html.push('<div class="xeokit-accordion">');
|
|
2489
|
+
for (let i = 0, len = propertySets.length; i < len; i++) {
|
|
2490
|
+
const propertySet = propertySets[i];
|
|
2491
|
+
const properties = propertySet.properties || [];
|
|
2492
|
+
if (properties.length > 0) {
|
|
2493
|
+
html.push('<div class="xeokit-accordion-container">' +
|
|
2494
|
+
'<h3><span>'+ (propertySet.name ? propertySet.name : propertySet.propertySetName) + '</span></h3>' +
|
|
2495
|
+
'<div class="xeokit-accordion-panel">' +
|
|
2496
|
+
'<table class="xeokit-table"><tbody>'
|
|
2497
|
+
);
|
|
2498
|
+
for (let i = 0, len = properties.length; i < len; i++) {
|
|
2499
|
+
const property = properties[i];
|
|
2500
|
+
html.push('<tr><td class="td1">' + (property.name || property.Name || property.label) + ':</td><td class="td2">' + (property.value || property.Value) + '</td></tr>');
|
|
2501
|
+
}
|
|
2502
|
+
html.push('</tbody></table>'+
|
|
2503
|
+
'</div>'+
|
|
2504
|
+
'</div>');
|
|
2505
|
+
} else {
|
|
2506
|
+
html.push('<p class="subtitle">No properties sets found.</p>');
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
html.push('</div>');
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
$('#propInspector .prop-inspector-content')[0].innerHTML = html.join("");
|
|
2513
|
+
$('.xeokit-accordion-container').accordion({
|
|
2514
|
+
collapsible: true,
|
|
2515
|
+
heightStyle: "content"
|
|
2516
|
+
});
|
|
2517
|
+
$('#propInspector').show();
|
|
2518
|
+
|
|
2519
|
+
// Hide all right-side positioned panels
|
|
2520
|
+
$('.sidebar').hide();
|
|
2521
|
+
$('#btnToggleSidebarNotes').removeClass('toggled');
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2524
|
+
function bindPropInspectorClose() {
|
|
2525
|
+
$('.prop-inspector-close').on('click', function() {
|
|
2526
|
+
$('#propInspector').hide();
|
|
2527
|
+
})
|
|
2528
|
+
}
|
|
2529
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
2530
|
+
// Sidebar Notes
|
|
2531
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
2532
|
+
|
|
2533
|
+
function initSidebarNotes() {
|
|
2534
|
+
clearSidebarNotes();
|
|
2535
|
+
createSidebarNotes();
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2538
|
+
function clearSidebarNotes() {
|
|
2539
|
+
$('.sidebar-note-wrap').remove();
|
|
2540
|
+
}
|
|
2541
|
+
|
|
2542
|
+
function createSidebarNotes() {
|
|
2543
|
+
$.each(notes, function(index, note) {
|
|
2544
|
+
var noteElm = createSidebarNotesItem(note);
|
|
2545
|
+
$('.sidebar-content').append(noteElm);
|
|
2546
|
+
});
|
|
2547
|
+
}
|
|
2548
|
+
|
|
2549
|
+
function createSidebarNotesItem(noteData) {
|
|
2550
|
+
var noteWrap = $('<div class="sidebar-note-wrap" id="noteWrap-'+noteData.id+'" />');
|
|
2551
|
+
|
|
2552
|
+
var noteHeader = createSidebarNotesItemHeader(noteData);
|
|
2553
|
+
var noteBody = createSidebarNotesItemBody(noteData);
|
|
2554
|
+
|
|
2555
|
+
noteWrap.append(noteHeader);
|
|
2556
|
+
noteWrap.append(noteBody);
|
|
2557
|
+
|
|
2558
|
+
return noteWrap;
|
|
2559
|
+
}
|
|
2560
|
+
|
|
2561
|
+
function createSidebarNotesItemBody(noteData) {
|
|
2562
|
+
var noteContent = noteData;
|
|
2563
|
+
|
|
2564
|
+
var noteBody = $('<div class="sidebar-note-body" />');
|
|
2565
|
+
var noteTextarea = $('<textarea data-id="' + noteData.id + '"></textarea>');
|
|
2566
|
+
bindTextareaHandlers(noteTextarea);
|
|
2567
|
+
noteTextarea.val(noteContent.values.description);
|
|
2568
|
+
|
|
2569
|
+
var expandBtnWrap = $('<div class="sidebar-note-expand-wrap"/>');
|
|
2570
|
+
var expandBtnWrapInner = $('<div class="sidebar-note-expand-btn collapsed"/>');
|
|
2571
|
+
var expandBtnExpand = $('<a class="btn-expand">' + labelExpand + '</a>');
|
|
2572
|
+
var expandBtnCollapse = $('<a class="btn-collapse">'+ labelCollapse + '</a>');
|
|
2573
|
+
bindOnClickTextareaExpand(expandBtnExpand);
|
|
2574
|
+
bindOnClickTextareaCollapse(expandBtnCollapse);
|
|
2575
|
+
expandBtnWrapInner.append(expandBtnExpand);
|
|
2576
|
+
expandBtnWrapInner.append(expandBtnCollapse);
|
|
2577
|
+
|
|
2578
|
+
|
|
2579
|
+
expandBtnWrap.append(expandBtnWrapInner);
|
|
2580
|
+
noteBody.append(noteTextarea);
|
|
2581
|
+
noteBody.append(expandBtnWrap);
|
|
2582
|
+
|
|
2583
|
+
if(noteContent.values.imageSrc) {
|
|
2584
|
+
var noteImage = $('<div class="sidebar-note-img-wrap"><img src="' + noteContent.values.imageSrc + '" /><div>');
|
|
2585
|
+
noteBody.append(noteImage);
|
|
2586
|
+
}
|
|
2587
|
+
|
|
2588
|
+
return noteBody;
|
|
2589
|
+
}
|
|
2590
|
+
|
|
2591
|
+
function bindTextareaHandlers(textarea) {
|
|
2592
|
+
textarea.on('focus', function() {
|
|
2593
|
+
doTextareaOnFocus($(this));
|
|
2594
|
+
});
|
|
2595
|
+
|
|
2596
|
+
textarea.on('change', function() {
|
|
2597
|
+
doNoteOnChange($(this));
|
|
2598
|
+
});
|
|
2599
|
+
}
|
|
2600
|
+
|
|
2601
|
+
function doTextareaOnFocus(textarea) {
|
|
2602
|
+
$('.sidebar-note-wrap').removeClass('active');
|
|
2603
|
+
var wrap = textarea.closest('.sidebar-note-wrap');
|
|
2604
|
+
wrap.addClass('active');
|
|
2605
|
+
autosize(textarea);
|
|
2606
|
+
wrap.find('.sidebar-note-expand-btn').removeClass('collapsed');
|
|
2607
|
+
}
|
|
2608
|
+
|
|
2609
|
+
function doNoteOnChange(textarea) {
|
|
2610
|
+
// TODO - Ajax -> save data
|
|
2611
|
+
|
|
2612
|
+
var noteId = textarea.data('id');
|
|
2613
|
+
var noteDesc = textarea.val();
|
|
2614
|
+
var date = new Date(Date.now()).toLocaleDateString("ru-RU"); // TODO
|
|
2615
|
+
var user = ''; // TODO
|
|
2616
|
+
|
|
2617
|
+
$.each(notes, function(index, val) {
|
|
2618
|
+
if(val.id == noteId) {
|
|
2619
|
+
// notes[index]['values']['glyph'] = noteGlyph; // ?
|
|
2620
|
+
// notes[index]['values']['title'] = noteTitle; // ?
|
|
2621
|
+
// notes[index]['creator'] = user;
|
|
2622
|
+
notes[index]['values']['description'] = noteDesc;
|
|
2623
|
+
notes[index]['date'] = date;
|
|
2624
|
+
}
|
|
2625
|
+
});
|
|
2626
|
+
|
|
2627
|
+
alert('noteId=' + noteId + ' | Data changed: \r\n' + noteDesc);
|
|
2628
|
+
}
|
|
2629
|
+
|
|
2630
|
+
function bindOnClickTextareaExpand(btnElm) {
|
|
2631
|
+
btnElm.on('click', function() {
|
|
2632
|
+
doTextareaExpand(btnElm);
|
|
2633
|
+
$(this).closest('.sidebar-note-expand-btn').removeClass('collapsed');
|
|
2634
|
+
});
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2637
|
+
function doTextareaExpand(btnElm) {
|
|
2638
|
+
var textarea = btnElm.closest('.sidebar-note-body').find('textarea');
|
|
2639
|
+
autosize(textarea);
|
|
2640
|
+
}
|
|
2641
|
+
|
|
2642
|
+
function bindOnClickTextareaCollapse(btnElm) {
|
|
2643
|
+
btnElm.on('click', function() {
|
|
2644
|
+
doTextareaCollapse(btnElm);
|
|
2645
|
+
$(this).closest('.sidebar-note-expand-btn').addClass('collapsed');
|
|
2646
|
+
});
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
function doTextareaCollapse(btnElm) {
|
|
2650
|
+
var textarea = btnElm.closest('.sidebar-note-body').find('textarea');
|
|
2651
|
+
autosize.destroy(textarea);
|
|
2652
|
+
}
|
|
2653
|
+
|
|
2654
|
+
function createSidebarNotesItemHeader(noteData) {
|
|
2655
|
+
var noteContent = noteData;
|
|
2656
|
+
|
|
2657
|
+
var noteHeader = $('<div class="sidebar-note-header" />');
|
|
2658
|
+
var noteName = $('<div class="sidebar-note-name" />');
|
|
2659
|
+
noteName.html(noteContent.creator);
|
|
2660
|
+
var noteDate = $('<div class="sidebar-note-date" />');
|
|
2661
|
+
noteDate.html(noteContent.date);
|
|
2662
|
+
|
|
2663
|
+
var noteTitle = $('<div class="sidebar-note-title">' + noteData.values.glyph + ' - ' + noteData.values.title + '</div>'); // TODO
|
|
2664
|
+
noteTitle.on('click', function() {
|
|
2665
|
+
goToNoteMarker($(this));
|
|
2666
|
+
});
|
|
2667
|
+
|
|
2668
|
+
var deleteBtn = $('<a title="' + labelBtnDelete + '" class="sidebar-note-btn-delete"><span>' + labelBtnDelete + '</span></a>');
|
|
2669
|
+
deleteBtn.data('id', noteData.id);
|
|
2670
|
+
bindSidebarNotesBtnDelete(deleteBtn);
|
|
2671
|
+
|
|
2672
|
+
noteHeader.append(noteName);
|
|
2673
|
+
noteHeader.append(noteDate);
|
|
2674
|
+
noteHeader.append(noteTitle);
|
|
2675
|
+
noteHeader.append(deleteBtn);
|
|
2676
|
+
|
|
2677
|
+
return noteHeader;
|
|
2678
|
+
}
|
|
2679
|
+
|
|
2680
|
+
// TODO
|
|
2681
|
+
function goToNoteMarker(noteTitle) {
|
|
2682
|
+
var sidebarNoteWrap = noteTitle.closest('.sidebar-note-wrap');
|
|
2683
|
+
var sidebarNoteWrapId = sidebarNoteWrap.attr('id');
|
|
2684
|
+
var noteId = sidebarNoteWrapId.replace("noteWrap-", "");
|
|
2685
|
+
//console.log('noteId', noteId);
|
|
2686
|
+
|
|
2687
|
+
// TODO - go to marker
|
|
2688
|
+
// Highlight annotation object
|
|
2689
|
+
// Go to annotation...
|
|
2690
|
+
// ...
|
|
2691
|
+
alert('Go to note ' + noteId);
|
|
2692
|
+
}
|
|
2693
|
+
|
|
2694
|
+
function bindSidebarNotesBtnDelete(btn) {
|
|
2695
|
+
btn.on('click', function(e) {
|
|
2696
|
+
$(document).trigger('deleteNote', [$(this)]);
|
|
2697
|
+
});
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2700
|
+
function bindDeleteNoteEventHandler() {
|
|
2701
|
+
$(document).on('deleteNote', function(e, item) {
|
|
2702
|
+
var id = item.attr('id') ? item.attr('id') : item.data('id');
|
|
2703
|
+
|
|
2704
|
+
// TODO -> Ajax -> send data to server
|
|
2705
|
+
// ...
|
|
2706
|
+
// on success -> deleteNote
|
|
2707
|
+
|
|
2708
|
+
deleteNote(id);
|
|
2709
|
+
});
|
|
2710
|
+
}
|
|
2711
|
+
|
|
2712
|
+
// TODO
|
|
2713
|
+
function deleteNote(id) {
|
|
2714
|
+
notes = jQuery.grep(notes, function(elm, index) {
|
|
2715
|
+
return (elm.id != id);
|
|
2716
|
+
});
|
|
2717
|
+
|
|
2718
|
+
// TODO
|
|
2719
|
+
// Delete annotation
|
|
2720
|
+
// ...
|
|
2721
|
+
alert('Delete annotation ' + id);
|
|
2722
|
+
|
|
2723
|
+
|
|
2724
|
+
if($('.sidebar').is(':visible')) {
|
|
2725
|
+
initSidebarNotes();
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2728
|
+
|
|
2729
|
+
function fixNotesTextareaBlur() {
|
|
2730
|
+
$('#xeokitCanvas').on('click', function() {
|
|
2731
|
+
//console.log('click - xeokitCanvas');
|
|
2732
|
+
if($('.sidebar-content').is(':visible')) {
|
|
2733
|
+
var textareas = $('.sidebar-content').find('textarea');
|
|
2734
|
+
if(textareas.length) {
|
|
2735
|
+
textareas.trigger('blur');
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
});
|
|
2739
|
+
}
|
|
2740
|
+
|
|
2741
|
+
function highlightSidebarNote(noteId) {
|
|
2742
|
+
$('.sidebar-note-wrap').removeClass('active');
|
|
2743
|
+
var notetWrap = $('#noteWrap-' + noteId);
|
|
2744
|
+
notetWrap.addClass('active');
|
|
2745
|
+
autosize(notetWrap.find('textarea'));
|
|
2746
|
+
notetWrap.find('.sidebar-note-expand-btn').removeClass('collapsed');
|
|
2747
|
+
var sidebarContent = $('.sidebar-content');
|
|
2748
|
+
var sidebarOffsetTop = parseInt(sidebarContent[0].offsetTop);
|
|
2749
|
+
var sidebarScrollTop = parseInt(sidebarContent[0].scrollTop);
|
|
2750
|
+
sidebarContent.animate({
|
|
2751
|
+
scrollTop: notetWrap.position().top - sidebarOffsetTop + sidebarScrollTop
|
|
2752
|
+
}, 1000);
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
function showNoteDesc(noteId) {
|
|
2756
|
+
if(!$('.sidebar').is(':visible')) {
|
|
2757
|
+
$('#btnToggleSidebarNotes').addClass('toggled');
|
|
2758
|
+
initSidebarNotes();
|
|
2759
|
+
expandSidebarNotes();
|
|
2760
|
+
}
|
|
2761
|
+
highlightSidebarNote(noteId);
|
|
2762
|
+
}
|
|
2763
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
2764
|
+
// Toolbar
|
|
2765
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
2766
|
+
|
|
2767
|
+
// btnToggleNotes
|
|
2768
|
+
function bindToggleNotes() {
|
|
2769
|
+
$(document).on('click', '#btnToggleNotes', function() {
|
|
2770
|
+
$(this).toggleClass('toggled');
|
|
2771
|
+
|
|
2772
|
+
if ($(this).hasClass('toggled')) {
|
|
2773
|
+
showAnnotationMarkers();
|
|
2774
|
+
} else {
|
|
2775
|
+
hideAnnotationMarkers();
|
|
2776
|
+
}
|
|
2777
|
+
});
|
|
2778
|
+
}
|
|
2779
|
+
|
|
2780
|
+
function hideAnnotationMarkers() {
|
|
2781
|
+
$('body').addClass('hide-annotations');
|
|
2782
|
+
$('.vitro-marker-label').hide();
|
|
2783
|
+
window.dxfViewer.VisibleDrawable(DrawMode.ANNOTATIONS, false);
|
|
2784
|
+
}
|
|
2785
|
+
|
|
2786
|
+
function showAnnotationMarkers() {
|
|
2787
|
+
$('body').removeClass('hide-annotations');
|
|
2788
|
+
$('.vitro-marker-label').show()
|
|
2789
|
+
window.dxfViewer.VisibleDrawable(DrawMode.ANNOTATIONS, true);
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2792
|
+
// btnToggleSidebarNotes
|
|
2793
|
+
function bindBtnToggleSidebarNotes() {
|
|
2794
|
+
$(document).on('click', '#btnToggleSidebarNotes', function() {
|
|
2795
|
+
$(this).toggleClass('toggled');
|
|
2796
|
+
|
|
2797
|
+
if($(this).hasClass('toggled')) {
|
|
2798
|
+
if(!$('.sidebar').is(':visible')) {
|
|
2799
|
+
expandSidebarNotes();
|
|
2800
|
+
$('body').addClass('vitro-sidebar-notes-expanded');
|
|
2801
|
+
}
|
|
2802
|
+
} else {
|
|
2803
|
+
collapseSidebarNotes();
|
|
2804
|
+
}
|
|
2805
|
+
updateCanvasContainerWidth();
|
|
2806
|
+
});
|
|
2807
|
+
}
|
|
2808
|
+
|
|
2809
|
+
function expandSidebarNotes() {
|
|
2810
|
+
context.initIssueList();
|
|
2811
|
+
|
|
2812
|
+
if ($('#btnCreateNotes').hasClass('toggled')) {
|
|
2813
|
+
$('#btnCreateNotes').removeClass('toggled');
|
|
2814
|
+
removeNewAnnotations();
|
|
2815
|
+
window.dxfViewer.Cancel();
|
|
2816
|
+
}
|
|
2817
|
+
|
|
2818
|
+
collapseSidebarIssueDetail();
|
|
2819
|
+
|
|
2820
|
+
var body = $('body');
|
|
2821
|
+
var bodyScrollWidth = body[0].offsetWidth - body[0].scrollWidth;
|
|
2822
|
+
var vScrollWidth = bodyScrollWidth ? bodyScrollWidth : 0;
|
|
2823
|
+
$('.sidebar').css('right', (vScrollWidth + 'px')).show("slide", { direction: "right" }, 200);
|
|
2824
|
+
body.addClass('vitro-sidebar-notes-expanded');
|
|
2825
|
+
}
|
|
2826
|
+
|
|
2827
|
+
function bindSidebarNotesClose() {
|
|
2828
|
+
$('.sidebar-close').on('click', function() {
|
|
2829
|
+
collapseSidebarNotes();
|
|
2830
|
+
updateCanvasContainerWidth();
|
|
2831
|
+
});
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2834
|
+
// btnToggleSidebarTreeView
|
|
2835
|
+
function bindBtnToggleSidebarTreeView() {
|
|
2836
|
+
$(document).on('click', '#btnToggleSidebarTreeView', function() {
|
|
2837
|
+
$(this).toggleClass('toggled');
|
|
2838
|
+
|
|
2839
|
+
if($(this).hasClass('toggled')) {
|
|
2840
|
+
$('body').addClass('treeview-expanded');
|
|
2841
|
+
$('#treeViewContainerWrap').show();
|
|
2842
|
+
} else {
|
|
2843
|
+
$('#treeViewContainerWrap').hide();
|
|
2844
|
+
$('body').removeClass('treeview-expanded');
|
|
2845
|
+
}
|
|
2846
|
+
});
|
|
2847
|
+
}
|
|
2848
|
+
|
|
2849
|
+
// btnCreateNotes
|
|
2850
|
+
function bindBtnToggleCreateNotes() {
|
|
2851
|
+
$(document).on('click', '#btnCreateNotes', function () {
|
|
2852
|
+
$(this).toggleClass('toggled');
|
|
2853
|
+
|
|
2854
|
+
if ($(this).hasClass('toggled')) {
|
|
2855
|
+
showAnnotationMarkers();
|
|
2856
|
+
$('#btnToggleNotes').addClass('toggled');
|
|
2857
|
+
collapseSidebarNotes();
|
|
2858
|
+
anno.Create();
|
|
2859
|
+
} else {
|
|
2860
|
+
collapseSidebarIssueDetail();
|
|
2861
|
+
removeNewAnnotations();
|
|
2862
|
+
window.dxfViewer.Cancel();
|
|
2863
|
+
}
|
|
2864
|
+
updateCanvasContainerWidth();
|
|
2865
|
+
});
|
|
2866
|
+
}
|
|
2867
|
+
|
|
2868
|
+
function collapseSidebarNotes() {
|
|
2869
|
+
$('.sidebar').hide();
|
|
2870
|
+
$('body').removeClass('vitro-sidebar-notes-expanded');
|
|
2871
|
+
$('#btnToggleSidebarNotes').removeClass('toggled');
|
|
2872
|
+
}
|
|
2873
|
+
|
|
2874
|
+
function collapseSidebarIssueDetail() {
|
|
2875
|
+
$('#issueDetail').hide();
|
|
2876
|
+
$('body').removeClass('vitro-sidebar-notes-expanded');
|
|
2877
|
+
}
|
|
2878
|
+
|
|
2879
|
+
function expandSidebarIssueDetail() {
|
|
2880
|
+
$('#issueDetail').show();
|
|
2881
|
+
$('body').addClass('vitro-sidebar-notes-expanded');
|
|
2882
|
+
}
|
|
2883
|
+
|
|
2884
|
+
// btnToggleSidebarLayers
|
|
2885
|
+
function bindBtnToggleSidebarLayers() {
|
|
2886
|
+
$(document).on('click', '#btnToggleSidebarLayers', function () {
|
|
2887
|
+
$(this).toggleClass('toggled');
|
|
2888
|
+
|
|
2889
|
+
if ($(this).hasClass('toggled')) {
|
|
2890
|
+
$('body').addClass('vitro-sidebar-layers-expanded');
|
|
2891
|
+
$('#layersContainer').show();
|
|
2892
|
+
collapseSidebarSheets();
|
|
2893
|
+
} else {
|
|
2894
|
+
$('#layersContainer').hide();
|
|
2895
|
+
$('body').removeClass('vitro-sidebar-layers-expanded');
|
|
2896
|
+
}
|
|
2897
|
+
updateCanvasContainerWidth();
|
|
2898
|
+
});
|
|
2899
|
+
}
|
|
2900
|
+
|
|
2901
|
+
function collapseSidebarLayers() {
|
|
2902
|
+
$('body').removeClass('vitro-sidebar-layers-expanded');
|
|
2903
|
+
$('#layersContainer').hide();
|
|
2904
|
+
$('#btnToggleSidebarLayers').removeClass('toggled');
|
|
2905
|
+
}
|
|
2906
|
+
|
|
2907
|
+
// btnToggleSidebarSheets
|
|
2908
|
+
function bindBtnToggleSidebarSheets() {
|
|
2909
|
+
$(document).on('click', '#btnToggleSidebarSheets', function () {
|
|
2910
|
+
$(this).toggleClass('toggled');
|
|
2911
|
+
|
|
2912
|
+
if ($(this).hasClass('toggled')) {
|
|
2913
|
+
$('#sidebarContainer').show();
|
|
2914
|
+
$('body').addClass('vitro-sidebar-sheets-expanded');
|
|
2915
|
+
collapseSidebarLayers();
|
|
2916
|
+
} else {
|
|
2917
|
+
$('#sidebarContainer').hide();
|
|
2918
|
+
$('body').removeClass('vitro-sidebar-sheets-expanded');
|
|
2919
|
+
}
|
|
2920
|
+
|
|
2921
|
+
updateCanvasContainerWidth();
|
|
2922
|
+
});
|
|
2923
|
+
}
|
|
2924
|
+
|
|
2925
|
+
function collapseSidebarSheets() {
|
|
2926
|
+
$('#sidebarContainer').hide();
|
|
2927
|
+
$('body').removeClass('vitro-sidebar-sheets-expanded');
|
|
2928
|
+
$('#btnToggleSidebarSheets').removeClass('toggled');
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2931
|
+
function bindBtnZoomIn() {
|
|
2932
|
+
$(document).on('click', '#zoomIn', function () {
|
|
2933
|
+
window.dxfViewer.ZoomIn();
|
|
2934
|
+
});
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2937
|
+
function bindBtnZoomOut() {
|
|
2938
|
+
$(document).on('click', '#zoomOut', function () {
|
|
2939
|
+
window.dxfViewer.ZoomOut();
|
|
2940
|
+
});
|
|
2941
|
+
}
|
|
2942
|
+
|
|
2943
|
+
|
|
2944
|
+
// TODO
|
|
2945
|
+
function bindTreeViewSpanOnClickHandler() {
|
|
2946
|
+
$(document).on('treeViewSpan', function(e, itemId) {
|
|
2947
|
+
// TODO
|
|
2948
|
+
alert('click treeViewSpan, id = ' + itemId);
|
|
2949
|
+
var pickResult = {
|
|
2950
|
+
entity: {
|
|
2951
|
+
id: itemId
|
|
2952
|
+
}
|
|
2953
|
+
};
|
|
2954
|
+
showPropertyInspector(pickResult);
|
|
2955
|
+
});
|
|
2956
|
+
}
|
|
2957
|
+
|
|
2958
|
+
function isTreeViewItemChecked(id) {
|
|
2959
|
+
return $('#checkbox-'+id).is(':checked');
|
|
2960
|
+
}
|
|
2961
|
+
|
|
2962
|
+
// TODO
|
|
2963
|
+
function bindTreeViewCheckboxOnChangeHandler() {
|
|
2964
|
+
$(document).on('treeViewCheckboxChange', function(e, itemId) {
|
|
2965
|
+
// TODO
|
|
2966
|
+
alert('change treeViewCheckbox | id = ' + itemId + ' | checked = ' + isTreeViewItemChecked(itemId));
|
|
2967
|
+
// Get all children
|
|
2968
|
+
//console.log(getChildren(itemId));
|
|
2969
|
+
});
|
|
2970
|
+
}
|
|
2971
|
+
// Super Fast Tree View in JavaScript by Chris Smith - like Xeokit
|
|
2972
|
+
function orphans() {
|
|
2973
|
+
return treeViewData.filter(function(item) {
|
|
2974
|
+
return item.parent === null;
|
|
2975
|
+
});
|
|
2976
|
+
}
|
|
2977
|
+
|
|
2978
|
+
function hasChildren(parentId) {
|
|
2979
|
+
return treeViewData.some(function(item) {
|
|
2980
|
+
return item.parent === parentId;
|
|
2981
|
+
});
|
|
2982
|
+
}
|
|
2983
|
+
|
|
2984
|
+
function getChildren(parentId) {
|
|
2985
|
+
return treeViewData.filter(function(item) {
|
|
2986
|
+
return item.parent === parentId;
|
|
2987
|
+
});
|
|
2988
|
+
}
|
|
2989
|
+
|
|
2990
|
+
function generateListItem(item) {
|
|
2991
|
+
// console.time('generateListItem');
|
|
2992
|
+
const li = document.createElement('li');
|
|
2993
|
+
li.id = 'item-' + item.id;
|
|
2994
|
+
|
|
2995
|
+
if (hasChildren(item.id)) {
|
|
2996
|
+
const a = document.createElement('a');
|
|
2997
|
+
a.href = '#';
|
|
2998
|
+
a.textContent = '+';
|
|
2999
|
+
a.classList.add('plus');
|
|
3000
|
+
a.addEventListener('click', expand);
|
|
3001
|
+
li.appendChild(a);
|
|
3002
|
+
}
|
|
3003
|
+
|
|
3004
|
+
const checkbox = document.createElement('input');
|
|
3005
|
+
checkbox.type = 'checkbox';
|
|
3006
|
+
checkbox.id = 'checkbox-' + item.id;
|
|
3007
|
+
|
|
3008
|
+
if(item.parent === null) {
|
|
3009
|
+
$(checkbox).prop('checked', true);
|
|
3010
|
+
}
|
|
3011
|
+
|
|
3012
|
+
$(checkbox).off('change');
|
|
3013
|
+
$(checkbox).on('change', function(){
|
|
3014
|
+
var _t = $(this);
|
|
3015
|
+
var childInputs = _t.parent().find('ul').find('input[type="checkbox"]');
|
|
3016
|
+
childInputs.prop('checked', _t.is(':checked'));
|
|
3017
|
+
$(document).trigger('treeViewCheckboxChange', [item.id]);
|
|
3018
|
+
});
|
|
3019
|
+
li.appendChild(checkbox);
|
|
3020
|
+
|
|
3021
|
+
const span = document.createElement('span');
|
|
3022
|
+
span.textContent = item.name;
|
|
3023
|
+
$(span).off('click');
|
|
3024
|
+
$(span).on('click', function() {
|
|
3025
|
+
$(document).trigger('treeViewSpan', [item.id]);
|
|
3026
|
+
});
|
|
3027
|
+
li.appendChild(span);
|
|
3028
|
+
// console.timeEnd('generateListItem');
|
|
3029
|
+
return li;
|
|
3030
|
+
}
|
|
3031
|
+
|
|
3032
|
+
function expand(event) {
|
|
3033
|
+
// console.time('expand');
|
|
3034
|
+
event.preventDefault();
|
|
3035
|
+
event.stopPropagation();
|
|
3036
|
+
const et = event.target,
|
|
3037
|
+
parent = et.parentElement,
|
|
3038
|
+
id = parent.id.replace('item-', ''),
|
|
3039
|
+
kids = getChildren(id),
|
|
3040
|
+
items = kids.map(generateListItem),
|
|
3041
|
+
ul = document.createElement('ul');
|
|
3042
|
+
items.forEach(function(li) {
|
|
3043
|
+
if($('#item-'+id + ' > input[type="checkbox"]').length && !$('#item-'+id + ' > input[type="checkbox"]').is(':checked')) {
|
|
3044
|
+
$(li).find('> input[type="checkbox"]').prop('checked', false);
|
|
3045
|
+
} else {
|
|
3046
|
+
$(li).find('> input[type="checkbox"]').prop('checked', true);
|
|
3047
|
+
}
|
|
3048
|
+
ul.appendChild(li);
|
|
3049
|
+
});
|
|
3050
|
+
parent.appendChild(ul);
|
|
3051
|
+
et.classList.remove('plus');
|
|
3052
|
+
et.classList.add('minus');
|
|
3053
|
+
et.textContent = '-';
|
|
3054
|
+
et.removeEventListener('click', expand);
|
|
3055
|
+
et.addEventListener('click', collapse);
|
|
3056
|
+
// console.timeEnd('expand');
|
|
3057
|
+
}
|
|
3058
|
+
|
|
3059
|
+
function collapse(event) {
|
|
3060
|
+
console.time('collapse');
|
|
3061
|
+
event.preventDefault();
|
|
3062
|
+
event.stopPropagation();
|
|
3063
|
+
const et = event.target,
|
|
3064
|
+
parent = et.parentElement,
|
|
3065
|
+
ul = parent.querySelector('ul');
|
|
3066
|
+
parent.removeChild(ul);
|
|
3067
|
+
et.classList.remove('minus');
|
|
3068
|
+
et.classList.add('plus');
|
|
3069
|
+
et.textContent = '+';
|
|
3070
|
+
et.removeEventListener('click', collapse);
|
|
3071
|
+
et.addEventListener('click', expand);
|
|
3072
|
+
// console.timeEnd('collapse');
|
|
3073
|
+
}
|
|
3074
|
+
|
|
3075
|
+
function initTreeView(treeViewContainerSelector) {
|
|
3076
|
+
const root = document.querySelector(treeViewContainerSelector),
|
|
3077
|
+
orphansArray = orphans();
|
|
3078
|
+
if (orphansArray.length) {
|
|
3079
|
+
const items = orphansArray.map(generateListItem),
|
|
3080
|
+
ul = document.createElement('ul');
|
|
3081
|
+
items.forEach(function(li) {
|
|
3082
|
+
ul.appendChild(li);
|
|
3083
|
+
});
|
|
3084
|
+
root.appendChild(ul);
|
|
3085
|
+
}
|
|
3086
|
+
}
|
|
3087
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
3088
|
+
// TreeView Panel resizable
|
|
3089
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
3090
|
+
function initTreeViewPanelResizable() {
|
|
3091
|
+
$('#treeViewContainerWrap').resizable({
|
|
3092
|
+
handles: "e",
|
|
3093
|
+
minWidth: 150
|
|
3094
|
+
});
|
|
3095
|
+
}
|
|
3096
|
+
var canvas = document.getElementById('canvasContainer');
|
|
3097
|
+
window.dxfViewer = new Viewer(canvas, null);
|
|
3098
|
+
|
|
3099
|
+
const version = context.fileVersionList.find(x => x.id === context.versionId);
|
|
3100
|
+
const versionStr = version ? version.name : null;
|
|
3101
|
+
|
|
3102
|
+
function getFileItemId(itemId, version, callback, error) {
|
|
3103
|
+
const path = window.location.pathname;
|
|
3104
|
+
const idx = path.indexOf("/dxfViewer");
|
|
3105
|
+
const webRelativeUrl = path.substring(0, idx);
|
|
3106
|
+
|
|
3107
|
+
jQuery.ajax({
|
|
3108
|
+
type: "GET",
|
|
3109
|
+
url: webRelativeUrl +
|
|
3110
|
+
"/dxfViewer/api/Model/Get/" +
|
|
3111
|
+
itemId + "/" +
|
|
3112
|
+
version,
|
|
3113
|
+
cache: false,
|
|
3114
|
+
contentType: "application/json",
|
|
3115
|
+
error: function (jqXHR, textStatus, errorThrown) {
|
|
3116
|
+
if (error) {
|
|
3117
|
+
error();
|
|
3118
|
+
}
|
|
3119
|
+
},
|
|
3120
|
+
success: function (modelId, status, jqXHR) {
|
|
3121
|
+
if (callback) {
|
|
3122
|
+
callback(modelId);
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
});
|
|
3126
|
+
}
|
|
3127
|
+
|
|
3128
|
+
async function load(id) {
|
|
3129
|
+
const url = '/api/file/getByItemId/' + id;
|
|
3130
|
+
|
|
3131
|
+
window.dxfViewer.Load(url).then(() => {
|
|
3132
|
+
anno.RemoveLabels();
|
|
3133
|
+
anno.UpdateLabelPosition();
|
|
3134
|
+
document.getElementById(window.dxfViewer.spaceName)?.classList.add('vitro-active');
|
|
3135
|
+
bindThumbnailClick();
|
|
3136
|
+
if (context.onLoaded) {
|
|
3137
|
+
context.onLoaded();
|
|
3138
|
+
}
|
|
3139
|
+
});
|
|
3140
|
+
}
|
|
3141
|
+
|
|
3142
|
+
function onLoadError() {
|
|
3143
|
+
alert('The file is being processed');
|
|
3144
|
+
}
|
|
3145
|
+
|
|
3146
|
+
getFileItemId(context.file.id, versionStr, load, onLoadError);
|
|
3147
|
+
|
|
3148
|
+
var strokeColorVal = '#2d9cdb';
|
|
3149
|
+
|
|
3150
|
+
var anno = new Annotation({
|
|
3151
|
+
viewer: window.dxfViewer,
|
|
3152
|
+
color: strokeColorVal,
|
|
3153
|
+
onLabelClick: onSelectAnnotation
|
|
3154
|
+
});
|
|
3155
|
+
window.dxfViewer.RegisterDrawablePlugin(anno);
|
|
3156
|
+
|
|
3157
|
+
document.addEventListener('keydown', KeyDown);
|
|
3158
|
+
|
|
3159
|
+
function KeyDown(event) {
|
|
3160
|
+
const code = event.code;
|
|
3161
|
+
if (code == 'Delete') {
|
|
3162
|
+
const selectedId = window.dxfViewer.GetSelectedHandle();
|
|
3163
|
+
if (selectedId) {initi
|
|
3164
|
+
const drawable = window.dxfViewer.GetDrawable(selectedId);
|
|
3165
|
+
if (drawable?.drawMode === DrawMode.ANNOTATIONS) {
|
|
3166
|
+
window.dxfViewer.DeleteDrawable(selectedId);
|
|
3167
|
+
}
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
3171
|
+
|
|
3172
|
+
const Subscribe = eventName => {
|
|
3173
|
+
window.dxfViewer.Subscribe(eventName, e => emit('dxf-' + eventName, e));
|
|
3174
|
+
};
|
|
3175
|
+
for (const eventName of ['loaded', 'cleared', 'destroyed', 'resized', 'pointerdown',
|
|
3176
|
+
'pointerup', 'viewChanged', 'message', 'added', 'selected', 'drawableCreated', 'drawCancelled']) {
|
|
3177
|
+
Subscribe(eventName);
|
|
3178
|
+
}
|
|
3179
|
+
|
|
3180
|
+
function emit(eventName, event) {
|
|
3181
|
+
if (eventName == 'dxf-pointerdown' && event.detail.domEvent.button == 1) {
|
|
3182
|
+
var layout = null;
|
|
3183
|
+
const viewer = window.dxfViewer;
|
|
3184
|
+
const scene = viewer.scene;
|
|
3185
|
+
for (let i = 0; i < scene.layouts.length; i++) {
|
|
3186
|
+
if (window.dxfViewer.spaceName === scene.layouts[i].space) {
|
|
3187
|
+
if (i == scene.layouts.length - 1)
|
|
3188
|
+
layout = scene.layouts[0];
|
|
3189
|
+
else
|
|
3190
|
+
layout = scene.layouts[i + 1];
|
|
3191
|
+
|
|
3192
|
+
break;
|
|
3193
|
+
}
|
|
3194
|
+
}
|
|
3195
|
+
|
|
3196
|
+
if (layout) {
|
|
3197
|
+
window.dxfViewer.SwitchSpace(layout);
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
3200
|
+
else if (eventName == 'dxf-pointerdown' && event.detail.domEvent.button == 0) {
|
|
3201
|
+
if (!window.dxfViewer.drawMode) {
|
|
3202
|
+
const selectedId = window.dxfViewer.SelectObj(event);
|
|
3203
|
+
}
|
|
3204
|
+
}
|
|
3205
|
+
else if (eventName == 'dxf-selected') {
|
|
3206
|
+
const selectedId = window.dxfViewer.GetSelectedHandle();
|
|
3207
|
+
const annotation = window.dxfViewer.GetDrawable(selectedId);
|
|
3208
|
+
if (annotation && annotation.space.layout.space === dxfViewer.spaceName) {
|
|
3209
|
+
onSelectAnnotation(selectedId);
|
|
3210
|
+
}
|
|
3211
|
+
}
|
|
3212
|
+
else if (eventName == 'dxf-loaded') {
|
|
3213
|
+
const spaceHandle = event.detail.space.layout.spaceHandle;
|
|
3214
|
+
createThumbnail(event.detail.space.layout.name, window.dxfViewer.GetSpace());
|
|
3215
|
+
initNotesBySpaceHandle(spaceHandle);
|
|
3216
|
+
initLayers();
|
|
3217
|
+
window.dxfViewer.controls.minZoom = 0.1;
|
|
3218
|
+
window.dxfViewer.controls.maxZoom = 10;
|
|
3219
|
+
}
|
|
3220
|
+
else if (eventName == 'dxf-drawableCreated') {
|
|
3221
|
+
const markupData = event.detail;
|
|
3222
|
+
if (markupData && markupData.id && markupData.id.includes(ID_PREFIX)) {
|
|
3223
|
+
context.onCreateIssue(markupData);
|
|
3224
|
+
expandSidebarIssueDetail();
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
else if (eventName == 'dxf-drawCancelled') {
|
|
3228
|
+
|
|
3229
|
+
}
|
|
3230
|
+
else if (eventName == 'dxf-resized') {
|
|
3231
|
+
anno.UpdateLabelRendererSize();
|
|
3232
|
+
anno.UpdateLabelPosition();
|
|
3233
|
+
if ($('#scaleSelect').data('value') === 'auto') {
|
|
3234
|
+
doZoomAuto();
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
else if (eventName == 'dxf-viewChanged') {
|
|
3238
|
+
if (+$('#scaleSelect').data('value') && dxfViewer.camera.zoom !== 1) {
|
|
3239
|
+
updateScaleSelectValue();
|
|
3240
|
+
}
|
|
3241
|
+
anno.UpdateLabelPosition();
|
|
3242
|
+
}
|
|
3243
|
+
|
|
3244
|
+
}
|
|
3245
|
+
|
|
3246
|
+
function destroyed() {
|
|
3247
|
+
window.dxfViewer.Destroy();
|
|
3248
|
+
window.dxfViewer = null;
|
|
3249
|
+
}
|
|
3250
|
+
|
|
3251
|
+
function initNotesBySpaceHandle(spaceHandle) {
|
|
3252
|
+
$.each(context.issueList, function (index, note) {
|
|
3253
|
+
initNote(note, spaceHandle);
|
|
3254
|
+
});
|
|
3255
|
+
|
|
3256
|
+
anno.UpdateLabelPosition();
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3259
|
+
function initLayers() {
|
|
3260
|
+
if (context.initLayers) {
|
|
3261
|
+
context.initLayers(window.dxfViewer.scene.layers);
|
|
3262
|
+
}
|
|
3263
|
+
}
|
|
3264
|
+
|
|
3265
|
+
function initNote(note, spaceHandle) {
|
|
3266
|
+
const markup = JSON.parse(note.markup);
|
|
3267
|
+
if (markup.space.layout.spaceHandle === spaceHandle) {
|
|
3268
|
+
const firstPoint = new three.Vector3(markup.firstPoint.x, markup.firstPoint.y, markup.firstPoint.z);
|
|
3269
|
+
const secondPoint = new three.Vector3(markup.secondPoint.x, markup.secondPoint.y, markup.secondPoint.z);
|
|
3270
|
+
const color = note.statusColor || strokeColorVal;
|
|
3271
|
+
const id = note.id.toString();
|
|
3272
|
+
anno.Add(spaceHandle, firstPoint, secondPoint, id, color);
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
|
|
3276
|
+
function bindUpdatePage() {
|
|
3277
|
+
if (context.deleteIssueEvent) {
|
|
3278
|
+
window.addEventListener(context.deleteIssueEvent, updatePage);
|
|
3279
|
+
}
|
|
3280
|
+
|
|
3281
|
+
if (context.updateIssueEvent) {
|
|
3282
|
+
window.addEventListener(context.updateIssueEvent, updatePage);
|
|
3283
|
+
}
|
|
3284
|
+
}
|
|
3285
|
+
|
|
3286
|
+
function updatePage(e) {
|
|
3287
|
+
const item = e.detail.itemList[0];
|
|
3288
|
+
const markup = item.fieldValueMap.markup;
|
|
3289
|
+
context.initIssueList(true);
|
|
3290
|
+
anno.RemoveLabels();
|
|
3291
|
+
removeNewAnnotations();
|
|
3292
|
+
|
|
3293
|
+
if (e.type === context.deleteIssueEvent && markup) {
|
|
3294
|
+
const selectedId = item.fieldValueMap.item_id;
|
|
3295
|
+
deleteNote(selectedId);
|
|
3296
|
+
}
|
|
3297
|
+
|
|
3298
|
+
if (e.type === context.updateIssueEvent && markup) {
|
|
3299
|
+
const newNote = {
|
|
3300
|
+
id: item.fieldValueMap.item_id,
|
|
3301
|
+
markup: markup,
|
|
3302
|
+
statusColor: item.fieldValueMap['task_status']?.fieldValueMap?.color || '',
|
|
3303
|
+
}
|
|
3304
|
+
const spaceHandle = getCurrentSpaceHandle();
|
|
3305
|
+
if (spaceHandle) {
|
|
3306
|
+
deleteNote(newNote.id);
|
|
3307
|
+
initNote(newNote, spaceHandle);
|
|
3308
|
+
}
|
|
3309
|
+
|
|
3310
|
+
if ($('#btnCreateNotes').hasClass('toggled')) {
|
|
3311
|
+
anno.Create();
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
|
|
3315
|
+
anno.UpdateLabelPosition();
|
|
3316
|
+
}
|
|
3317
|
+
|
|
3318
|
+
function removeNewAnnotations() {
|
|
3319
|
+
const drawables = window.dxfViewer.drawables;
|
|
3320
|
+
const newAnnotations = drawables.filter(drawable => drawable.drawMode === DrawMode.ANNOTATIONS && drawable.id.includes(ID_PREFIX));
|
|
3321
|
+
if (newAnnotations && newAnnotations.length) {
|
|
3322
|
+
$.each(newAnnotations, function (index, anno) {
|
|
3323
|
+
window.dxfViewer.DeleteDrawable(anno.id);
|
|
3324
|
+
})
|
|
3325
|
+
}
|
|
3326
|
+
}
|
|
3327
|
+
|
|
3328
|
+
function deleteNote(id) {
|
|
3329
|
+
if (id) {
|
|
3330
|
+
const drawable = window.dxfViewer.GetDrawable(id);
|
|
3331
|
+
if (drawable?.drawMode === DrawMode.ANNOTATIONS) {//this is annotation
|
|
3332
|
+
window.dxfViewer.DeleteDrawable(id);
|
|
3333
|
+
}
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
|
|
3337
|
+
function getCurrentSpaceHandle() {
|
|
3338
|
+
const spaces = window.dxfViewer.spaces;
|
|
3339
|
+
const currentSpaceName = window.dxfViewer.spaceName;
|
|
3340
|
+
const currentSpace = spaces.get(currentSpaceName);
|
|
3341
|
+
if (currentSpace) {
|
|
3342
|
+
return currentSpace.layout.spaceHandle;
|
|
3343
|
+
}
|
|
3344
|
+
|
|
3345
|
+
return null;
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3348
|
+
function onSelectAnnotation(id) {
|
|
3349
|
+
if (context.selectIssue) {
|
|
3350
|
+
context.selectIssue(id, true);
|
|
3351
|
+
}
|
|
3352
|
+
zoomToAnnotation(id);
|
|
3353
|
+
|
|
3354
|
+
if (!$('#btnToggleSidebarNotes').hasClass('toggled')) {
|
|
3355
|
+
$('#btnToggleSidebarNotes').addClass('toggled');
|
|
3356
|
+
expandSidebarNotes();
|
|
3357
|
+
}
|
|
3358
|
+
updateCanvasContainerWidth();
|
|
3359
|
+
}
|
|
3360
|
+
|
|
3361
|
+
function zoomToAnnotation(id) {
|
|
3362
|
+
const drawable = window.dxfViewer.GetDrawable(id);
|
|
3363
|
+
if (drawable?.drawMode === DrawMode.ANNOTATIONS && drawable.space.layout.space === window.dxfViewer.spaceName) {
|
|
3364
|
+
window.dxfViewer.ZoomTo(drawable.objects);
|
|
3365
|
+
updateScaleSelectValue();
|
|
3366
|
+
} else {
|
|
3367
|
+
window.dxfViewer.FindDxfEntity(id);
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
|
|
3371
|
+
function switchSpace(space) {
|
|
3372
|
+
const layout = window.dxfViewer.scene.layouts.find(layout => layout.space === space);
|
|
3373
|
+
|
|
3374
|
+
if (layout) {
|
|
3375
|
+
window.dxfViewer.SwitchSpace(layout);
|
|
3376
|
+
dxfViewer.ZoomTo(dxfViewer.GetSpace(dxfViewer.spaceName).scene);
|
|
3377
|
+
dxfViewer.DoFakeZoomToRedrawScene();
|
|
3378
|
+
anno.RemoveLabels();
|
|
3379
|
+
anno.UpdateLabelPosition();
|
|
3380
|
+
}
|
|
3381
|
+
}
|
|
3382
|
+
|
|
3383
|
+
function createThumbnail(name, space) {
|
|
3384
|
+
if (context.initThumbnail) {
|
|
3385
|
+
const imgUrl = window.dxfViewer.renderer.domElement.toDataURL();
|
|
3386
|
+
context.initThumbnail(space.layout.space, name, imgUrl);
|
|
3387
|
+
}
|
|
3388
|
+
}
|
|
3389
|
+
|
|
3390
|
+
function bindThumbnailClick() {
|
|
3391
|
+
$('.vitro-thumbnail').on('click', function () {
|
|
3392
|
+
switchSpace($(this).attr('id'));
|
|
3393
|
+
$('.vitro-thumbnail').removeClass('vitro-active');
|
|
3394
|
+
$(this).addClass('vitro-active');
|
|
3395
|
+
});
|
|
3396
|
+
}
|
|
3397
|
+
|
|
3398
|
+
function getSpaceImage(space, renderer) {
|
|
3399
|
+
const dataURL = window.dxfViewer.renderer.domElement.toDataURL();
|
|
3400
|
+
|
|
3401
|
+
const img = document.createElement('img');
|
|
3402
|
+
img.src = dataURL;
|
|
3403
|
+
|
|
3404
|
+
return img;
|
|
3405
|
+
}
|
|
3406
|
+
|
|
3407
|
+
function onChangeLayerVisibility(name, show) {
|
|
3408
|
+
window.dxfViewer.ShowLayer(name, show);
|
|
3409
|
+
}
|
|
3410
|
+
|
|
3411
|
+
function bindSelect(select) {
|
|
3412
|
+
$(select).click(function (e) {
|
|
3413
|
+
let input = $(select).children()[0];
|
|
3414
|
+
if (e.target.localName == 'li') {
|
|
3415
|
+
let value = $(e.target).attr('value');
|
|
3416
|
+
let text = $(e.target).text();
|
|
3417
|
+
$(input).val(text);
|
|
3418
|
+
$(input).data('value', value);
|
|
3419
|
+
input.dispatchEvent(new CustomEvent('change', { detail: { value: value } }));
|
|
3420
|
+
$(select).removeClass('vitro-active');
|
|
3421
|
+
}
|
|
3422
|
+
else if (e.currentTarget == select && !$(select).hasClass('vitro-active')) {
|
|
3423
|
+
$(select).addClass('vitro-active');
|
|
3424
|
+
} else {
|
|
3425
|
+
$(select).removeClass('vitro-active');
|
|
3426
|
+
}
|
|
3427
|
+
});
|
|
3428
|
+
|
|
3429
|
+
$(document).click(function (e) {
|
|
3430
|
+
if (!Array.from($(select).children()).includes(e.target)) {
|
|
3431
|
+
$(select).removeClass('vitro-active');
|
|
3432
|
+
}
|
|
3433
|
+
});
|
|
3434
|
+
}
|
|
3435
|
+
|
|
3436
|
+
function bindSelectList() {
|
|
3437
|
+
$('.vitro-select').each(function (i, item) {
|
|
3438
|
+
bindSelect(item);
|
|
3439
|
+
});
|
|
3440
|
+
}
|
|
3441
|
+
|
|
3442
|
+
function bindScaleSelectChange() {
|
|
3443
|
+
$('#pageAutoOption').text(context.scaleAutoLabel);
|
|
3444
|
+
$('#scaleSelect').data('value', $('#scaleSelect').val());
|
|
3445
|
+
$('#scaleSelect').val(context.scaleAutoLabel);
|
|
3446
|
+
$('#scaleSelect').on('change', function (e) {
|
|
3447
|
+
const scale = e.detail.value;
|
|
3448
|
+
changeZoom(scale);
|
|
3449
|
+
});
|
|
3450
|
+
}
|
|
3451
|
+
|
|
3452
|
+
function doZoomPageFit() {
|
|
3453
|
+
const space = dxfViewer.GetSpace(dxfViewer.spaceName);
|
|
3454
|
+
if (space) {
|
|
3455
|
+
dxfViewer.ZoomTo(space.scene);
|
|
3456
|
+
}
|
|
3457
|
+
}
|
|
3458
|
+
|
|
3459
|
+
function doZoomAuto() {
|
|
3460
|
+
doZoomPageFit();
|
|
3461
|
+
window.dxfViewer.DoFakeZoomToRedrawScene();
|
|
3462
|
+
}
|
|
3463
|
+
|
|
3464
|
+
function changeZoom(scale) {
|
|
3465
|
+
if (scale === 'auto') {
|
|
3466
|
+
doZoomAuto();
|
|
3467
|
+
} else {
|
|
3468
|
+
scale = +scale;
|
|
3469
|
+
if (scale === 1) {
|
|
3470
|
+
doZoomPageFit();
|
|
3471
|
+
} else {
|
|
3472
|
+
doZoomPageFit();
|
|
3473
|
+
window.dxfViewer.ZoomOut(scale);
|
|
3474
|
+
}
|
|
3475
|
+
}
|
|
3476
|
+
}
|
|
3477
|
+
|
|
3478
|
+
function updateScaleSelectValue() {
|
|
3479
|
+
const cameraZoom = window.dxfViewer.camera.zoom;
|
|
3480
|
+
const cameraZoomVal = Math.round(cameraZoom * 100);
|
|
3481
|
+
const newVal = cameraZoomVal + '%';
|
|
3482
|
+
if ($('#scaleSelect').val() !== newVal) {
|
|
3483
|
+
$('#scaleSelect').val(newVal);
|
|
3484
|
+
$('#scaleSelect').data('value', cameraZoom);
|
|
3485
|
+
}
|
|
3486
|
+
}
|
|
3487
|
+
|
|
3488
|
+
context.zoomToAnnotation = zoomToAnnotation;
|
|
3489
|
+
context.onChangeLayerVisibility = onChangeLayerVisibility;
|
|
3490
|
+
context.expandSidebarIssueDetail = () => {
|
|
3491
|
+
expandSidebarIssueDetail();
|
|
3492
|
+
collapseSidebarNotes();
|
|
3493
|
+
};
|
|
3494
|
+
|
|
3495
|
+
function bindPanelResize() {
|
|
3496
|
+
bindResizerMousedown();
|
|
3497
|
+
bindResizerMouseup();
|
|
3498
|
+
bindResizerMousemove();
|
|
3499
|
+
}
|
|
3500
|
+
|
|
3501
|
+
function bindResizerMousedown() {
|
|
3502
|
+
$('.vitro-resizer').on('mousedown', function (e) {
|
|
3503
|
+
e.preventDefault();
|
|
3504
|
+
e.stopPropagation();
|
|
3505
|
+
$(this).addClass('vitro-draggable');
|
|
3506
|
+
});
|
|
3507
|
+
}
|
|
3508
|
+
|
|
3509
|
+
function bindResizerMouseup() {
|
|
3510
|
+
$(document).on('mouseup', function (e) {
|
|
3511
|
+
e.preventDefault();
|
|
3512
|
+
e.stopPropagation();
|
|
3513
|
+
$('.vitro-resizer').removeClass('vitro-draggable');
|
|
3514
|
+
});
|
|
3515
|
+
}
|
|
3516
|
+
|
|
3517
|
+
function bindResizerMousemove() {
|
|
3518
|
+
$(document).on('mousemove', function (e) {
|
|
3519
|
+
if ($('.vitro-draggable').length) {
|
|
3520
|
+
e.preventDefault();
|
|
3521
|
+
e.stopPropagation();
|
|
3522
|
+
if ($('.vitro-draggable').hasClass('vitro-left')) {
|
|
3523
|
+
$('.vitro-draggable').parent().width($(document).width() - e.clientX);
|
|
3524
|
+
} else {
|
|
3525
|
+
$('.vitro-draggable').parent().width(e.clientX);
|
|
3526
|
+
}
|
|
3527
|
+
updateCanvasContainerWidth();
|
|
3528
|
+
}
|
|
3529
|
+
});
|
|
3530
|
+
}
|
|
3531
|
+
|
|
3532
|
+
function updateCanvasContainerWidth() {
|
|
3533
|
+
let insetStart = 0;
|
|
3534
|
+
let insetEnd = 0;
|
|
3535
|
+
$('.vitro-panel').each((idx, panel) => {
|
|
3536
|
+
const rect = panel.getBoundingClientRect();
|
|
3537
|
+
if (rect.left === 0) {
|
|
3538
|
+
insetStart += panel.clientWidth;
|
|
3539
|
+
} else if (rect.right) {
|
|
3540
|
+
insetEnd += panel.clientWidth;
|
|
3541
|
+
}
|
|
3542
|
+
});
|
|
3543
|
+
$('#canvasContainer').css('width', `calc(100% - ${insetStart + insetEnd}px)`);
|
|
3544
|
+
$('#canvasContainer').css('inset-inline-start', `${insetStart}px`);
|
|
3545
|
+
$('#canvasContainer').css('inset-inline-end', `${insetEnd}px`);
|
|
3546
|
+
}
|
|
3547
|
+
$(document).ready(function () {
|
|
3548
|
+
bindBtnToggleSidebarNotes();
|
|
3549
|
+
bindSidebarNotesClose();
|
|
3550
|
+
bindDeleteNoteEventHandler();
|
|
3551
|
+
|
|
3552
|
+
fixNotesTextareaBlur();
|
|
3553
|
+
|
|
3554
|
+
bindToggleNotes();
|
|
3555
|
+
|
|
3556
|
+
bindPropInspectorClose();
|
|
3557
|
+
initPropertySetsResizable();
|
|
3558
|
+
|
|
3559
|
+
bindBtnToggleCreateNotes();
|
|
3560
|
+
bindUpdatePage();
|
|
3561
|
+
bindBtnToggleSidebarLayers();
|
|
3562
|
+
bindBtnToggleSidebarSheets();
|
|
3563
|
+
|
|
3564
|
+
bindBtnZoomIn();
|
|
3565
|
+
bindBtnZoomOut();
|
|
3566
|
+
|
|
3567
|
+
bindSelectList();
|
|
3568
|
+
bindScaleSelectChange();
|
|
3569
|
+
bindPanelResize();
|
|
3570
|
+
});
|
|
3571
|
+
|
|
3572
|
+
var userLocale =
|
|
3573
|
+
navigator.languages && navigator.languages.length
|
|
3574
|
+
? navigator.languages[0]
|
|
3575
|
+
: navigator.language;
|
|
3576
|
+
|
|
3577
|
+
document.webL10n.setLanguage(userLocale, function () {
|
|
3578
|
+
document.webL10n.translate();
|
|
3579
|
+
});
|
|
3580
|
+
}
|