@mlightcad/cad-simple-viewer 1.7.6 → 1.7.7-preview.0

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.
Files changed (110) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +190 -190
  3. package/dist/cad-simple-viewer.js +5892 -5754
  4. package/dist/cad-simple-viewer.umd.cjs +114 -114
  5. package/dist/mtext-renderer-worker.js +14124 -8730
  6. package/find.ts +7 -7
  7. package/icons.ts +7 -7
  8. package/lib/app/AcApDocManager.d.ts.map +1 -1
  9. package/lib/app/AcApDocManager.js +56 -66
  10. package/lib/app/AcApDocManager.js.map +1 -1
  11. package/lib/app/AcApOpenDatabaseOptions.d.ts +8 -2
  12. package/lib/app/AcApOpenDatabaseOptions.d.ts.map +1 -1
  13. package/lib/command/convert/AcApEntityPreviewCmd.d.ts.map +1 -1
  14. package/lib/command/convert/AcApEntityPreviewCmd.js +1 -0
  15. package/lib/command/convert/AcApEntityPreviewCmd.js.map +1 -1
  16. package/lib/command/convert/AcApRasterImageConvertor.d.ts +17 -8
  17. package/lib/command/convert/AcApRasterImageConvertor.d.ts.map +1 -1
  18. package/lib/command/convert/AcApRasterImageConvertor.js +50 -12
  19. package/lib/command/convert/AcApRasterImageConvertor.js.map +1 -1
  20. package/lib/command/draw/AcApHatchCmd.d.ts.map +1 -1
  21. package/lib/command/draw/AcApHatchCmd.js +1 -0
  22. package/lib/command/draw/AcApHatchCmd.js.map +1 -1
  23. package/lib/command/layer/AcApLayerIsoCmd.d.ts.map +1 -1
  24. package/lib/command/layer/AcApLayerIsoCmd.js +1 -0
  25. package/lib/command/layer/AcApLayerIsoCmd.js.map +1 -1
  26. package/lib/editor/grip/AcEdGripEditSession.d.ts.map +1 -1
  27. package/lib/editor/grip/AcEdGripEditSession.js +6 -1
  28. package/lib/editor/grip/AcEdGripEditSession.js.map +1 -1
  29. package/lib/editor/grip/AcEdGripManager.d.ts.map +1 -1
  30. package/lib/editor/grip/AcEdGripManager.js +2 -1
  31. package/lib/editor/grip/AcEdGripManager.js.map +1 -1
  32. package/lib/editor/input/prompt/AcEdPromptSelectionOptions.d.ts +8 -0
  33. package/lib/editor/input/prompt/AcEdPromptSelectionOptions.d.ts.map +1 -1
  34. package/lib/editor/input/prompt/AcEdPromptSelectionOptions.js +16 -0
  35. package/lib/editor/input/prompt/AcEdPromptSelectionOptions.js.map +1 -1
  36. package/lib/editor/input/ui/AcEdInputManager.d.ts.map +1 -1
  37. package/lib/editor/input/ui/AcEdInputManager.js +6 -6
  38. package/lib/editor/input/ui/AcEdInputManager.js.map +1 -1
  39. package/lib/editor/view/AcEdBaseView.d.ts +16 -0
  40. package/lib/editor/view/AcEdBaseView.d.ts.map +1 -1
  41. package/lib/editor/view/AcEdBaseView.js +38 -0
  42. package/lib/editor/view/AcEdBaseView.js.map +1 -1
  43. package/lib/i18n/ar/main.d.ts +1 -0
  44. package/lib/i18n/ar/main.d.ts.map +1 -1
  45. package/lib/i18n/ar/main.js +1 -0
  46. package/lib/i18n/ar/main.js.map +1 -1
  47. package/lib/i18n/cs/main.d.ts +1 -0
  48. package/lib/i18n/cs/main.d.ts.map +1 -1
  49. package/lib/i18n/cs/main.js +1 -0
  50. package/lib/i18n/cs/main.js.map +1 -1
  51. package/lib/i18n/en/main.d.ts +1 -0
  52. package/lib/i18n/en/main.d.ts.map +1 -1
  53. package/lib/i18n/en/main.js +1 -0
  54. package/lib/i18n/en/main.js.map +1 -1
  55. package/lib/i18n/tr/main.d.ts +1 -0
  56. package/lib/i18n/tr/main.d.ts.map +1 -1
  57. package/lib/i18n/tr/main.js +1 -0
  58. package/lib/i18n/tr/main.js.map +1 -1
  59. package/lib/i18n/zh/main.d.ts +1 -0
  60. package/lib/i18n/zh/main.d.ts.map +1 -1
  61. package/lib/i18n/zh/main.js +1 -0
  62. package/lib/i18n/zh/main.js.map +1 -1
  63. package/lib/service/AcApEntitySelection.d.ts.map +1 -1
  64. package/lib/service/AcApEntitySelection.js +34 -4
  65. package/lib/service/AcApEntitySelection.js.map +1 -1
  66. package/lib/service/AcApEntityService.d.ts.map +1 -1
  67. package/lib/service/AcApEntityService.js +11 -0
  68. package/lib/service/AcApEntityService.js.map +1 -1
  69. package/lib/service/AcApLayerService.d.ts +8 -1
  70. package/lib/service/AcApLayerService.d.ts.map +1 -1
  71. package/lib/service/AcApLayerService.js +10 -0
  72. package/lib/service/AcApLayerService.js.map +1 -1
  73. package/lib/service/AcApLockedLayer.d.ts +23 -0
  74. package/lib/service/AcApLockedLayer.d.ts.map +1 -0
  75. package/lib/service/AcApLockedLayer.js +94 -0
  76. package/lib/service/AcApLockedLayer.js.map +1 -0
  77. package/lib/service/index.d.ts +1 -0
  78. package/lib/service/index.d.ts.map +1 -1
  79. package/lib/service/index.js +1 -0
  80. package/lib/service/index.js.map +1 -1
  81. package/lib/ui/icons.d.ts +5 -2
  82. package/lib/ui/icons.d.ts.map +1 -1
  83. package/lib/ui/icons.js +5 -2
  84. package/lib/ui/icons.js.map +1 -1
  85. package/lib/util/AcApLayoutViewFraming.d.ts +68 -0
  86. package/lib/util/AcApLayoutViewFraming.d.ts.map +1 -0
  87. package/lib/util/AcApLayoutViewFraming.js +146 -0
  88. package/lib/util/AcApLayoutViewFraming.js.map +1 -0
  89. package/lib/util/index.d.ts +1 -0
  90. package/lib/util/index.d.ts.map +1 -1
  91. package/lib/util/index.js +1 -0
  92. package/lib/util/index.js.map +1 -1
  93. package/lib/view/AcTrDirectBatch.d.ts +4 -14
  94. package/lib/view/AcTrDirectBatch.d.ts.map +1 -1
  95. package/lib/view/AcTrDirectBatch.js +4 -120
  96. package/lib/view/AcTrDirectBatch.js.map +1 -1
  97. package/lib/view/AcTrScene.d.ts +1 -1
  98. package/lib/view/AcTrScene.d.ts.map +1 -1
  99. package/lib/view/AcTrView2d.d.ts +32 -36
  100. package/lib/view/AcTrView2d.d.ts.map +1 -1
  101. package/lib/view/AcTrView2d.js +82 -65
  102. package/lib/view/AcTrView2d.js.map +1 -1
  103. package/lib/view/AcTrViewSessionState.d.ts +7 -0
  104. package/lib/view/AcTrViewSessionState.d.ts.map +1 -1
  105. package/package.json +11 -11
  106. package/src/find/AcApFindNavigator.ts +190 -190
  107. package/src/find/findDrawing.ts +211 -211
  108. package/src/find/findText.ts +624 -624
  109. package/src/find/index.ts +2 -2
  110. package/src/ui/icons.ts +411 -408
@@ -1,211 +1,211 @@
1
- /**
2
- * Whole-drawing text search (FIND across layouts).
3
- *
4
- * Builds on {@link acapFindTextInLayout}: every layout of the drawing (model
5
- * space and each paper space, in tab order) is searched with the same rules,
6
- * and every hit is tagged with the layout it lives in so a UI can show it and
7
- * navigate there.
8
- *
9
- * Pure TypeScript with no runtime imports (structural database shape), shared
10
- * by cad-simple-ui-plugin and the Vue cad-viewer.
11
- */
12
- import {
13
- ACAP_FIND_MAX_RESULTS,
14
- type AcApFindDatabaseLike,
15
- type AcApFindHit,
16
- type AcApFindOptions,
17
- acapFindTextInLayout
18
- } from './findText'
19
-
20
- /**
21
- * Where to search.
22
- *
23
- * - `drawing` (default): every layout of the drawing
24
- * - `layout`: only the layout that is currently active in the view
25
- */
26
- export type AcApFindScope = 'drawing' | 'layout'
27
-
28
- /** One layout of the drawing (model space or paper space). */
29
- export interface AcApFindLayoutInfo {
30
- /** Layout name as shown on the layout tab (e.g. `Model`, `Layout1`). */
31
- name: string
32
- /** Block table record id of the layout. */
33
- btrId: string
34
- /** Tab order; layouts are searched and listed in this order. */
35
- tabOrder: number
36
- }
37
-
38
- /** A hit that also identifies the layout that contains it. */
39
- export interface AcApFindLayoutHit extends AcApFindHit {
40
- /** Block table record id of the layout containing the hit. */
41
- layoutId: string
42
- /** Name of the layout containing the hit. */
43
- layoutName: string
44
- }
45
-
46
- /** Result of one drawing-level search. */
47
- export interface AcApFindDrawingResult {
48
- hits: AcApFindLayoutHit[]
49
- /** True when more than `maxResults` entities matched. */
50
- truncated: boolean
51
- }
52
-
53
- /** Options for {@link acapFindText}. */
54
- export interface AcApFindDrawingOptions extends AcApFindOptions {
55
- /** Search scope; defaults to `drawing`. */
56
- scope?: AcApFindScope
57
- /**
58
- * Block table record id of the layout currently shown. Required for the
59
- * `layout` scope; also used as the only layout when the drawing exposes no
60
- * layout objects.
61
- */
62
- currentLayoutId: string
63
- }
64
-
65
- interface LayoutLike {
66
- layoutName?: string
67
- tabOrder?: number
68
- blockTableRecordId?: string
69
- }
70
-
71
- /** Database shape used to enumerate layouts. */
72
- export interface AcApFindLayoutsDatabaseLike {
73
- objects?: {
74
- layout?: { newIterator?(): Iterable<LayoutLike> }
75
- }
76
- }
77
-
78
- /**
79
- * Lists the layouts of a drawing sorted by tab order (model space first in
80
- * practice). Returns an empty list when the drawing has no layout objects.
81
- */
82
- export function acapListFindLayouts(
83
- db: AcApFindLayoutsDatabaseLike
84
- ): AcApFindLayoutInfo[] {
85
- const table = db.objects?.layout
86
- if (!table?.newIterator) return []
87
- const layouts: AcApFindLayoutInfo[] = []
88
- for (const layout of table.newIterator()) {
89
- if (!layout.blockTableRecordId) continue
90
- layouts.push({
91
- name: layout.layoutName ?? '',
92
- btrId: layout.blockTableRecordId,
93
- tabOrder: Number(layout.tabOrder) || 0
94
- })
95
- }
96
- return layouts.sort(
97
- (a, b) => a.tabOrder - b.tabOrder || a.name.localeCompare(b.name)
98
- )
99
- }
100
-
101
- /**
102
- * Finds text in the whole drawing or in the current layout only.
103
- *
104
- * Layouts are visited in tab order and the result cap is shared, so
105
- * `truncated` is true as soon as any match beyond `maxResults` exists in any
106
- * searched layout. Search runs on the database, not on the rendered scene, so
107
- * layouts that were never opened in the view are searched too.
108
- */
109
- export function acapFindText(
110
- db: AcApFindDatabaseLike & AcApFindLayoutsDatabaseLike,
111
- query: string,
112
- options: AcApFindDrawingOptions
113
- ): AcApFindDrawingResult {
114
- const max = options.maxResults ?? ACAP_FIND_MAX_RESULTS
115
- const known = acapListFindLayouts(db)
116
- const nameOf = (btrId: string) =>
117
- known.find(layout => layout.btrId === btrId)?.name ?? ''
118
-
119
- let targets: Array<{ btrId: string; name: string }>
120
- if (options.scope === 'layout' || known.length === 0) {
121
- targets = [
122
- { btrId: options.currentLayoutId, name: nameOf(options.currentLayoutId) }
123
- ]
124
- } else {
125
- targets = known.map(layout => ({ btrId: layout.btrId, name: layout.name }))
126
- }
127
-
128
- const result: AcApFindDrawingResult = { hits: [], truncated: false }
129
- for (const target of targets) {
130
- const found = acapFindTextInLayout(db, target.btrId, query, {
131
- matchCase: options.matchCase,
132
- maxResults: max - result.hits.length
133
- })
134
- for (const hit of found.hits) {
135
- result.hits.push({
136
- ...hit,
137
- layoutId: target.btrId,
138
- layoutName: target.name
139
- })
140
- }
141
- if (found.truncated) {
142
- result.truncated = true
143
- break
144
- }
145
- }
146
- return result
147
- }
148
-
149
- /** Axis-aligned 2D box in WCS (plain numbers; no geometry library needed). */
150
- export interface AcApFindBox {
151
- min: { x: number; y: number }
152
- max: { x: number; y: number }
153
- }
154
-
155
- type XY = { x: number; y: number }
156
- interface WithExtents {
157
- geometricExtents?: { min: XY; max: XY }
158
- }
159
-
160
- /**
161
- * View box for a hit: the text extents (`hit.extents` for nested text), widened so a short label does not
162
- * zoom in absurdly far (at least ~10 text heights wide). Falls back to the
163
- * hit position when the entity has no usable extents.
164
- *
165
- * @param layoutBtrId - Layout that contains the hit (`hit.layoutId`).
166
- */
167
- export function acapFindHitBox(
168
- db: AcApFindDatabaseLike,
169
- layoutBtrId: string,
170
- hit: AcApFindHit
171
- ): AcApFindBox {
172
- const btr = db.tables.blockTable.getIdAt(layoutBtrId)
173
- const owner = btr?.getIdAt?.(hit.entityId) as
174
- | (WithExtents & {
175
- attributeIterator?: () => Iterable<WithExtents & { objectId: string }>
176
- })
177
- | undefined
178
- let target: WithExtents | undefined = owner
179
- if (hit.kind === 'attribute' && owner?.attributeIterator) {
180
- for (const attribute of owner.attributeIterator()) {
181
- if (attribute.objectId === hit.textEntityId) {
182
- target = attribute
183
- break
184
- }
185
- }
186
- }
187
- let min: XY
188
- let max: XY
189
- try {
190
- // Text nested in a block / dimension / table: the search already
191
- // resolved its WCS extents (the owner's extents are the whole block).
192
- const extents = hit.extents ?? target?.geometricExtents
193
- if (!extents || !isFinite(extents.min.x) || !isFinite(extents.max.x)) {
194
- throw new Error('no extents')
195
- }
196
- min = extents.min
197
- max = extents.max
198
- } catch {
199
- min = max = hit.position
200
- }
201
- const cx = (min.x + max.x) / 2
202
- const cy = (min.y + max.y) / 2
203
- const w = max.x - min.x
204
- const h = max.y - min.y
205
- const width = Math.max(w * 3, h * 10, 1e-3)
206
- const height = Math.max(h * 3, width / 4, 1e-3)
207
- return {
208
- min: { x: cx - width / 2, y: cy - height / 2 },
209
- max: { x: cx + width / 2, y: cy + height / 2 }
210
- }
211
- }
1
+ /**
2
+ * Whole-drawing text search (FIND across layouts).
3
+ *
4
+ * Builds on {@link acapFindTextInLayout}: every layout of the drawing (model
5
+ * space and each paper space, in tab order) is searched with the same rules,
6
+ * and every hit is tagged with the layout it lives in so a UI can show it and
7
+ * navigate there.
8
+ *
9
+ * Pure TypeScript with no runtime imports (structural database shape), shared
10
+ * by cad-simple-ui-plugin and the Vue cad-viewer.
11
+ */
12
+ import {
13
+ ACAP_FIND_MAX_RESULTS,
14
+ type AcApFindDatabaseLike,
15
+ type AcApFindHit,
16
+ type AcApFindOptions,
17
+ acapFindTextInLayout
18
+ } from './findText'
19
+
20
+ /**
21
+ * Where to search.
22
+ *
23
+ * - `drawing` (default): every layout of the drawing
24
+ * - `layout`: only the layout that is currently active in the view
25
+ */
26
+ export type AcApFindScope = 'drawing' | 'layout'
27
+
28
+ /** One layout of the drawing (model space or paper space). */
29
+ export interface AcApFindLayoutInfo {
30
+ /** Layout name as shown on the layout tab (e.g. `Model`, `Layout1`). */
31
+ name: string
32
+ /** Block table record id of the layout. */
33
+ btrId: string
34
+ /** Tab order; layouts are searched and listed in this order. */
35
+ tabOrder: number
36
+ }
37
+
38
+ /** A hit that also identifies the layout that contains it. */
39
+ export interface AcApFindLayoutHit extends AcApFindHit {
40
+ /** Block table record id of the layout containing the hit. */
41
+ layoutId: string
42
+ /** Name of the layout containing the hit. */
43
+ layoutName: string
44
+ }
45
+
46
+ /** Result of one drawing-level search. */
47
+ export interface AcApFindDrawingResult {
48
+ hits: AcApFindLayoutHit[]
49
+ /** True when more than `maxResults` entities matched. */
50
+ truncated: boolean
51
+ }
52
+
53
+ /** Options for {@link acapFindText}. */
54
+ export interface AcApFindDrawingOptions extends AcApFindOptions {
55
+ /** Search scope; defaults to `drawing`. */
56
+ scope?: AcApFindScope
57
+ /**
58
+ * Block table record id of the layout currently shown. Required for the
59
+ * `layout` scope; also used as the only layout when the drawing exposes no
60
+ * layout objects.
61
+ */
62
+ currentLayoutId: string
63
+ }
64
+
65
+ interface LayoutLike {
66
+ layoutName?: string
67
+ tabOrder?: number
68
+ blockTableRecordId?: string
69
+ }
70
+
71
+ /** Database shape used to enumerate layouts. */
72
+ export interface AcApFindLayoutsDatabaseLike {
73
+ objects?: {
74
+ layout?: { newIterator?(): Iterable<LayoutLike> }
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Lists the layouts of a drawing sorted by tab order (model space first in
80
+ * practice). Returns an empty list when the drawing has no layout objects.
81
+ */
82
+ export function acapListFindLayouts(
83
+ db: AcApFindLayoutsDatabaseLike
84
+ ): AcApFindLayoutInfo[] {
85
+ const table = db.objects?.layout
86
+ if (!table?.newIterator) return []
87
+ const layouts: AcApFindLayoutInfo[] = []
88
+ for (const layout of table.newIterator()) {
89
+ if (!layout.blockTableRecordId) continue
90
+ layouts.push({
91
+ name: layout.layoutName ?? '',
92
+ btrId: layout.blockTableRecordId,
93
+ tabOrder: Number(layout.tabOrder) || 0
94
+ })
95
+ }
96
+ return layouts.sort(
97
+ (a, b) => a.tabOrder - b.tabOrder || a.name.localeCompare(b.name)
98
+ )
99
+ }
100
+
101
+ /**
102
+ * Finds text in the whole drawing or in the current layout only.
103
+ *
104
+ * Layouts are visited in tab order and the result cap is shared, so
105
+ * `truncated` is true as soon as any match beyond `maxResults` exists in any
106
+ * searched layout. Search runs on the database, not on the rendered scene, so
107
+ * layouts that were never opened in the view are searched too.
108
+ */
109
+ export function acapFindText(
110
+ db: AcApFindDatabaseLike & AcApFindLayoutsDatabaseLike,
111
+ query: string,
112
+ options: AcApFindDrawingOptions
113
+ ): AcApFindDrawingResult {
114
+ const max = options.maxResults ?? ACAP_FIND_MAX_RESULTS
115
+ const known = acapListFindLayouts(db)
116
+ const nameOf = (btrId: string) =>
117
+ known.find(layout => layout.btrId === btrId)?.name ?? ''
118
+
119
+ let targets: Array<{ btrId: string; name: string }>
120
+ if (options.scope === 'layout' || known.length === 0) {
121
+ targets = [
122
+ { btrId: options.currentLayoutId, name: nameOf(options.currentLayoutId) }
123
+ ]
124
+ } else {
125
+ targets = known.map(layout => ({ btrId: layout.btrId, name: layout.name }))
126
+ }
127
+
128
+ const result: AcApFindDrawingResult = { hits: [], truncated: false }
129
+ for (const target of targets) {
130
+ const found = acapFindTextInLayout(db, target.btrId, query, {
131
+ matchCase: options.matchCase,
132
+ maxResults: max - result.hits.length
133
+ })
134
+ for (const hit of found.hits) {
135
+ result.hits.push({
136
+ ...hit,
137
+ layoutId: target.btrId,
138
+ layoutName: target.name
139
+ })
140
+ }
141
+ if (found.truncated) {
142
+ result.truncated = true
143
+ break
144
+ }
145
+ }
146
+ return result
147
+ }
148
+
149
+ /** Axis-aligned 2D box in WCS (plain numbers; no geometry library needed). */
150
+ export interface AcApFindBox {
151
+ min: { x: number; y: number }
152
+ max: { x: number; y: number }
153
+ }
154
+
155
+ type XY = { x: number; y: number }
156
+ interface WithExtents {
157
+ geometricExtents?: { min: XY; max: XY }
158
+ }
159
+
160
+ /**
161
+ * View box for a hit: the text extents (`hit.extents` for nested text), widened so a short label does not
162
+ * zoom in absurdly far (at least ~10 text heights wide). Falls back to the
163
+ * hit position when the entity has no usable extents.
164
+ *
165
+ * @param layoutBtrId - Layout that contains the hit (`hit.layoutId`).
166
+ */
167
+ export function acapFindHitBox(
168
+ db: AcApFindDatabaseLike,
169
+ layoutBtrId: string,
170
+ hit: AcApFindHit
171
+ ): AcApFindBox {
172
+ const btr = db.tables.blockTable.getIdAt(layoutBtrId)
173
+ const owner = btr?.getIdAt?.(hit.entityId) as
174
+ | (WithExtents & {
175
+ attributeIterator?: () => Iterable<WithExtents & { objectId: string }>
176
+ })
177
+ | undefined
178
+ let target: WithExtents | undefined = owner
179
+ if (hit.kind === 'attribute' && owner?.attributeIterator) {
180
+ for (const attribute of owner.attributeIterator()) {
181
+ if (attribute.objectId === hit.textEntityId) {
182
+ target = attribute
183
+ break
184
+ }
185
+ }
186
+ }
187
+ let min: XY
188
+ let max: XY
189
+ try {
190
+ // Text nested in a block / dimension / table: the search already
191
+ // resolved its WCS extents (the owner's extents are the whole block).
192
+ const extents = hit.extents ?? target?.geometricExtents
193
+ if (!extents || !isFinite(extents.min.x) || !isFinite(extents.max.x)) {
194
+ throw new Error('no extents')
195
+ }
196
+ min = extents.min
197
+ max = extents.max
198
+ } catch {
199
+ min = max = hit.position
200
+ }
201
+ const cx = (min.x + max.x) / 2
202
+ const cy = (min.y + max.y) / 2
203
+ const w = max.x - min.x
204
+ const h = max.y - min.y
205
+ const width = Math.max(w * 3, h * 10, 1e-3)
206
+ const height = Math.max(h * 3, width / 4, 1e-3)
207
+ return {
208
+ min: { x: cx - width / 2, y: cy - height / 2 },
209
+ max: { x: cx + width / 2, y: cy + height / 2 }
210
+ }
211
+ }