dytools-capture-engine 1.0.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.
- package/dist/index.cjs +1837 -0
- package/dist/index.js +1819 -0
- package/package.json +30 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1837 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
CaptureEngine: () => CaptureEngine,
|
|
24
|
+
CaptureEngineToZoneEventType: () => CaptureEngineToZoneEventType,
|
|
25
|
+
CapturePublicEventType: () => CapturePublicEventType,
|
|
26
|
+
CaptureToEngineEventType: () => CaptureToEngineEventType
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(index_exports);
|
|
29
|
+
var import_dytools_canvas_engine = require("dytools-canvas-engine");
|
|
30
|
+
var CapturePublicEventType = {
|
|
31
|
+
// These are events based on the state of the zone that is handled by the zone itself.
|
|
32
|
+
ZonePositionChanged: "zone:position_changed",
|
|
33
|
+
// This is a call that happens when either resize or moved.
|
|
34
|
+
ZoneNameChanged: "zone:name_changed",
|
|
35
|
+
ZoneFilterRegexChanged: "zone:filter_regex_changed",
|
|
36
|
+
ZoneExampleChanged: "zone:example_changed",
|
|
37
|
+
ZoneHiddenChanged: "zone:hidden_changed",
|
|
38
|
+
ZoneChanged: "zone:changed",
|
|
39
|
+
// This happens on all the above events.
|
|
40
|
+
TemplateChanged: "template:changed",
|
|
41
|
+
//ZoneChildZoneAdded: "zone:child_zone_added",
|
|
42
|
+
//ZoneChildZoneRemoved: "zone:child_zone_removed",
|
|
43
|
+
//ZoneChildZonesChanged: "zone:child_zone_changed", // This happens on child zone add/remove.
|
|
44
|
+
// These are events based on the state of the zone that is handled by the engine.
|
|
45
|
+
ZoneSelected: "zone:selected",
|
|
46
|
+
ZoneDeselected: "zone:deselected",
|
|
47
|
+
ZoneFlagsAdded: "zone:flags_added",
|
|
48
|
+
ZoneFlagsRemoved: "zone:flags_removed",
|
|
49
|
+
// These are events that are emitted by the engine.
|
|
50
|
+
ZoneAdded: "capture:zone_added",
|
|
51
|
+
ZoneRemoved: "capture:zone_removed",
|
|
52
|
+
ViewportChanged: "capture:viewport_changed",
|
|
53
|
+
// for pan and zoom
|
|
54
|
+
DrawingCompleted: "capture:drawing_completed",
|
|
55
|
+
// for drawing new shape
|
|
56
|
+
OcrShown: "capture:ocr_shown",
|
|
57
|
+
OcrHidden: "capture:ocr_hidden",
|
|
58
|
+
OcrReadLoaded: "capture:api_ocr_loaded",
|
|
59
|
+
OcrMatchesLoaded: "capture:api_ocr_matches_loaded",
|
|
60
|
+
CaptureStarted: "capture:started",
|
|
61
|
+
// when started
|
|
62
|
+
//CaptureStopped: "capture:stopped", // when stopped
|
|
63
|
+
CaptureError: "capture:error",
|
|
64
|
+
// any errors
|
|
65
|
+
CaptureBackgroundChanged: "capture:background_changed",
|
|
66
|
+
CaptureRenderStarted: "capture:render_started",
|
|
67
|
+
CaptureRenderCompleted: "capture:render_completed"
|
|
68
|
+
};
|
|
69
|
+
var CaptureZoneEventType = {
|
|
70
|
+
// These are events that originate and end inside the zone itself.
|
|
71
|
+
ZoneCanvasManagerSet: "zone_internal:canvas_manager_set",
|
|
72
|
+
ZonePositionChanged: "zone_internal:position_changed",
|
|
73
|
+
ZoneColorChanged: "zone_internal:color_changed",
|
|
74
|
+
ZoneNameChanged: "zone_internal:name_changed",
|
|
75
|
+
ZoneExampleChanged: "zone_internal:example_changed",
|
|
76
|
+
ZoneHiddenChanged: "zone_internal:hidden_changed",
|
|
77
|
+
ZoneFilterRegexChanged: "zone_internal:filter_regex_changed",
|
|
78
|
+
ZoneOutputRegexChanged: "zone_internal:output_regex_changed",
|
|
79
|
+
ZoneOutputReplacementChanged: "zone_internal:output_replacement_changed",
|
|
80
|
+
ZoneRequiredChanged: "zone_internal:required_changed",
|
|
81
|
+
ZoneDataTypeChanged: "zone_internal:data_type_changed",
|
|
82
|
+
ZoneExcludeFromOutputChanged: "zone_internal:exclude_from_output_changed",
|
|
83
|
+
ZoneDefaultValueIfEmptyChanged: "zone_internal:default_value_if_empty_changed",
|
|
84
|
+
ZoneOcrMatchesChanged: "zone_internal:ocr_matches_changed",
|
|
85
|
+
ZoneGroupChildrenChanged: "zone_internal:group_children_changed",
|
|
86
|
+
ZoneAnchorLocationChanged: "zone_internal:anchor_location_changed"
|
|
87
|
+
// These are events based on the state of the zone that is handled by the engine.
|
|
88
|
+
// ZoneSelected: "zone:selected",
|
|
89
|
+
// ZoneDeselected: "zone:deselected",
|
|
90
|
+
// ZoneFlagsAdded: "zone:flags_added",
|
|
91
|
+
// ZoneFlagsRemoved: "zone:flags_removed",
|
|
92
|
+
};
|
|
93
|
+
var CaptureEngineToZoneEventType = {
|
|
94
|
+
// These are events that originate from the canvas engine.
|
|
95
|
+
// These are just forwarded to the zone and the zone is responsible for updating its
|
|
96
|
+
// state and emitting events back to the CaptureEngine.
|
|
97
|
+
CanvasObjectPositionChanged: "canvas:object_position_changed",
|
|
98
|
+
CanvasObjectResized: "canvas:object_resized",
|
|
99
|
+
CanvasObjectMoved: "canvas:object_moved",
|
|
100
|
+
//
|
|
101
|
+
// ZonePositionChanged: "zone:position_changed",
|
|
102
|
+
// ZoneColorChanged: "zone:color_changed",
|
|
103
|
+
// ZoneNameChanged: "zone:name_changed",
|
|
104
|
+
// ZoneVisibleChanged: "zone:visible_changed",
|
|
105
|
+
// These are events based on the state of the zone that is handled by the engine.
|
|
106
|
+
ZoneSelected: "zone:selected",
|
|
107
|
+
ZoneDeselected: "zone:deselected",
|
|
108
|
+
ZoneFlagsAdded: "zone:flags_added",
|
|
109
|
+
ZoneFlagsRemoved: "zone:flags_removed",
|
|
110
|
+
CaptureOcrReadLoaded: "capture:ocr_read_loaded",
|
|
111
|
+
CaptureOcrMatchesLoaded: "capture:ocr_matches_loaded"
|
|
112
|
+
};
|
|
113
|
+
var CaptureToEngineEventType = {
|
|
114
|
+
// These are events based on the state of the zone that is handled by the zone itself.
|
|
115
|
+
ZonePositionChanged: "zone:position_changed",
|
|
116
|
+
// This is a call that happens when either resize or moved.
|
|
117
|
+
ZoneNameChanged: "zone:name_changed",
|
|
118
|
+
ZoneFilterRegexChanged: "zone:filter_regex_changed",
|
|
119
|
+
ZoneOutputRegexChanged: "zone:output_regex_changed",
|
|
120
|
+
ZoneOutputReplacementChanged: "zone:output_replacement_changed",
|
|
121
|
+
ZoneRequiredChanged: "zone:required_changed",
|
|
122
|
+
ZoneDataTypeChanged: "zone:data_type_changed",
|
|
123
|
+
ZoneExcludeFromOutputChanged: "zone:exclude_from_output_changed",
|
|
124
|
+
ZoneDefaultValueIfEmptyChanged: "zone:default_value_if_empty_changed",
|
|
125
|
+
ZoneExampleChanged: "zone:example_changed",
|
|
126
|
+
ZoneHiddenChanged: "zone:hidden_changed",
|
|
127
|
+
ZoneChanged: "zone:changed",
|
|
128
|
+
// This happens on all the above events.
|
|
129
|
+
ZoneAnchorLocationChanged: "zone:anchor_location_changed",
|
|
130
|
+
ZoneGroupChildrenChanged: "zone:group_children_changed",
|
|
131
|
+
ZoneChildZoneAdded: "zone:child_zone_added",
|
|
132
|
+
ZoneChildZoneRemoved: "zone:child_zone_removed",
|
|
133
|
+
ZoneChildZonesChanged: "zone:child_zone_changed",
|
|
134
|
+
// This happens on child zone add/remove.
|
|
135
|
+
//
|
|
136
|
+
ZoneError: "zone:error"
|
|
137
|
+
// ObjectPositionChanged: "object:positionchanged",
|
|
138
|
+
// ObjectResized: "object:resized",
|
|
139
|
+
// ObjectMoved: "object:moved",
|
|
140
|
+
// ObjectSelected: "object:selected",
|
|
141
|
+
// ObjectDeselected: "object:deselected",
|
|
142
|
+
};
|
|
143
|
+
var CaptureZoneBase = class {
|
|
144
|
+
constructor(name, rect, hidden, filterRegex, outputRegex, outputReplacement, required = false, dataType = null, excludeFromOutput = false, defaultValueIfEmpty = null) {
|
|
145
|
+
this._example = null;
|
|
146
|
+
this.needsAnchorReposition = false;
|
|
147
|
+
// This is true when the zone needs to be repositioned to the parent's anchor point when the anchor is moved.
|
|
148
|
+
this.primaryCanvasRectangleId = null;
|
|
149
|
+
// a queue for pending internal events
|
|
150
|
+
this.pendingInternalEvents = [];
|
|
151
|
+
this._id = this.makeId();
|
|
152
|
+
this._name = name;
|
|
153
|
+
this._rect = rect;
|
|
154
|
+
this._hidden = hidden;
|
|
155
|
+
this._filterRegex = filterRegex;
|
|
156
|
+
this._outputRegex = outputRegex;
|
|
157
|
+
this._outputReplacement = outputReplacement;
|
|
158
|
+
this._required = required;
|
|
159
|
+
this._dataType = dataType;
|
|
160
|
+
this._excludeFromOutput = excludeFromOutput;
|
|
161
|
+
this._defaultValueIfEmpty = defaultValueIfEmpty;
|
|
162
|
+
}
|
|
163
|
+
handleInternalZoneEvent(type, payload) {
|
|
164
|
+
if (this.primaryCanvasRectangleId === null || !this.canvasManager) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
let propertiesChanged = [];
|
|
168
|
+
if (type === CaptureZoneEventType.ZonePositionChanged) {
|
|
169
|
+
const zonePositionChangedPayload = payload;
|
|
170
|
+
const oldRect = zonePositionChangedPayload.oldPosition;
|
|
171
|
+
const newRect = zonePositionChangedPayload.newPosition;
|
|
172
|
+
this.canvasManager.setRectangleSize(this.primaryCanvasRectangleId, newRect);
|
|
173
|
+
this.emitToEngine(CaptureToEngineEventType.ZonePositionChanged, {
|
|
174
|
+
zone: this,
|
|
175
|
+
oldPosition: oldRect,
|
|
176
|
+
newPosition: newRect
|
|
177
|
+
});
|
|
178
|
+
propertiesChanged.push("rect");
|
|
179
|
+
}
|
|
180
|
+
if (type === CaptureZoneEventType.ZoneNameChanged) {
|
|
181
|
+
const zoneNameChangedPayload = payload;
|
|
182
|
+
const oldName = zoneNameChangedPayload.oldName;
|
|
183
|
+
const newName = zoneNameChangedPayload.newName;
|
|
184
|
+
this.canvasManager.setName(this.primaryCanvasRectangleId, newName);
|
|
185
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneNameChanged, {
|
|
186
|
+
zone: this,
|
|
187
|
+
oldName,
|
|
188
|
+
newName
|
|
189
|
+
});
|
|
190
|
+
propertiesChanged.push("name");
|
|
191
|
+
}
|
|
192
|
+
if (type === CaptureZoneEventType.ZoneExampleChanged) {
|
|
193
|
+
const zoneNameChangedPayload = payload;
|
|
194
|
+
const oldExample = zoneNameChangedPayload.oldName;
|
|
195
|
+
const newExample = zoneNameChangedPayload.newName;
|
|
196
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneExampleChanged, {
|
|
197
|
+
zone: this,
|
|
198
|
+
oldExample,
|
|
199
|
+
newExample
|
|
200
|
+
});
|
|
201
|
+
propertiesChanged.push("example");
|
|
202
|
+
}
|
|
203
|
+
if (type === CaptureZoneEventType.ZoneHiddenChanged) {
|
|
204
|
+
const zoneHiddenChangedPayload = payload;
|
|
205
|
+
const oldHidden = zoneHiddenChangedPayload.oldHidden;
|
|
206
|
+
const newHidden = zoneHiddenChangedPayload.newHidden;
|
|
207
|
+
this.canvasManager?.setVisibility(this.primaryCanvasRectangleId, !newHidden);
|
|
208
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneHiddenChanged, {
|
|
209
|
+
zone: this,
|
|
210
|
+
oldHidden,
|
|
211
|
+
newHidden
|
|
212
|
+
});
|
|
213
|
+
propertiesChanged.push("hidden");
|
|
214
|
+
}
|
|
215
|
+
if (type === CaptureZoneEventType.ZoneFilterRegexChanged) {
|
|
216
|
+
const zoneFilterRegexChangedPayload = payload;
|
|
217
|
+
const oldFilterRegex = zoneFilterRegexChangedPayload.oldFilterRegex;
|
|
218
|
+
const newFilterRegex = zoneFilterRegexChangedPayload.newFilterRegex;
|
|
219
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneFilterRegexChanged, {
|
|
220
|
+
zone: this,
|
|
221
|
+
oldFilterRegex,
|
|
222
|
+
newFilterRegex
|
|
223
|
+
});
|
|
224
|
+
propertiesChanged.push("filterRegex");
|
|
225
|
+
}
|
|
226
|
+
if (type === CaptureZoneEventType.ZoneOutputRegexChanged) {
|
|
227
|
+
const zoneOutputRegexChangedPayload = payload;
|
|
228
|
+
const oldOutputRegex = zoneOutputRegexChangedPayload.oldOutputRegex;
|
|
229
|
+
const newOutputRegex = zoneOutputRegexChangedPayload.newOutputRegex;
|
|
230
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneOutputRegexChanged, {
|
|
231
|
+
zone: this,
|
|
232
|
+
oldOutputRegex,
|
|
233
|
+
newOutputRegex
|
|
234
|
+
});
|
|
235
|
+
propertiesChanged.push("outputRegex");
|
|
236
|
+
}
|
|
237
|
+
if (type === CaptureZoneEventType.ZoneOutputReplacementChanged) {
|
|
238
|
+
const zoneOutputReplacementChangedPayload = payload;
|
|
239
|
+
const oldOutputReplacement = zoneOutputReplacementChangedPayload.oldOutputReplacement;
|
|
240
|
+
const newOutputReplacement = zoneOutputReplacementChangedPayload.newOutputReplacement;
|
|
241
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneOutputReplacementChanged, {
|
|
242
|
+
zone: this,
|
|
243
|
+
oldOutputReplacement,
|
|
244
|
+
newOutputReplacement
|
|
245
|
+
});
|
|
246
|
+
propertiesChanged.push("outputReplacement");
|
|
247
|
+
}
|
|
248
|
+
if (type === CaptureZoneEventType.ZoneRequiredChanged) {
|
|
249
|
+
const zoneRequiredChangedPayload = payload;
|
|
250
|
+
const oldRequired = zoneRequiredChangedPayload.oldRequired;
|
|
251
|
+
const newRequired = zoneRequiredChangedPayload.newRequired;
|
|
252
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneRequiredChanged, {
|
|
253
|
+
zone: this,
|
|
254
|
+
oldRequired,
|
|
255
|
+
newRequired
|
|
256
|
+
});
|
|
257
|
+
propertiesChanged.push("required");
|
|
258
|
+
}
|
|
259
|
+
if (type === CaptureZoneEventType.ZoneDataTypeChanged) {
|
|
260
|
+
const zoneDataTypeChangedPayload = payload;
|
|
261
|
+
const oldDataType = zoneDataTypeChangedPayload.oldDataType;
|
|
262
|
+
const newDataType = zoneDataTypeChangedPayload.newDataType;
|
|
263
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneDataTypeChanged, {
|
|
264
|
+
zone: this,
|
|
265
|
+
oldDataType,
|
|
266
|
+
newDataType
|
|
267
|
+
});
|
|
268
|
+
propertiesChanged.push("dataType");
|
|
269
|
+
}
|
|
270
|
+
if (type === CaptureZoneEventType.ZoneExcludeFromOutputChanged) {
|
|
271
|
+
const zoneExcludeFromOutputChangedPayload = payload;
|
|
272
|
+
const oldExcludeFromOutput = zoneExcludeFromOutputChangedPayload.oldExcludeFromOutput;
|
|
273
|
+
const newExcludeFromOutput = zoneExcludeFromOutputChangedPayload.newExcludeFromOutput;
|
|
274
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneExcludeFromOutputChanged, {
|
|
275
|
+
zone: this,
|
|
276
|
+
oldExcludeFromOutput,
|
|
277
|
+
newExcludeFromOutput
|
|
278
|
+
});
|
|
279
|
+
propertiesChanged.push("excludeFromOutput");
|
|
280
|
+
}
|
|
281
|
+
if (type === CaptureZoneEventType.ZoneDefaultValueIfEmptyChanged) {
|
|
282
|
+
const zoneDefaultValueIfEmptyChangedPayload = payload;
|
|
283
|
+
const oldDefaultValueIfEmpty = zoneDefaultValueIfEmptyChangedPayload.oldDefaultValueIfEmpty;
|
|
284
|
+
const newDefaultValueIfEmpty = zoneDefaultValueIfEmptyChangedPayload.newDefaultValueIfEmpty;
|
|
285
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneDefaultValueIfEmptyChanged, {
|
|
286
|
+
zone: this,
|
|
287
|
+
oldDefaultValueIfEmpty,
|
|
288
|
+
newDefaultValueIfEmpty
|
|
289
|
+
});
|
|
290
|
+
propertiesChanged.push("defaultValueIfEmpty");
|
|
291
|
+
}
|
|
292
|
+
if (propertiesChanged.length > 0) {
|
|
293
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneChanged, { zone: this, propertiesChanged });
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/* --- PROPERTIES --- */
|
|
297
|
+
get id() {
|
|
298
|
+
return this._id;
|
|
299
|
+
}
|
|
300
|
+
// if you really want id to be immutable, just omit the setter
|
|
301
|
+
get rect() {
|
|
302
|
+
return this._rect;
|
|
303
|
+
}
|
|
304
|
+
set rect(value) {
|
|
305
|
+
if (value.equals(this._rect)) return;
|
|
306
|
+
let originVect = value.origin.getDeltaFromPoint(this._rect.origin);
|
|
307
|
+
let widthDifference = Math.abs(value.size.width - this._rect.size.width);
|
|
308
|
+
let heightDifference = Math.abs(value.size.height - this._rect.size.height);
|
|
309
|
+
if (Math.abs(originVect.x) < 1 && Math.abs(originVect.y) < 1 && widthDifference < 1 && heightDifference < 1) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
const oldRect = this._rect;
|
|
313
|
+
this._rect = value;
|
|
314
|
+
this.emitZoneEvent(CaptureZoneEventType.ZonePositionChanged, { oldPosition: oldRect, newPosition: value });
|
|
315
|
+
}
|
|
316
|
+
get name() {
|
|
317
|
+
return this._name;
|
|
318
|
+
}
|
|
319
|
+
set name(value) {
|
|
320
|
+
if (value === this._name) return;
|
|
321
|
+
if ((value === void 0 || value === null || value === "") && (this._name === void 0 || this._name === null || this._name === "")) return;
|
|
322
|
+
const oldName = this._name;
|
|
323
|
+
this._name = value;
|
|
324
|
+
this.emitZoneEvent(CaptureZoneEventType.ZoneNameChanged, { oldName, newName: value });
|
|
325
|
+
}
|
|
326
|
+
get example() {
|
|
327
|
+
return this._example;
|
|
328
|
+
}
|
|
329
|
+
set example(value) {
|
|
330
|
+
if (value === this._example) return;
|
|
331
|
+
if ((value === void 0 || value === null || value === "") && (this._example === void 0 || this._example === null || this._example === "")) return;
|
|
332
|
+
const oldExample = this._example;
|
|
333
|
+
this._example = value;
|
|
334
|
+
this.emitZoneEvent(CaptureZoneEventType.ZoneExampleChanged, { oldExample, newExample: value });
|
|
335
|
+
}
|
|
336
|
+
get hidden() {
|
|
337
|
+
return this._hidden;
|
|
338
|
+
}
|
|
339
|
+
set hidden(value) {
|
|
340
|
+
if (value === this._hidden) return;
|
|
341
|
+
const oldHidden = this._hidden;
|
|
342
|
+
this._hidden = value;
|
|
343
|
+
this.emitZoneEvent(CaptureZoneEventType.ZoneHiddenChanged, { oldHidden, newHidden: value });
|
|
344
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneHiddenChanged, {
|
|
345
|
+
zone: this,
|
|
346
|
+
oldHidden,
|
|
347
|
+
newHidden: value
|
|
348
|
+
});
|
|
349
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneChanged, { zone: this, propertiesChanged: ["hidden"] });
|
|
350
|
+
}
|
|
351
|
+
get filterRegex() {
|
|
352
|
+
return this._filterRegex ?? null;
|
|
353
|
+
}
|
|
354
|
+
set filterRegex(value) {
|
|
355
|
+
if (value === this._filterRegex) return;
|
|
356
|
+
if ((value === void 0 || value === null || value === "") && (this._filterRegex === void 0 || this._filterRegex === null || this._filterRegex === "")) return;
|
|
357
|
+
if (!this.isValidRegex(value)) {
|
|
358
|
+
console.error(`Invalid filter regex: ${value}`);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
const oldFilterRegex = this._filterRegex;
|
|
362
|
+
this._filterRegex = value;
|
|
363
|
+
this.emitZoneEvent(CaptureZoneEventType.ZoneFilterRegexChanged, { oldFilterRegex, newFilterRegex: value });
|
|
364
|
+
}
|
|
365
|
+
get outputRegex() {
|
|
366
|
+
return this._outputRegex ?? null;
|
|
367
|
+
}
|
|
368
|
+
set outputRegex(value) {
|
|
369
|
+
if (value === this._outputRegex) return;
|
|
370
|
+
if ((value === void 0 || value === null || value === "") && (this._outputRegex === void 0 || this._outputRegex === null || this._outputRegex === "")) return;
|
|
371
|
+
if (!this.isValidRegex(value)) {
|
|
372
|
+
console.error(`Invalid output regex: ${value}`);
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
const oldOutputRegex = this._outputRegex;
|
|
376
|
+
this._outputRegex = value;
|
|
377
|
+
this.emitZoneEvent(CaptureZoneEventType.ZoneOutputRegexChanged, { oldOutputRegex, newOutputRegex: value });
|
|
378
|
+
}
|
|
379
|
+
get outputReplacement() {
|
|
380
|
+
return this._outputRegex ?? null;
|
|
381
|
+
}
|
|
382
|
+
set outputReplacement(value) {
|
|
383
|
+
if (value === this._outputReplacement) return;
|
|
384
|
+
if ((value === void 0 || value === null || value === "") && (this._outputReplacement === void 0 || this._outputReplacement === null || this._outputReplacement === "")) return;
|
|
385
|
+
const oldOutputReplacement = this._outputReplacement;
|
|
386
|
+
this._outputReplacement = value;
|
|
387
|
+
this.emitZoneEvent(CaptureZoneEventType.ZoneOutputReplacementChanged, { oldOutputReplacement, newOutputReplacement: value });
|
|
388
|
+
}
|
|
389
|
+
get required() {
|
|
390
|
+
return this._required;
|
|
391
|
+
}
|
|
392
|
+
set required(value) {
|
|
393
|
+
if (value === this._required) return;
|
|
394
|
+
const oldRequired = this._required;
|
|
395
|
+
this._required = value;
|
|
396
|
+
this.emitZoneEvent(CaptureZoneEventType.ZoneRequiredChanged, { oldRequired, newRequired: value });
|
|
397
|
+
}
|
|
398
|
+
get dataType() {
|
|
399
|
+
return this._dataType ?? null;
|
|
400
|
+
}
|
|
401
|
+
set dataType(value) {
|
|
402
|
+
if (value === this._dataType) return;
|
|
403
|
+
if ((value === void 0 || value === null || value === "") && (this._dataType === void 0 || this._dataType === null || this._dataType === "")) return;
|
|
404
|
+
const oldDataType = this._dataType;
|
|
405
|
+
this._dataType = value;
|
|
406
|
+
this.emitZoneEvent(CaptureZoneEventType.ZoneDataTypeChanged, { oldDataType, newDataType: value });
|
|
407
|
+
}
|
|
408
|
+
get excludeFromOutput() {
|
|
409
|
+
return this._excludeFromOutput;
|
|
410
|
+
}
|
|
411
|
+
set excludeFromOutput(value) {
|
|
412
|
+
if (value === this._excludeFromOutput) return;
|
|
413
|
+
const oldExcludeFromOutput = this._excludeFromOutput;
|
|
414
|
+
this._excludeFromOutput = value;
|
|
415
|
+
this.emitZoneEvent(CaptureZoneEventType.ZoneExcludeFromOutputChanged, { oldExcludeFromOutput, newExcludeFromOutput: value });
|
|
416
|
+
}
|
|
417
|
+
get defaultValueIfEmpty() {
|
|
418
|
+
return this._defaultValueIfEmpty ?? null;
|
|
419
|
+
}
|
|
420
|
+
set defaultValueIfEmpty(value) {
|
|
421
|
+
if (value === this._defaultValueIfEmpty) return;
|
|
422
|
+
if ((value === void 0 || value === null || value === "") && (this._defaultValueIfEmpty === void 0 || this._defaultValueIfEmpty === null || this._defaultValueIfEmpty === "")) return;
|
|
423
|
+
const oldDefaultValueIfEmpty = this._defaultValueIfEmpty;
|
|
424
|
+
this._defaultValueIfEmpty = value;
|
|
425
|
+
this.emitZoneEvent(CaptureZoneEventType.ZoneDefaultValueIfEmptyChanged, { oldDefaultValueIfEmpty, newDefaultValueIfEmpty: value });
|
|
426
|
+
}
|
|
427
|
+
/* EVENT HANDLING METHODS */
|
|
428
|
+
setEngineEventSink(callback) {
|
|
429
|
+
this.engineEventSink = callback;
|
|
430
|
+
}
|
|
431
|
+
setCanvasManager(cm) {
|
|
432
|
+
this._canvasManager = cm;
|
|
433
|
+
this.emitZoneEvent(CaptureZoneEventType.ZoneCanvasManagerSet, { canvasManager: cm });
|
|
434
|
+
}
|
|
435
|
+
emitToEngine(type, payload) {
|
|
436
|
+
this.engineEventSink?.(type, payload);
|
|
437
|
+
}
|
|
438
|
+
emitZoneEvent(type, payload) {
|
|
439
|
+
if (this.canvasManager === null) {
|
|
440
|
+
this.pendingInternalEvents.push({ type, payload });
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
if (this.pendingInternalEvents.length > 0) {
|
|
444
|
+
let events = this.pendingInternalEvents;
|
|
445
|
+
this.pendingInternalEvents = [];
|
|
446
|
+
for (const event of events) {
|
|
447
|
+
this.handleInternalZoneEvent(event.type, event.payload);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
this.handleInternalZoneEvent(type, payload);
|
|
451
|
+
}
|
|
452
|
+
get canvasManager() {
|
|
453
|
+
return this._canvasManager ?? null;
|
|
454
|
+
}
|
|
455
|
+
makeId() {
|
|
456
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
457
|
+
return crypto.randomUUID();
|
|
458
|
+
}
|
|
459
|
+
const template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
|
|
460
|
+
return template.replace(/[xy]/g, (c) => {
|
|
461
|
+
const r = Math.random() * 16 | 0;
|
|
462
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
463
|
+
return v.toString(16);
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
isValidRegex(pattern) {
|
|
467
|
+
if (!pattern || !pattern.trim()) return false;
|
|
468
|
+
try {
|
|
469
|
+
new RegExp(pattern);
|
|
470
|
+
return true;
|
|
471
|
+
} catch {
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
var SimpleZone = class extends CaptureZoneBase {
|
|
477
|
+
constructor(name, rect, hidden, filterRegex, outputRegex, outputReplacement, required = false, dataType = null, excludeFromOutput = false, defaultValueIfEmpty = null) {
|
|
478
|
+
super(name, rect, hidden, filterRegex, outputRegex, outputReplacement, required, dataType, excludeFromOutput, defaultValueIfEmpty);
|
|
479
|
+
this.type = "simple";
|
|
480
|
+
this.ocrOverlayIds = [];
|
|
481
|
+
this.lastMatchHash = "";
|
|
482
|
+
}
|
|
483
|
+
handleInternalZoneEvent(type, payload) {
|
|
484
|
+
super.handleInternalZoneEvent(type, payload);
|
|
485
|
+
if (this.canvasManager === null) {
|
|
486
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneError, { zone: this, message: "Missing CanvasManager" });
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
if (type === CaptureZoneEventType.ZoneCanvasManagerSet) {
|
|
490
|
+
this.primaryCanvasRectangleId = this.canvasManager.addRectangle(this.rect, this.name, "blue", true, true);
|
|
491
|
+
}
|
|
492
|
+
if (type === CaptureZoneEventType.ZoneHiddenChanged) {
|
|
493
|
+
}
|
|
494
|
+
if (type === CaptureZoneEventType.ZoneOcrMatchesChanged) {
|
|
495
|
+
const zoneOcrMatchesChangedPayload = payload;
|
|
496
|
+
let ocrMatches = zoneOcrMatchesChangedPayload.matches;
|
|
497
|
+
if (ocrMatches === null) {
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
this.ocrOverlayIds.forEach((id) => this.canvasManager?.removeObject(id));
|
|
501
|
+
this.ocrOverlayIds = [];
|
|
502
|
+
let isFirstMatch = true;
|
|
503
|
+
for (const match of ocrMatches) {
|
|
504
|
+
if (match.templateZoneId != this.id) continue;
|
|
505
|
+
if (isFirstMatch) {
|
|
506
|
+
this.example = match.processedText;
|
|
507
|
+
}
|
|
508
|
+
if (!this.hidden) {
|
|
509
|
+
this.ocrOverlayIds.push(this.canvasManager?.addPolygon(match.polygonAbsolute.points, "rgba(0, 255, 0, 0.25)", false));
|
|
510
|
+
}
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
handleEvent(id, type, payload) {
|
|
516
|
+
if (this.id !== id) {
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
if (type == CaptureEngineToZoneEventType.CanvasObjectPositionChanged) {
|
|
520
|
+
const objectPositionChangedPayload = payload;
|
|
521
|
+
let newPosition = objectPositionChangedPayload.newPosition;
|
|
522
|
+
this.rect = newPosition;
|
|
523
|
+
this.emitToEngine(CaptureToEngineEventType.ZonePositionChanged, { zone: this, oldPosition: this.rect, newPosition });
|
|
524
|
+
}
|
|
525
|
+
if (type == CaptureEngineToZoneEventType.CaptureOcrMatchesLoaded) {
|
|
526
|
+
const captureOcrMatchesLoadedPayload = payload;
|
|
527
|
+
let ocrMatches = captureOcrMatchesLoadedPayload.ocrMatches;
|
|
528
|
+
let thisOcrMatches = ocrMatches?.filter((e) => e.templateZoneId == this.id) ?? [];
|
|
529
|
+
let matchHash = this.hidden + "|" + thisOcrMatches.map((e) => `${e.ocrTextResultId}*${e.anchorPointPercent}`).join(",");
|
|
530
|
+
if (matchHash !== this.lastMatchHash) {
|
|
531
|
+
this.lastMatchHash = matchHash;
|
|
532
|
+
this.emitZoneEvent(CaptureZoneEventType.ZoneOcrMatchesChanged, { matches: ocrMatches });
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
update(ocrRead, ocrMatches, canvas, flags) {
|
|
537
|
+
if (!this.primaryCanvasRectangleId) {
|
|
538
|
+
this.primaryCanvasRectangleId = canvas.addRectangle(this.rect, this.name, "blue", true, true);
|
|
539
|
+
} else {
|
|
540
|
+
canvas.setName(this.primaryCanvasRectangleId, this.name);
|
|
541
|
+
canvas.setColor(this.primaryCanvasRectangleId, "blue");
|
|
542
|
+
canvas.setVisibility(this.primaryCanvasRectangleId, !this.hidden);
|
|
543
|
+
canvas.setSelectable(this.primaryCanvasRectangleId, true);
|
|
544
|
+
canvas.setResizable(this.primaryCanvasRectangleId, true);
|
|
545
|
+
canvas.setRectangleSize(this.primaryCanvasRectangleId, this.rect);
|
|
546
|
+
}
|
|
547
|
+
if (!ocrMatches || ocrMatches.length == 0) {
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
let thisOcrMatches = ocrMatches?.filter((e) => e.templateZoneId == this.id) ?? [];
|
|
551
|
+
let matchHash = this.hidden + "|" + thisOcrMatches.map((e) => `${e.ocrTextResultId}`).join(",");
|
|
552
|
+
if (matchHash === this.lastMatchHash) {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
this.ocrOverlayIds.forEach((id) => canvas.removeObject(id));
|
|
556
|
+
this.lastMatchHash = matchHash;
|
|
557
|
+
let isFirstMatch = true;
|
|
558
|
+
for (const match of thisOcrMatches) {
|
|
559
|
+
if (isFirstMatch) {
|
|
560
|
+
this.example = match.processedText;
|
|
561
|
+
}
|
|
562
|
+
if (!this.hidden) {
|
|
563
|
+
this.ocrOverlayIds.push(canvas.addPolygon(match.polygonAbsolute.points, "rgba(0, 255, 0, 0.25)", false));
|
|
564
|
+
}
|
|
565
|
+
break;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
toExternal(docWidth, docHeight) {
|
|
569
|
+
console.log(`Sim x:${this.rect.origin.x}, y:${this.rect.origin.y}, w:${this.rect.size.width}, h:${this.rect.size.height}`);
|
|
570
|
+
return {
|
|
571
|
+
TemplateZoneId: this.id,
|
|
572
|
+
Name: this.name,
|
|
573
|
+
Type: "TemplateSimpleZone",
|
|
574
|
+
X: this.rect.origin.x / docWidth,
|
|
575
|
+
Y: this.rect.origin.y / docHeight,
|
|
576
|
+
Width: this.rect.size.width / docWidth,
|
|
577
|
+
Height: this.rect.size.height / docHeight,
|
|
578
|
+
XAbsolute: this.rect.origin.x,
|
|
579
|
+
YAbsolute: this.rect.origin.y,
|
|
580
|
+
WidthAbsolute: this.rect.size.width,
|
|
581
|
+
HeightAbsolute: this.rect.size.height,
|
|
582
|
+
RegExFilter: this.filterRegex,
|
|
583
|
+
RegExOutput: this.outputRegex,
|
|
584
|
+
RegExReplacement: this.outputReplacement,
|
|
585
|
+
Required: this.required,
|
|
586
|
+
DataType: this.dataType,
|
|
587
|
+
ExcludeFromOutput: this.excludeFromOutput,
|
|
588
|
+
DefaultValueIfEmpty: this.defaultValueIfEmpty
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
var AnchorChildZone = class extends SimpleZone {
|
|
593
|
+
constructor() {
|
|
594
|
+
super(...arguments);
|
|
595
|
+
this.type = "anchor-child";
|
|
596
|
+
}
|
|
597
|
+
toExternalChild(docWidth, docHeight, parentAnchor) {
|
|
598
|
+
let external = this.toExternal(docWidth, docHeight);
|
|
599
|
+
external.Type = "TemplateAnchorZoneChild";
|
|
600
|
+
const parentAnchorPercent = new import_dytools_canvas_engine.Point(parentAnchor.x / docWidth, parentAnchor.y / docHeight);
|
|
601
|
+
external.X = this.rect.origin.x / docWidth - parentAnchorPercent.x;
|
|
602
|
+
external.Y = this.rect.origin.y / docHeight - parentAnchorPercent.y;
|
|
603
|
+
external.XAbsolute = this.rect.origin.x;
|
|
604
|
+
external.YAbsolute = this.rect.origin.y;
|
|
605
|
+
return external;
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
var AnchorZone = class extends CaptureZoneBase {
|
|
609
|
+
constructor(name, rect, hidden, filterRegex, outputRegex, outputReplacement, required = false, dataType = null, excludeFromOutput = false, defaultValueIfEmpty = null) {
|
|
610
|
+
super(name, rect, hidden, filterRegex, outputRegex, outputReplacement, required, dataType, excludeFromOutput, defaultValueIfEmpty);
|
|
611
|
+
this.type = "anchor";
|
|
612
|
+
//private primaryCanvasRectangleId: string | null = null;
|
|
613
|
+
this._anchorLocation = "TopLeft";
|
|
614
|
+
this._groupChildren = true;
|
|
615
|
+
this.children = [];
|
|
616
|
+
//canvasEngineIds: string[] = [];
|
|
617
|
+
this.ocrOverlayIds = [];
|
|
618
|
+
this.lastMatchHash = "";
|
|
619
|
+
this.currentAnchorPoint = null;
|
|
620
|
+
this._cycle = 50;
|
|
621
|
+
const internalArray = [];
|
|
622
|
+
const snapshotChildren = (arr) => {
|
|
623
|
+
const map = /* @__PURE__ */ new Map();
|
|
624
|
+
for (const c of arr) {
|
|
625
|
+
if (!c) continue;
|
|
626
|
+
map.set(c.id, c);
|
|
627
|
+
}
|
|
628
|
+
return map;
|
|
629
|
+
};
|
|
630
|
+
const applyChildrenDiff = (before, afterArr) => {
|
|
631
|
+
const after = /* @__PURE__ */ new Map();
|
|
632
|
+
for (const c of afterArr) {
|
|
633
|
+
if (!c) continue;
|
|
634
|
+
after.set(c.id, c);
|
|
635
|
+
}
|
|
636
|
+
for (const [id, child] of before.entries()) {
|
|
637
|
+
if (!after.has(id)) {
|
|
638
|
+
this.onChildZoneRemoved(child);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
for (const [id, child] of after.entries()) {
|
|
642
|
+
if (!before.has(id)) {
|
|
643
|
+
this.onChildZoneAdded(child);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
this.children = new Proxy(internalArray, {
|
|
648
|
+
set: (target, property, value) => {
|
|
649
|
+
const prop = String(property);
|
|
650
|
+
const isIndex = !Number.isNaN(Number(prop));
|
|
651
|
+
const isLength = prop === "length";
|
|
652
|
+
const before = isIndex || isLength ? snapshotChildren(target) : null;
|
|
653
|
+
const result = Reflect.set(target, property, value);
|
|
654
|
+
if (before && (isIndex || isLength)) {
|
|
655
|
+
applyChildrenDiff(before, target);
|
|
656
|
+
}
|
|
657
|
+
return result;
|
|
658
|
+
},
|
|
659
|
+
deleteProperty: (target, property) => {
|
|
660
|
+
const isIndex = !Number.isNaN(Number(property));
|
|
661
|
+
const before = isIndex ? snapshotChildren(target) : null;
|
|
662
|
+
const result = Reflect.deleteProperty(target, property);
|
|
663
|
+
if (isIndex && before) {
|
|
664
|
+
applyChildrenDiff(before, target);
|
|
665
|
+
}
|
|
666
|
+
return result;
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
Object.defineProperty(this, "children", {
|
|
670
|
+
writable: false,
|
|
671
|
+
configurable: false
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
get anchorLocation() {
|
|
675
|
+
return this._anchorLocation;
|
|
676
|
+
}
|
|
677
|
+
set anchorLocation(value) {
|
|
678
|
+
if (value === this._anchorLocation) return;
|
|
679
|
+
const oldAnchorLocation = this._anchorLocation;
|
|
680
|
+
this._anchorLocation = value;
|
|
681
|
+
this.emitZoneEvent(CaptureZoneEventType.ZoneAnchorLocationChanged, { oldAnchorLocation, newAnchorLocation: value });
|
|
682
|
+
}
|
|
683
|
+
get groupChildren() {
|
|
684
|
+
return this._groupChildren;
|
|
685
|
+
}
|
|
686
|
+
set groupChildren(value) {
|
|
687
|
+
if (value === this._groupChildren) return;
|
|
688
|
+
const oldGroupChildren = this._groupChildren;
|
|
689
|
+
this._groupChildren = value;
|
|
690
|
+
this.emitZoneEvent(CaptureZoneEventType.ZoneGroupChildrenChanged, { oldGroupChildren, newGroupChildren: value });
|
|
691
|
+
}
|
|
692
|
+
handleInternalZoneEvent(type, payload) {
|
|
693
|
+
super.handleInternalZoneEvent(type, payload);
|
|
694
|
+
if (this.canvasManager === null) {
|
|
695
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneError, { zone: this, message: "Missing CanvasManager" });
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
if (type === CaptureZoneEventType.ZoneCanvasManagerSet) {
|
|
699
|
+
this.primaryCanvasRectangleId = this.canvasManager?.addRectangle(this.rect, this.name, "green", true, true);
|
|
700
|
+
}
|
|
701
|
+
if (type === CaptureZoneEventType.ZoneAnchorLocationChanged) {
|
|
702
|
+
const zoneAnchorLocationChangedPayload = payload;
|
|
703
|
+
const oldAnchorLocation = zoneAnchorLocationChangedPayload.oldAnchorLocation;
|
|
704
|
+
const newAnchorLocation = zoneAnchorLocationChangedPayload.newAnchorLocation;
|
|
705
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneAnchorLocationChanged, {
|
|
706
|
+
zone: this,
|
|
707
|
+
oldAnchorLocation,
|
|
708
|
+
newAnchorLocation
|
|
709
|
+
});
|
|
710
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneChanged, { zone: this, propertiesChanged: ["anchorLocation"] });
|
|
711
|
+
}
|
|
712
|
+
if (type === CaptureZoneEventType.ZoneGroupChildrenChanged) {
|
|
713
|
+
const zoneGroupChildrenChangedPayload = payload;
|
|
714
|
+
const oldGroupChildren = zoneGroupChildrenChangedPayload.oldGroupChildren;
|
|
715
|
+
const newGroupChildren = zoneGroupChildrenChangedPayload.newGroupChildren;
|
|
716
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneGroupChildrenChanged, {
|
|
717
|
+
zone: this,
|
|
718
|
+
oldGroupChildren,
|
|
719
|
+
newGroupChildren
|
|
720
|
+
});
|
|
721
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneChanged, { zone: this, propertiesChanged: ["groupChildren"] });
|
|
722
|
+
}
|
|
723
|
+
if (type === CaptureZoneEventType.ZoneOcrMatchesChanged) {
|
|
724
|
+
const zoneOcrMatchesChangedPayload = payload;
|
|
725
|
+
let ocrMatches = zoneOcrMatchesChangedPayload.matches;
|
|
726
|
+
if (ocrMatches === null) {
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
this.ocrOverlayIds.forEach((id) => this.canvasManager?.removeObject(id));
|
|
730
|
+
this.ocrOverlayIds = [];
|
|
731
|
+
let isFirstMatch = true;
|
|
732
|
+
let cycle = this.cycle;
|
|
733
|
+
for (const match of ocrMatches) {
|
|
734
|
+
if (match.templateZoneId != this.id) continue;
|
|
735
|
+
if (isFirstMatch) {
|
|
736
|
+
this.example = match.processedText;
|
|
737
|
+
}
|
|
738
|
+
if (!this.hidden) {
|
|
739
|
+
this.ocrOverlayIds.push(this.canvasManager?.addPolygon(match.polygonAbsolute.points, "rgba(0, 255, 0, 0.25)", false));
|
|
740
|
+
}
|
|
741
|
+
if (match.anchorPointAbsolute) {
|
|
742
|
+
if (!this.hidden) {
|
|
743
|
+
this.ocrOverlayIds.push(this.canvasManager?.addCircle(match.anchorPointAbsolute, 2, "rgba(0, 0, 255, 0.25)", false, false));
|
|
744
|
+
}
|
|
745
|
+
if (isFirstMatch) {
|
|
746
|
+
for (const child of this.children.filter((e) => e.needsAnchorReposition)) {
|
|
747
|
+
let currentAnchorPoint = this.currentAnchorPoint ?? this.rect.origin;
|
|
748
|
+
let moveVector = match.anchorPointAbsolute.getDeltaFromPoint(currentAnchorPoint);
|
|
749
|
+
child.rect = child.rect.move(moveVector);
|
|
750
|
+
child.needsAnchorReposition = false;
|
|
751
|
+
}
|
|
752
|
+
} else {
|
|
753
|
+
for (const child of this.children) {
|
|
754
|
+
if (child.hidden == false) {
|
|
755
|
+
let vector = this.currentAnchorPoint ? match.anchorPointAbsolute.getDeltaFromPoint(this.currentAnchorPoint) : new import_dytools_canvas_engine.Vector(0, 0);
|
|
756
|
+
let color = "rgba(" + cycle + ", 128, 255, 0.5)";
|
|
757
|
+
const polygon = child.rect.move(vector).toPolygon().points;
|
|
758
|
+
this.ocrOverlayIds.push(this.canvasManager?.addPolygon(polygon, color, false));
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
if (this.currentAnchorPoint === null || isFirstMatch) {
|
|
763
|
+
this.currentAnchorPoint = match.anchorPointAbsolute;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
isFirstMatch = false;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
get cycle() {
|
|
771
|
+
this._cycle = (this._cycle + 64) % 255;
|
|
772
|
+
return this._cycle;
|
|
773
|
+
}
|
|
774
|
+
handleEvent(id, type, payload) {
|
|
775
|
+
if (this.id == id) {
|
|
776
|
+
if (type == CaptureEngineToZoneEventType.CanvasObjectPositionChanged) {
|
|
777
|
+
const objectPositionChangedPayload = payload;
|
|
778
|
+
let newPosition = objectPositionChangedPayload.newPosition;
|
|
779
|
+
this.rect = newPosition;
|
|
780
|
+
this.emitToEngine(CaptureToEngineEventType.ZonePositionChanged, { zone: this, oldPosition: this.rect, newPosition });
|
|
781
|
+
}
|
|
782
|
+
} else {
|
|
783
|
+
for (const child of this.children) {
|
|
784
|
+
child.handleEvent?.(id, type, payload);
|
|
785
|
+
}
|
|
786
|
+
let wasChild = this.children.some((e) => e.id == id);
|
|
787
|
+
if (wasChild) {
|
|
788
|
+
this.lastMatchHash = "";
|
|
789
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneChanged, { zone: this, propertiesChanged: ["anchorLocation", "groupChildren"] });
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
if (type == CaptureEngineToZoneEventType.CaptureOcrMatchesLoaded) {
|
|
793
|
+
const captureOcrMatchesLoadedPayload = payload;
|
|
794
|
+
let ocrMatches = captureOcrMatchesLoadedPayload.ocrMatches;
|
|
795
|
+
let thisOcrMatches = ocrMatches?.filter((e) => e.templateZoneId == this.id) ?? [];
|
|
796
|
+
let matchHash = this.groupChildren + "|" + this.anchorLocation + "|" + this.hidden + "|" + thisOcrMatches.map((e) => `${e.ocrTextResultId}*${e.anchorPointPercent?.x}*${e.anchorPointPercent?.y}`).join(",") + "|" + this.children.map((e) => `${e.id}*${e.hidden}*${e.rect?.origin.x}*${e.rect?.origin.y}*${e.rect?.size.width}*${e.rect?.size.height}`).join(",");
|
|
797
|
+
if (matchHash !== this.lastMatchHash) {
|
|
798
|
+
this.lastMatchHash = matchHash;
|
|
799
|
+
this.emitZoneEvent(CaptureZoneEventType.ZoneOcrMatchesChanged, { matches: ocrMatches });
|
|
800
|
+
} else {
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
update(ocrRead, ocrMatches, canvas, flags) {
|
|
805
|
+
if (!this.primaryCanvasRectangleId) {
|
|
806
|
+
this.primaryCanvasRectangleId = canvas.addRectangle(this.rect, this.name, "green", true, true);
|
|
807
|
+
} else {
|
|
808
|
+
canvas.setName(this.primaryCanvasRectangleId, this.name);
|
|
809
|
+
canvas.setColor(this.primaryCanvasRectangleId, "green");
|
|
810
|
+
canvas.setVisibility(this.primaryCanvasRectangleId, !this.hidden);
|
|
811
|
+
canvas.setSelectable(this.primaryCanvasRectangleId, true);
|
|
812
|
+
canvas.setResizable(this.primaryCanvasRectangleId, true);
|
|
813
|
+
canvas.setRectangleSize(this.primaryCanvasRectangleId, this.rect);
|
|
814
|
+
}
|
|
815
|
+
let thisOcrMatches = ocrMatches?.filter((e) => e.templateZoneId == this.id) ?? [];
|
|
816
|
+
let matchHash = this.hidden + "|" + thisOcrMatches.map((e) => `${e.ocrTextResultId}`).join(",") + "|" + this.children.map((e) => `${e.id}*${e.hidden}`).join(",");
|
|
817
|
+
if (matchHash === this.lastMatchHash) {
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
this.ocrOverlayIds.forEach((id) => canvas.removeObject(id));
|
|
821
|
+
this.lastMatchHash = matchHash;
|
|
822
|
+
let isFirstMatch = true;
|
|
823
|
+
for (const match of thisOcrMatches) {
|
|
824
|
+
if (isFirstMatch) {
|
|
825
|
+
this.example = match.processedText;
|
|
826
|
+
}
|
|
827
|
+
if (!this.hidden) {
|
|
828
|
+
this.ocrOverlayIds.push(canvas.addPolygon(match.polygonAbsolute.points, "rgba(0, 255, 0, 0.25)", false));
|
|
829
|
+
}
|
|
830
|
+
if (match.anchorPointAbsolute) {
|
|
831
|
+
if (!this.hidden) {
|
|
832
|
+
this.ocrOverlayIds.push(canvas.addCircle(match.anchorPointAbsolute, 2, "rgba(0, 0, 255, 0.25)", false, false));
|
|
833
|
+
}
|
|
834
|
+
if (!isFirstMatch) {
|
|
835
|
+
for (const child of this.children) {
|
|
836
|
+
if (child.hidden == false) {
|
|
837
|
+
let vector = this.currentAnchorPoint ? match.anchorPointAbsolute.getDeltaFromPoint(this.currentAnchorPoint) : new import_dytools_canvas_engine.Vector(0, 0);
|
|
838
|
+
let color = "rgba(128, 128, 255, 0.5)";
|
|
839
|
+
const polygon = child.rect.move(vector).toPolygon().points;
|
|
840
|
+
this.ocrOverlayIds.push(canvas.addPolygon(polygon, color, false));
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
if (this.currentAnchorPoint === null || isFirstMatch) {
|
|
845
|
+
this.currentAnchorPoint = match.anchorPointAbsolute;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
isFirstMatch = false;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
onChildZoneAdded(childZone) {
|
|
852
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneChildZoneAdded, { parentZone: this, newChildZone: childZone });
|
|
853
|
+
}
|
|
854
|
+
onChildZoneRemoved(childZone) {
|
|
855
|
+
this.emitToEngine(CaptureToEngineEventType.ZoneChildZoneRemoved, { parentZone: this, removedChildZone: childZone });
|
|
856
|
+
}
|
|
857
|
+
toExternal(docWidth, docHeight) {
|
|
858
|
+
return {
|
|
859
|
+
TemplateZoneId: this.id,
|
|
860
|
+
Name: this.name,
|
|
861
|
+
Type: "TemplateAnchorZone",
|
|
862
|
+
X: this.rect.origin.x / docWidth,
|
|
863
|
+
Y: this.rect.origin.y / docHeight,
|
|
864
|
+
Width: this.rect.size.width / docWidth,
|
|
865
|
+
Height: this.rect.size.height / docHeight,
|
|
866
|
+
XAbsolute: this.rect.origin.x,
|
|
867
|
+
YAbsolute: this.rect.origin.y,
|
|
868
|
+
WidthAbsolute: this.rect.size.width,
|
|
869
|
+
HeightAbsolute: this.rect.size.height,
|
|
870
|
+
RegExFilter: this.filterRegex,
|
|
871
|
+
RegExOutput: this.outputRegex,
|
|
872
|
+
RegExReplacement: this.outputReplacement,
|
|
873
|
+
Required: this.required,
|
|
874
|
+
DataType: this.dataType,
|
|
875
|
+
ExcludeFromOutput: this.excludeFromOutput,
|
|
876
|
+
DefaultValueIfEmpty: this.defaultValueIfEmpty,
|
|
877
|
+
AnchorLocation: this.anchorLocation,
|
|
878
|
+
AnchorLocationXAbsoluteHint: this.currentAnchorPoint?.x,
|
|
879
|
+
AnchorLocationYAbsoluteHint: this.currentAnchorPoint?.y,
|
|
880
|
+
GroupChildrenInSubRecord: this.groupChildren,
|
|
881
|
+
ChildZones: this.children.map((e) => e instanceof AnchorChildZone ? e.toExternalChild(docWidth, docHeight, this.currentAnchorPoint || this.rect.origin) : e.toExternal(docWidth, docHeight))
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
};
|
|
885
|
+
var DefaultZoneCanvasManager = class {
|
|
886
|
+
constructor(engine, zoneId) {
|
|
887
|
+
this.engine = engine;
|
|
888
|
+
this.zoneId = zoneId;
|
|
889
|
+
}
|
|
890
|
+
makeId(id) {
|
|
891
|
+
return `${this.zoneId}|${id}`;
|
|
892
|
+
}
|
|
893
|
+
makeUuid() {
|
|
894
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
895
|
+
return crypto.randomUUID();
|
|
896
|
+
}
|
|
897
|
+
const template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
|
|
898
|
+
return template.replace(/[xy]/g, (c) => {
|
|
899
|
+
const r = Math.random() * 16 | 0;
|
|
900
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
901
|
+
return v.toString(16);
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
clearAll() {
|
|
905
|
+
let allObjects = this.engine.getAllObjects();
|
|
906
|
+
for (const obj of allObjects) {
|
|
907
|
+
if (obj.id.startsWith(this.zoneId + "|")) {
|
|
908
|
+
this.engine.removeObject(obj.id);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
addRectangle(rect, name, color, isResizable, isSelectable) {
|
|
913
|
+
const extId = this.makeUuid();
|
|
914
|
+
const id = this.makeId(extId);
|
|
915
|
+
const obj = new import_dytools_canvas_engine.Zone(id, rect, color, isSelectable, isResizable, isResizable);
|
|
916
|
+
if (name != null) {
|
|
917
|
+
obj.name = name;
|
|
918
|
+
obj.showName = true;
|
|
919
|
+
}
|
|
920
|
+
this.engine.addObject(obj);
|
|
921
|
+
return extId;
|
|
922
|
+
}
|
|
923
|
+
addPolygon(points, color, isSelectable) {
|
|
924
|
+
const extId = this.makeUuid();
|
|
925
|
+
const id = this.makeId(extId);
|
|
926
|
+
const obj = new import_dytools_canvas_engine.PolygonObject(id, points, color, isSelectable, false);
|
|
927
|
+
this.engine.addObject(obj);
|
|
928
|
+
return extId;
|
|
929
|
+
}
|
|
930
|
+
addCircle(center, radius, color, isResizable, isSelectable) {
|
|
931
|
+
const extId = this.makeUuid();
|
|
932
|
+
const id = this.makeId(extId);
|
|
933
|
+
const obj = new import_dytools_canvas_engine.CircleObject(id, center, radius, color, isSelectable, isResizable);
|
|
934
|
+
this.engine.addObject(obj);
|
|
935
|
+
return extId;
|
|
936
|
+
}
|
|
937
|
+
setName(id, name) {
|
|
938
|
+
let canvasId = this.makeId(id);
|
|
939
|
+
const obj = this.engine.getObject(canvasId);
|
|
940
|
+
if (obj && obj instanceof import_dytools_canvas_engine.Zone) {
|
|
941
|
+
obj.name = name ?? "";
|
|
942
|
+
obj.showName = !!name;
|
|
943
|
+
this.engine.redraw();
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
setColor(id, color) {
|
|
947
|
+
let canvasId = this.makeId(id);
|
|
948
|
+
this.engine.setObjectColor(canvasId, color);
|
|
949
|
+
}
|
|
950
|
+
setSelectable(id, isSelectable) {
|
|
951
|
+
let canvasId = this.makeId(id);
|
|
952
|
+
const obj = this.engine.getObject(canvasId);
|
|
953
|
+
if (obj) {
|
|
954
|
+
this.engine.updateObjectSelectability(canvasId, isSelectable);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
setResizable(id, isResizable) {
|
|
958
|
+
let canvasId = this.makeId(id);
|
|
959
|
+
const obj = this.engine.getObject(canvasId);
|
|
960
|
+
if (obj && obj instanceof import_dytools_canvas_engine.Zone) {
|
|
961
|
+
this.engine.updateObjectResizeability(canvasId, isResizable);
|
|
962
|
+
this.engine.updateObjectMovability(canvasId, isResizable);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
setRectangleSize(id, rect) {
|
|
966
|
+
let canvasId = this.makeId(id);
|
|
967
|
+
const obj = this.engine.getObject(canvasId);
|
|
968
|
+
if (obj && obj instanceof import_dytools_canvas_engine.Zone) {
|
|
969
|
+
this.engine.moveObjectToPoint(obj, rect.origin);
|
|
970
|
+
this.engine.resizeObjectToSize(obj, rect.size);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
//
|
|
974
|
+
// setCircleSize(id: string, center: Point, radius: number): void {
|
|
975
|
+
// let canvasId = this.makeId(id);
|
|
976
|
+
// const obj = this.engine.getObject(canvasId);
|
|
977
|
+
// if (obj && obj instanceof CircleObject) {
|
|
978
|
+
// obj.center = center;
|
|
979
|
+
// obj.radius = radius;
|
|
980
|
+
// this.engine.redraw();
|
|
981
|
+
// }
|
|
982
|
+
// }
|
|
983
|
+
setVisibility(id, isVisible) {
|
|
984
|
+
let canvasId = this.makeId(id);
|
|
985
|
+
const obj = this.engine.getObject(canvasId);
|
|
986
|
+
if (obj) {
|
|
987
|
+
this.engine.updateObjectVisibility(canvasId, isVisible);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
removeObject(id) {
|
|
991
|
+
let canvasId = this.makeId(id);
|
|
992
|
+
this.engine.removeObject(canvasId);
|
|
993
|
+
}
|
|
994
|
+
};
|
|
995
|
+
var CaptureEngine = class {
|
|
996
|
+
constructor(selector, serverApi) {
|
|
997
|
+
this.listeners = {};
|
|
998
|
+
// Template properties
|
|
999
|
+
this._name = "Untitled";
|
|
1000
|
+
this.zones = [];
|
|
1001
|
+
// Zone+OCR properties
|
|
1002
|
+
this.ocrRead = null;
|
|
1003
|
+
this.zoneOcrMatches = [];
|
|
1004
|
+
this.ocrOverlayIds = [];
|
|
1005
|
+
// TODO: im not sure out this.
|
|
1006
|
+
this.flags = /* @__PURE__ */ new Map();
|
|
1007
|
+
// key = object id, value = set of flags
|
|
1008
|
+
// Refactor properties
|
|
1009
|
+
this.zoneCounter = 1;
|
|
1010
|
+
/* --- INTERNAL ENGINE EVENT METHODS --- */
|
|
1011
|
+
// These are used for messages to the engine itself (e.g. from a zone if the zone mutated.)
|
|
1012
|
+
this.refreshMatches = this.createMeteredFn(async () => {
|
|
1013
|
+
if (!this.serverApi || !this.ocrRead) return;
|
|
1014
|
+
const matches = await this.getZoneMatchesFromServer();
|
|
1015
|
+
this.setOcrMatchesSnapshot(matches);
|
|
1016
|
+
}, 1e3);
|
|
1017
|
+
this.engine = new import_dytools_canvas_engine.CanvasEngine(selector, {});
|
|
1018
|
+
if (serverApi) {
|
|
1019
|
+
this.setServerApi(serverApi);
|
|
1020
|
+
}
|
|
1021
|
+
const internalArray = [];
|
|
1022
|
+
const snapshotChildren = (arr) => {
|
|
1023
|
+
const map = /* @__PURE__ */ new Map();
|
|
1024
|
+
for (const c of arr) {
|
|
1025
|
+
if (!c) continue;
|
|
1026
|
+
map.set(c.id, c);
|
|
1027
|
+
}
|
|
1028
|
+
return map;
|
|
1029
|
+
};
|
|
1030
|
+
const applyChildrenDiff = (before, afterArr) => {
|
|
1031
|
+
const after = /* @__PURE__ */ new Map();
|
|
1032
|
+
for (const c of afterArr) {
|
|
1033
|
+
if (!c) continue;
|
|
1034
|
+
after.set(c.id, c);
|
|
1035
|
+
}
|
|
1036
|
+
for (const [id, child] of before.entries()) {
|
|
1037
|
+
if (!after.has(id)) {
|
|
1038
|
+
this.onZoneRemoved(child);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
for (const [id, child] of after.entries()) {
|
|
1042
|
+
if (!before.has(id)) {
|
|
1043
|
+
this.onZoneAdded(child);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
};
|
|
1047
|
+
this.zones = new Proxy(internalArray, {
|
|
1048
|
+
set: (target, property, value) => {
|
|
1049
|
+
const prop = String(property);
|
|
1050
|
+
const isIndex = !Number.isNaN(Number(prop));
|
|
1051
|
+
const isLength = prop === "length";
|
|
1052
|
+
const before = isIndex || isLength ? snapshotChildren(target) : null;
|
|
1053
|
+
const result = Reflect.set(target, property, value);
|
|
1054
|
+
if (before && (isIndex || isLength)) {
|
|
1055
|
+
applyChildrenDiff(before, target);
|
|
1056
|
+
}
|
|
1057
|
+
return result;
|
|
1058
|
+
},
|
|
1059
|
+
deleteProperty: (target, property) => {
|
|
1060
|
+
const isIndex = !Number.isNaN(Number(property));
|
|
1061
|
+
const before = isIndex ? snapshotChildren(target) : null;
|
|
1062
|
+
const result = Reflect.deleteProperty(target, property);
|
|
1063
|
+
if (isIndex && before) {
|
|
1064
|
+
applyChildrenDiff(before, target);
|
|
1065
|
+
}
|
|
1066
|
+
return result;
|
|
1067
|
+
}
|
|
1068
|
+
});
|
|
1069
|
+
Object.defineProperty(this, "zones", {
|
|
1070
|
+
writable: false,
|
|
1071
|
+
configurable: false
|
|
1072
|
+
});
|
|
1073
|
+
this.setupEngine();
|
|
1074
|
+
}
|
|
1075
|
+
// This is used to attach event handlers to the canvas engine (this.engine)
|
|
1076
|
+
// All zone-related events (like position changed, resized, etc.) will be sent to the zones and not externally.
|
|
1077
|
+
// All zones will listen to these events and update their internal state accordingly and send the completed event
|
|
1078
|
+
// to the CaptureEngine.
|
|
1079
|
+
setupEngine() {
|
|
1080
|
+
this.engine.on(import_dytools_canvas_engine.EngineEventType.ObjectPositionChanged, ({ object, oldPosition, newPosition }) => {
|
|
1081
|
+
let zone = this.getZoneByCanvasEngineId(object.id);
|
|
1082
|
+
if (zone) {
|
|
1083
|
+
this.emitToZone(zone.id, CaptureEngineToZoneEventType.CanvasObjectPositionChanged, { object, oldPosition, newPosition });
|
|
1084
|
+
}
|
|
1085
|
+
});
|
|
1086
|
+
this.engine.on(import_dytools_canvas_engine.EngineEventType.ObjectSelected, ({ object }) => {
|
|
1087
|
+
let zone = this.getZoneByCanvasEngineId(object.id);
|
|
1088
|
+
if (zone) {
|
|
1089
|
+
this.setFlag(zone, "selected", false);
|
|
1090
|
+
}
|
|
1091
|
+
});
|
|
1092
|
+
this.engine.on(import_dytools_canvas_engine.EngineEventType.ObjectDeselected, ({ object }) => {
|
|
1093
|
+
let zone = this.getZoneByCanvasEngineId(object.id);
|
|
1094
|
+
if (zone) {
|
|
1095
|
+
this.clearFlag(zone, "selected", false);
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
1098
|
+
this.engine.on(import_dytools_canvas_engine.EngineEventType.ViewportChanged, ({ newPan, newZoom, oldPan, oldZoom }) => {
|
|
1099
|
+
this.emitExternal(CapturePublicEventType.ViewportChanged, { newPan, newZoom, oldPan, oldZoom });
|
|
1100
|
+
});
|
|
1101
|
+
this.engine.on(import_dytools_canvas_engine.EngineEventType.DrawingCompleted, ({ rect, maxZ }) => {
|
|
1102
|
+
this.emitExternal(CapturePublicEventType.DrawingCompleted, { rect, maxZ });
|
|
1103
|
+
});
|
|
1104
|
+
this.engine.on(import_dytools_canvas_engine.EngineEventType.EngineStarted, () => {
|
|
1105
|
+
this.emitExternal(CapturePublicEventType.CaptureStarted, {});
|
|
1106
|
+
});
|
|
1107
|
+
this.engine.on(import_dytools_canvas_engine.EngineEventType.EngineError, ({ error, message }) => {
|
|
1108
|
+
this.emitExternal(CapturePublicEventType.CaptureError, { error, message });
|
|
1109
|
+
});
|
|
1110
|
+
this.engine.on(import_dytools_canvas_engine.EngineEventType.EngineBackgroundChanged, ({ newImage, newWidth, newHeight, oldWidth, oldHeight }) => {
|
|
1111
|
+
this.emitExternal(CapturePublicEventType.CaptureBackgroundChanged, { newImage: this.engine.documentBlob, newWidth, newHeight, oldWidth, oldHeight });
|
|
1112
|
+
});
|
|
1113
|
+
this.engine.on(import_dytools_canvas_engine.EngineEventType.EngineRenderStarted, () => {
|
|
1114
|
+
this.emitExternal(CapturePublicEventType.CaptureRenderStarted, {});
|
|
1115
|
+
this.doRender();
|
|
1116
|
+
});
|
|
1117
|
+
this.engine.on(import_dytools_canvas_engine.EngineEventType.EngineRenderCompleted, () => {
|
|
1118
|
+
this.emitExternal(CapturePublicEventType.CaptureRenderCompleted, {});
|
|
1119
|
+
});
|
|
1120
|
+
}
|
|
1121
|
+
/* --- PUBLIC/EXTERNAL EVENT METHODS --- */
|
|
1122
|
+
on(event, handler, options) {
|
|
1123
|
+
if (!this.listeners[event]) {
|
|
1124
|
+
this.listeners[event] = [];
|
|
1125
|
+
}
|
|
1126
|
+
if (options?.once) {
|
|
1127
|
+
const onceWrapper = (data) => {
|
|
1128
|
+
this.off(event, onceWrapper);
|
|
1129
|
+
handler(data);
|
|
1130
|
+
};
|
|
1131
|
+
this.listeners[event].push(onceWrapper);
|
|
1132
|
+
} else {
|
|
1133
|
+
this.listeners[event].push(handler);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
off(event, handler) {
|
|
1137
|
+
const handlers = this.listeners[event];
|
|
1138
|
+
if (!handlers) {
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1141
|
+
const idx = handlers.indexOf(handler);
|
|
1142
|
+
if (idx !== -1) {
|
|
1143
|
+
handlers.splice(idx, 1);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
// Only the engine should emit external events
|
|
1147
|
+
emitExternal(type, payload) {
|
|
1148
|
+
const handlers = this.listeners[type];
|
|
1149
|
+
handlers?.forEach((fn) => fn(payload));
|
|
1150
|
+
}
|
|
1151
|
+
/* --- INTERNAL ZONE EVENT METHODS --- */
|
|
1152
|
+
// These are used for messages to a zone. We send all events to all zones, so if a zone wants to monitor it's
|
|
1153
|
+
// children or another zone, it is able to.
|
|
1154
|
+
emitToZone(id, type, payload) {
|
|
1155
|
+
for (const zone of this.zones) {
|
|
1156
|
+
zone.handleEvent?.(id, type, payload);
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
engineEventHandler(type, payload) {
|
|
1160
|
+
if (type === CaptureToEngineEventType.ZoneChildZoneAdded) {
|
|
1161
|
+
const zoneChildZoneAddedPayload = payload;
|
|
1162
|
+
this.onZoneAdded(zoneChildZoneAddedPayload.newChildZone, zoneChildZoneAddedPayload.parentZone);
|
|
1163
|
+
}
|
|
1164
|
+
if (type === CaptureToEngineEventType.ZoneChildZoneRemoved) {
|
|
1165
|
+
const zoneChildZoneRemovedPayload = payload;
|
|
1166
|
+
this.onZoneRemoved(zoneChildZoneRemovedPayload.removedChildZone, zoneChildZoneRemovedPayload.parentZone);
|
|
1167
|
+
}
|
|
1168
|
+
if (type === CaptureToEngineEventType.ZoneNameChanged) {
|
|
1169
|
+
const zoneNameChangedPayload = payload;
|
|
1170
|
+
this.emitExternal(CapturePublicEventType.ZoneChanged, { zone: zoneNameChangedPayload.zone, propertiesChanged: ["name"] });
|
|
1171
|
+
}
|
|
1172
|
+
if (type === CaptureToEngineEventType.ZoneHiddenChanged) {
|
|
1173
|
+
const zoneHiddenChangedPayload = payload;
|
|
1174
|
+
this.emitExternal(CapturePublicEventType.ZoneChanged, { zone: zoneHiddenChangedPayload.zone, propertiesChanged: ["hidden"] });
|
|
1175
|
+
}
|
|
1176
|
+
if (type === CaptureToEngineEventType.ZoneExampleChanged) {
|
|
1177
|
+
const zoneExampleChangedPayload = payload;
|
|
1178
|
+
this.emitExternal(CapturePublicEventType.ZoneChanged, { zone: zoneExampleChangedPayload.zone, propertiesChanged: ["example"] });
|
|
1179
|
+
}
|
|
1180
|
+
if (type === CaptureToEngineEventType.ZonePositionChanged) {
|
|
1181
|
+
const zonePositionChangedPayload = payload;
|
|
1182
|
+
this.emitExternal(CapturePublicEventType.ZoneChanged, { zone: zonePositionChangedPayload.zone, propertiesChanged: ["rect"] });
|
|
1183
|
+
this.emitExternal(CapturePublicEventType.TemplateChanged, {});
|
|
1184
|
+
this.refreshMatches();
|
|
1185
|
+
}
|
|
1186
|
+
if (type === CaptureToEngineEventType.ZoneFilterRegexChanged) {
|
|
1187
|
+
const zoneFilterRegexChangedPayload = payload;
|
|
1188
|
+
this.emitExternal(CapturePublicEventType.ZoneChanged, { zone: zoneFilterRegexChangedPayload.zone, propertiesChanged: ["filterRegex"] });
|
|
1189
|
+
this.emitExternal(CapturePublicEventType.TemplateChanged, {});
|
|
1190
|
+
this.refreshMatches();
|
|
1191
|
+
}
|
|
1192
|
+
if (type === CaptureToEngineEventType.ZoneOutputRegexChanged) {
|
|
1193
|
+
const zoneOutputRegexChangedPayload = payload;
|
|
1194
|
+
this.emitExternal(CapturePublicEventType.ZoneChanged, { zone: zoneOutputRegexChangedPayload.zone, propertiesChanged: ["outputRegex"] });
|
|
1195
|
+
this.emitExternal(CapturePublicEventType.TemplateChanged, {});
|
|
1196
|
+
this.refreshMatches();
|
|
1197
|
+
}
|
|
1198
|
+
if (type === CaptureToEngineEventType.ZoneOutputReplacementChanged) {
|
|
1199
|
+
const zoneOutputReplacementChangedPayload = payload;
|
|
1200
|
+
this.emitExternal(CapturePublicEventType.ZoneChanged, { zone: zoneOutputReplacementChangedPayload.zone, propertiesChanged: ["outputReplacement"] });
|
|
1201
|
+
this.emitExternal(CapturePublicEventType.TemplateChanged, {});
|
|
1202
|
+
this.refreshMatches();
|
|
1203
|
+
}
|
|
1204
|
+
if (type === CaptureToEngineEventType.ZoneRequiredChanged) {
|
|
1205
|
+
const zoneRequiredChangedPayload = payload;
|
|
1206
|
+
this.emitExternal(CapturePublicEventType.ZoneChanged, { zone: zoneRequiredChangedPayload.zone, propertiesChanged: ["required"] });
|
|
1207
|
+
this.emitExternal(CapturePublicEventType.TemplateChanged, {});
|
|
1208
|
+
}
|
|
1209
|
+
if (type === CaptureToEngineEventType.ZoneDataTypeChanged) {
|
|
1210
|
+
const zoneDataTypeChangedPayload = payload;
|
|
1211
|
+
this.emitExternal(CapturePublicEventType.ZoneChanged, { zone: zoneDataTypeChangedPayload.zone, propertiesChanged: ["dataType"] });
|
|
1212
|
+
this.emitExternal(CapturePublicEventType.TemplateChanged, {});
|
|
1213
|
+
}
|
|
1214
|
+
if (type === CaptureToEngineEventType.ZoneExcludeFromOutputChanged) {
|
|
1215
|
+
const zoneExcludeFromOutputChangedPayload = payload;
|
|
1216
|
+
this.emitExternal(CapturePublicEventType.ZoneChanged, { zone: zoneExcludeFromOutputChangedPayload.zone, propertiesChanged: ["excludeFromOutput"] });
|
|
1217
|
+
this.emitExternal(CapturePublicEventType.TemplateChanged, {});
|
|
1218
|
+
}
|
|
1219
|
+
if (type === CaptureToEngineEventType.ZoneDefaultValueIfEmptyChanged) {
|
|
1220
|
+
const zoneDefaultValueIfEmptyChangedPayload = payload;
|
|
1221
|
+
this.emitExternal(CapturePublicEventType.ZoneChanged, { zone: zoneDefaultValueIfEmptyChangedPayload.zone, propertiesChanged: ["defaultValueIfEmpty"] });
|
|
1222
|
+
this.emitExternal(CapturePublicEventType.TemplateChanged, {});
|
|
1223
|
+
}
|
|
1224
|
+
if (type === CaptureToEngineEventType.ZoneAnchorLocationChanged) {
|
|
1225
|
+
const zoneAnchorLocationChangedPayload = payload;
|
|
1226
|
+
this.emitExternal(CapturePublicEventType.ZoneChanged, { zone: zoneAnchorLocationChangedPayload.zone, propertiesChanged: ["anchorLocation"] });
|
|
1227
|
+
this.emitExternal(CapturePublicEventType.TemplateChanged, {});
|
|
1228
|
+
this.refreshMatches();
|
|
1229
|
+
}
|
|
1230
|
+
if (type === CaptureToEngineEventType.ZoneGroupChildrenChanged) {
|
|
1231
|
+
const zoneGroupChildrenChangedPayload = payload;
|
|
1232
|
+
this.emitExternal(CapturePublicEventType.ZoneChanged, { zone: zoneGroupChildrenChangedPayload.zone, propertiesChanged: ["groupChildren"] });
|
|
1233
|
+
this.emitExternal(CapturePublicEventType.TemplateChanged, {});
|
|
1234
|
+
this.refreshMatches();
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
onZoneAdded(zone, parentZone, excludeOcrMatches = false) {
|
|
1238
|
+
zone.setEngineEventSink?.(
|
|
1239
|
+
(type, payload) => this.engineEventHandler(type, payload)
|
|
1240
|
+
);
|
|
1241
|
+
const canvasManager = new DefaultZoneCanvasManager(this.engine, zone.id);
|
|
1242
|
+
zone.setCanvasManager?.(canvasManager);
|
|
1243
|
+
this.emitExternal(CapturePublicEventType.ZoneAdded, { newZone: zone, parentZone, isChildZone: parentZone !== void 0 });
|
|
1244
|
+
if (zone.children) {
|
|
1245
|
+
for (const child of zone.children) {
|
|
1246
|
+
this.onZoneAdded(child, zone, true);
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
if (!excludeOcrMatches) {
|
|
1250
|
+
this.refreshMatches();
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
onZoneRemoved(zone, parentZone) {
|
|
1254
|
+
zone.setEngineEventSink?.();
|
|
1255
|
+
this.flags.delete(zone.id);
|
|
1256
|
+
this.emitExternal(CapturePublicEventType.ZoneRemoved, { id: zone.id, removedZone: zone, parentZone, isChildZone: parentZone !== void 0 });
|
|
1257
|
+
this.refreshMatches();
|
|
1258
|
+
}
|
|
1259
|
+
/* --- ENGINE HELPERS --- */
|
|
1260
|
+
// This will return a TemplateZoneBase for a given canvas engine id.
|
|
1261
|
+
getZoneByCanvasEngineId(id) {
|
|
1262
|
+
const parts = id.split("|");
|
|
1263
|
+
if (parts.length !== 2) return void 0;
|
|
1264
|
+
const zoneId = parts[0];
|
|
1265
|
+
return this.allZonesFlattened.find((z) => z.id === zoneId);
|
|
1266
|
+
}
|
|
1267
|
+
doRender() {
|
|
1268
|
+
for (const zone of this.allZonesFlattened) {
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
// ---- metered wrapper ----
|
|
1272
|
+
createMeteredFn(fn, minIntervalMs = 1e3) {
|
|
1273
|
+
let lastExec = 0;
|
|
1274
|
+
let running = false;
|
|
1275
|
+
let queued = false;
|
|
1276
|
+
const invoke = () => {
|
|
1277
|
+
const now = Date.now();
|
|
1278
|
+
const elapsed = now - lastExec;
|
|
1279
|
+
if (running) {
|
|
1280
|
+
queued = true;
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
1283
|
+
if (elapsed < minIntervalMs) {
|
|
1284
|
+
if (!queued) {
|
|
1285
|
+
queued = true;
|
|
1286
|
+
const delay = minIntervalMs - elapsed;
|
|
1287
|
+
setTimeout(() => {
|
|
1288
|
+
queued = false;
|
|
1289
|
+
invoke();
|
|
1290
|
+
}, delay);
|
|
1291
|
+
}
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
running = true;
|
|
1295
|
+
lastExec = now;
|
|
1296
|
+
Promise.resolve(fn()).finally(() => {
|
|
1297
|
+
running = false;
|
|
1298
|
+
if (queued) {
|
|
1299
|
+
queued = false;
|
|
1300
|
+
invoke();
|
|
1301
|
+
}
|
|
1302
|
+
});
|
|
1303
|
+
};
|
|
1304
|
+
return invoke;
|
|
1305
|
+
}
|
|
1306
|
+
/* --- TEMPLATE METHODS --- */
|
|
1307
|
+
loadExternalTemplate(external, reapplyZonePositioning) {
|
|
1308
|
+
const docWidth = reapplyZonePositioning ? this.width : external.DocumentWidth ?? this.width;
|
|
1309
|
+
const docHeight = reapplyZonePositioning ? this.height : external.DocumentHeight ?? this.height;
|
|
1310
|
+
if (docWidth != this.width) {
|
|
1311
|
+
console.warn("Document width mismatch, resizing canvas to match. Template width: ", docWidth, "Canvas width: ", this.width);
|
|
1312
|
+
}
|
|
1313
|
+
if (docHeight != this.height) {
|
|
1314
|
+
console.warn("Document height mismatch, resizing canvas to match. Template height: ", docHeight, "Canvas height: ", this.height);
|
|
1315
|
+
}
|
|
1316
|
+
this._name = external.Name ?? "Untitled";
|
|
1317
|
+
for (const z of this.allZonesFlattened) {
|
|
1318
|
+
z.setEngineEventSink?.();
|
|
1319
|
+
z.setCanvasManager?.();
|
|
1320
|
+
}
|
|
1321
|
+
this.engine.getAllObjects().forEach((e) => this.engine.removeObject(e));
|
|
1322
|
+
this.zones.length = 0;
|
|
1323
|
+
for (const z of external.Zones) {
|
|
1324
|
+
const zone = this.zoneFromExternal(z, docWidth, docHeight);
|
|
1325
|
+
this.zones.push(zone);
|
|
1326
|
+
}
|
|
1327
|
+
this.refreshMatches();
|
|
1328
|
+
}
|
|
1329
|
+
getExternalTemplate() {
|
|
1330
|
+
const docWidth = this.width;
|
|
1331
|
+
const docHeight = this.height;
|
|
1332
|
+
this.getOcrMatchesSnapshot();
|
|
1333
|
+
console.log(this.zones.filter((e) => e.name == "Anchor 1").map((e) => {
|
|
1334
|
+
let extParent = e.toExternal(docWidth, docHeight);
|
|
1335
|
+
if (extParent.ChildZones && extParent.ChildZones.length > 0) {
|
|
1336
|
+
let ext = extParent.ChildZones[0];
|
|
1337
|
+
return { x: ext.X, y: ext.Y, width: ext.Width, height: ext.Height };
|
|
1338
|
+
} else {
|
|
1339
|
+
return "no child";
|
|
1340
|
+
}
|
|
1341
|
+
}));
|
|
1342
|
+
return {
|
|
1343
|
+
Name: this._name ?? "Untitled",
|
|
1344
|
+
DocumentWidth: docWidth,
|
|
1345
|
+
DocumentHeight: docHeight,
|
|
1346
|
+
Zones: this.zones.map((e) => e.toExternal(docWidth, docHeight))
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1349
|
+
// --- in CaptureEngine.ts (or a new file) ---
|
|
1350
|
+
rectFromExternal(z, docW, docH) {
|
|
1351
|
+
return new import_dytools_canvas_engine.Rectangle(
|
|
1352
|
+
z.X * docW,
|
|
1353
|
+
z.Y * docH,
|
|
1354
|
+
z.Width * docW,
|
|
1355
|
+
z.Height * docH
|
|
1356
|
+
);
|
|
1357
|
+
}
|
|
1358
|
+
zoneFromExternal(z, docW, docH, parentAnchorAbs) {
|
|
1359
|
+
if (z.Type === "TemplateAnchorZone" && (!parentAnchorAbs && z.ChildZones)) {
|
|
1360
|
+
const anchor = new AnchorZone(
|
|
1361
|
+
z.Name,
|
|
1362
|
+
this.rectFromExternal(z, docW, docH),
|
|
1363
|
+
false,
|
|
1364
|
+
z.RegExFilter ?? null,
|
|
1365
|
+
z.RegExOutput ?? null,
|
|
1366
|
+
z.RegExReplacement ?? null,
|
|
1367
|
+
z.Required ?? false,
|
|
1368
|
+
z.DataType ?? null,
|
|
1369
|
+
z.ExcludeFromOutput ?? false,
|
|
1370
|
+
z.DefaultValueIfEmpty ?? null
|
|
1371
|
+
);
|
|
1372
|
+
if (z.AnchorLocation) anchor.anchorLocation = z.AnchorLocation;
|
|
1373
|
+
if (z.GroupChildrenInSubRecord !== void 0) anchor.groupChildren = z.GroupChildrenInSubRecord;
|
|
1374
|
+
const anchorPoint = anchor.rect.origin;
|
|
1375
|
+
for (const childDto of z.ChildZones ?? []) {
|
|
1376
|
+
const child = this.zoneFromExternal(childDto, docW, docH, anchorPoint);
|
|
1377
|
+
child.needsAnchorReposition = true;
|
|
1378
|
+
anchor.children.push(child);
|
|
1379
|
+
}
|
|
1380
|
+
return anchor;
|
|
1381
|
+
}
|
|
1382
|
+
if (parentAnchorAbs) {
|
|
1383
|
+
const absX = parentAnchorAbs.x / docW + z.X;
|
|
1384
|
+
const absY = parentAnchorAbs.y / docH + z.Y;
|
|
1385
|
+
const childRect = new import_dytools_canvas_engine.Rectangle(
|
|
1386
|
+
absX * docW,
|
|
1387
|
+
absY * docH,
|
|
1388
|
+
z.Width * docW,
|
|
1389
|
+
z.Height * docH
|
|
1390
|
+
);
|
|
1391
|
+
return new AnchorChildZone(
|
|
1392
|
+
z.Name,
|
|
1393
|
+
childRect,
|
|
1394
|
+
false,
|
|
1395
|
+
z.RegExFilter ?? null,
|
|
1396
|
+
z.RegExOutput ?? null,
|
|
1397
|
+
z.RegExReplacement ?? null,
|
|
1398
|
+
z.Required ?? false,
|
|
1399
|
+
z.DataType ?? null,
|
|
1400
|
+
z.ExcludeFromOutput ?? false,
|
|
1401
|
+
z.DefaultValueIfEmpty ?? null
|
|
1402
|
+
);
|
|
1403
|
+
}
|
|
1404
|
+
return new SimpleZone(
|
|
1405
|
+
z.Name,
|
|
1406
|
+
this.rectFromExternal(z, docW, docH),
|
|
1407
|
+
false,
|
|
1408
|
+
z.RegExFilter ?? null,
|
|
1409
|
+
z.RegExOutput ?? null,
|
|
1410
|
+
z.RegExReplacement ?? null,
|
|
1411
|
+
z.Required ?? false,
|
|
1412
|
+
z.DataType ?? null,
|
|
1413
|
+
z.ExcludeFromOutput ?? false,
|
|
1414
|
+
z.DefaultValueIfEmpty ?? null
|
|
1415
|
+
);
|
|
1416
|
+
}
|
|
1417
|
+
get name() {
|
|
1418
|
+
return this._name;
|
|
1419
|
+
}
|
|
1420
|
+
set name(value) {
|
|
1421
|
+
if (this._name === value) return;
|
|
1422
|
+
this._name = value;
|
|
1423
|
+
this.emitExternal(CapturePublicEventType.TemplateChanged, {});
|
|
1424
|
+
}
|
|
1425
|
+
/* --- ZONE METHODS --- */
|
|
1426
|
+
get allZonesFlattened() {
|
|
1427
|
+
return this.zones.map((e) => [e].concat(e.children ?? [])).flat();
|
|
1428
|
+
}
|
|
1429
|
+
getZoneById(id) {
|
|
1430
|
+
return this.allZonesFlattened.find((z) => z.id === id);
|
|
1431
|
+
}
|
|
1432
|
+
/**
|
|
1433
|
+
* Add a new simple zone
|
|
1434
|
+
* @param bounds Rectangle
|
|
1435
|
+
*/
|
|
1436
|
+
addSimpleZone(bounds) {
|
|
1437
|
+
let newZone = new SimpleZone("Test1", bounds, false, null, null, null);
|
|
1438
|
+
this.zones.push(newZone);
|
|
1439
|
+
}
|
|
1440
|
+
/**
|
|
1441
|
+
* Add a new anchor zone
|
|
1442
|
+
* @param bounds Rectangle
|
|
1443
|
+
*/
|
|
1444
|
+
addAnchorZone(bounds) {
|
|
1445
|
+
let newZone = new AnchorZone(`Anchor ${this.zoneCounter++}`, bounds, false, null, null, null);
|
|
1446
|
+
this.zones.push(newZone);
|
|
1447
|
+
}
|
|
1448
|
+
/**
|
|
1449
|
+
* Add a child zone linked to an anchor
|
|
1450
|
+
* @param anchorId string
|
|
1451
|
+
* @param bounds Rectangle
|
|
1452
|
+
*/
|
|
1453
|
+
addAnchorChildZone(anchorId, bounds) {
|
|
1454
|
+
const anchorZone = this.zones.find((z) => z.id === anchorId);
|
|
1455
|
+
if (!anchorZone) return;
|
|
1456
|
+
let newZone = new AnchorChildZone(`Child ${this.zoneCounter++}`, bounds, false, null, null, null);
|
|
1457
|
+
if (!anchorZone.children) anchorZone.children = [];
|
|
1458
|
+
anchorZone.children.push(newZone);
|
|
1459
|
+
}
|
|
1460
|
+
/**
|
|
1461
|
+
* Remove a zone and its canvas representation by id
|
|
1462
|
+
* @param id string
|
|
1463
|
+
*/
|
|
1464
|
+
removeZoneById(id) {
|
|
1465
|
+
const idx = this.zones.findIndex((z) => z.id === id);
|
|
1466
|
+
if (idx === -1) {
|
|
1467
|
+
let found = false;
|
|
1468
|
+
for (const zone of this.zones) {
|
|
1469
|
+
if (!zone.children) {
|
|
1470
|
+
continue;
|
|
1471
|
+
}
|
|
1472
|
+
const childIdx = zone.children.findIndex((z) => z.id === id);
|
|
1473
|
+
if (childIdx === -1) {
|
|
1474
|
+
continue;
|
|
1475
|
+
}
|
|
1476
|
+
found = true;
|
|
1477
|
+
let childZone = zone.children[childIdx];
|
|
1478
|
+
childZone.setEngineEventSink?.();
|
|
1479
|
+
childZone.setCanvasManager?.();
|
|
1480
|
+
this.engine.getAllObjects().filter((e) => e.id.startsWith(childZone.id)).forEach((e) => this.engine.removeObject(e));
|
|
1481
|
+
zone.children.splice(idx, 1);
|
|
1482
|
+
}
|
|
1483
|
+
return found;
|
|
1484
|
+
}
|
|
1485
|
+
let thisZone = this.zones[idx];
|
|
1486
|
+
thisZone.setEngineEventSink?.();
|
|
1487
|
+
thisZone.setCanvasManager?.();
|
|
1488
|
+
this.engine.getAllObjects().filter((e) => e.id.startsWith(thisZone.id)).forEach((e) => this.engine.removeObject(e));
|
|
1489
|
+
this.zones.splice(idx, 1);
|
|
1490
|
+
return true;
|
|
1491
|
+
}
|
|
1492
|
+
updateZone(id, patch) {
|
|
1493
|
+
const zone = this.allZonesFlattened.find((z) => z.id === id);
|
|
1494
|
+
if (!zone) {
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1497
|
+
if (patch.name !== void 0) {
|
|
1498
|
+
zone.name = patch.name;
|
|
1499
|
+
}
|
|
1500
|
+
if (patch.hidden !== void 0) {
|
|
1501
|
+
zone.hidden = patch.hidden;
|
|
1502
|
+
}
|
|
1503
|
+
if (patch.required !== void 0) {
|
|
1504
|
+
zone.required = patch.required;
|
|
1505
|
+
}
|
|
1506
|
+
if (patch.dataType !== void 0) {
|
|
1507
|
+
zone.dataType = patch.dataType;
|
|
1508
|
+
}
|
|
1509
|
+
if (patch.defaultValueIfEmpty !== void 0) {
|
|
1510
|
+
zone.defaultValueIfEmpty = patch.defaultValueIfEmpty;
|
|
1511
|
+
}
|
|
1512
|
+
if (patch.excludeFromOutput !== void 0) {
|
|
1513
|
+
zone.excludeFromOutput = patch.excludeFromOutput;
|
|
1514
|
+
}
|
|
1515
|
+
if (patch.filterRegex !== void 0) {
|
|
1516
|
+
zone.filterRegex = patch.filterRegex;
|
|
1517
|
+
}
|
|
1518
|
+
if (patch.outputRegex !== void 0) {
|
|
1519
|
+
zone.outputRegex = patch.outputRegex;
|
|
1520
|
+
}
|
|
1521
|
+
if (patch.outputReplacement !== void 0) {
|
|
1522
|
+
zone.outputReplacement = patch.outputReplacement;
|
|
1523
|
+
}
|
|
1524
|
+
if (patch.anchorLocation !== void 0) {
|
|
1525
|
+
zone.anchorLocation = patch.anchorLocation;
|
|
1526
|
+
}
|
|
1527
|
+
if (patch.groupChildren !== void 0) {
|
|
1528
|
+
zone.groupChildren = patch.groupChildren;
|
|
1529
|
+
}
|
|
1530
|
+
if (patch.rect) {
|
|
1531
|
+
const b = patch.rect;
|
|
1532
|
+
if (b instanceof import_dytools_canvas_engine.Rectangle) {
|
|
1533
|
+
zone.rect = b.clone();
|
|
1534
|
+
} else if (b.origin && b.size) {
|
|
1535
|
+
zone.rect = new import_dytools_canvas_engine.Rectangle(
|
|
1536
|
+
b.origin.x,
|
|
1537
|
+
b.origin.y,
|
|
1538
|
+
b.size.width,
|
|
1539
|
+
b.size.height
|
|
1540
|
+
);
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
/* --- FLAG MANAGEMENT --- */
|
|
1545
|
+
setFlag(objOrId, flag, emitToCanvasEngine) {
|
|
1546
|
+
const obj = typeof objOrId === "string" ? this.allZonesFlattened.find((o) => o.id === objOrId) : objOrId;
|
|
1547
|
+
if (!obj) throw new Error(`Zone not found: ${objOrId}`);
|
|
1548
|
+
const id = typeof objOrId === "string" ? objOrId : objOrId.id;
|
|
1549
|
+
if (!this.flags.has(id)) this.flags.set(id, /* @__PURE__ */ new Set());
|
|
1550
|
+
let currentFlags = this.flags.get(id);
|
|
1551
|
+
if (currentFlags.has(flag)) {
|
|
1552
|
+
return;
|
|
1553
|
+
}
|
|
1554
|
+
currentFlags.add(flag);
|
|
1555
|
+
this.emitToZone(id, CaptureEngineToZoneEventType.ZoneFlagsAdded, {
|
|
1556
|
+
addedFlags: [flag],
|
|
1557
|
+
currentFlags: [...this.flags.get(id)]
|
|
1558
|
+
});
|
|
1559
|
+
this.emitExternal(CapturePublicEventType.ZoneFlagsAdded, {
|
|
1560
|
+
zone: obj,
|
|
1561
|
+
addedFlags: [flag],
|
|
1562
|
+
currentFlags: [...this.flags.get(id)]
|
|
1563
|
+
});
|
|
1564
|
+
if (flag === "selected") {
|
|
1565
|
+
this.emitToZone(id, CaptureEngineToZoneEventType.ZoneSelected, { zone: obj });
|
|
1566
|
+
this.emitExternal(CapturePublicEventType.ZoneSelected, { zone: obj });
|
|
1567
|
+
if (emitToCanvasEngine) {
|
|
1568
|
+
this.engine.getAllObjects().filter((e) => e.id.startsWith(id) && e.selectable).forEach((e) => this.engine.setFlag(e.id, flag));
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
clearFlag(objOrId, flag, emitToCanvasEngine) {
|
|
1573
|
+
const obj = typeof objOrId === "string" ? this.allZonesFlattened.find((o) => o.id === objOrId) : objOrId;
|
|
1574
|
+
if (!obj) throw new Error(`Zone not found: ${objOrId}`);
|
|
1575
|
+
const id = typeof objOrId === "string" ? objOrId : objOrId.id;
|
|
1576
|
+
this.flags.get(id)?.delete(flag);
|
|
1577
|
+
this.emitToZone(id, CaptureEngineToZoneEventType.ZoneFlagsRemoved, {
|
|
1578
|
+
removedFlags: [flag],
|
|
1579
|
+
currentFlags: [...this.flags.get(id)]
|
|
1580
|
+
});
|
|
1581
|
+
this.emitExternal(CapturePublicEventType.ZoneFlagsRemoved, {
|
|
1582
|
+
zone: obj,
|
|
1583
|
+
removedFlags: [flag],
|
|
1584
|
+
currentFlags: [...this.flags.get(id) || []]
|
|
1585
|
+
});
|
|
1586
|
+
if (flag === "selected") {
|
|
1587
|
+
this.emitToZone(id, CaptureEngineToZoneEventType.ZoneDeselected, { zone: obj });
|
|
1588
|
+
this.emitExternal(CapturePublicEventType.ZoneDeselected, { zone: obj });
|
|
1589
|
+
if (flag === "selected") {
|
|
1590
|
+
this.emitToZone(id, CaptureEngineToZoneEventType.ZoneSelected, { zone: obj });
|
|
1591
|
+
this.emitExternal(CapturePublicEventType.ZoneSelected, { zone: obj });
|
|
1592
|
+
if (emitToCanvasEngine) {
|
|
1593
|
+
this.engine.getAllObjects().filter((e) => e.id.startsWith(id) && e.selectable).forEach((e) => this.engine.clearFlag(e.id, flag));
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
// noinspection JSUnusedGlobalSymbols
|
|
1599
|
+
hasFlag(objOrId, flag) {
|
|
1600
|
+
const id = typeof objOrId === "string" ? objOrId : objOrId.id;
|
|
1601
|
+
return this.flags.get(id)?.has(flag) ?? false;
|
|
1602
|
+
}
|
|
1603
|
+
// noinspection JSUnusedGlobalSymbols
|
|
1604
|
+
clearAllFlags(flag) {
|
|
1605
|
+
for (const [id, flags] of this.flags.entries()) {
|
|
1606
|
+
const obj = this.allZonesFlattened.find((o) => o.id === id) ?? null;
|
|
1607
|
+
if (!obj) throw new Error(`Zone not found: ${id}`);
|
|
1608
|
+
flags.delete(flag);
|
|
1609
|
+
this.emitToZone(id, CaptureEngineToZoneEventType.ZoneFlagsRemoved, {
|
|
1610
|
+
removedFlags: [flag],
|
|
1611
|
+
currentFlags: [...this.flags.get(id)]
|
|
1612
|
+
});
|
|
1613
|
+
this.emitExternal(CapturePublicEventType.ZoneFlagsRemoved, {
|
|
1614
|
+
zone: obj,
|
|
1615
|
+
removedFlags: [flag],
|
|
1616
|
+
currentFlags: [...this.flags.get(id) || []]
|
|
1617
|
+
});
|
|
1618
|
+
if (flag === "selected") {
|
|
1619
|
+
this.emitToZone(id, CaptureEngineToZoneEventType.ZoneDeselected, { zone: obj });
|
|
1620
|
+
this.emitExternal(CapturePublicEventType.ZoneDeselected, { zone: obj });
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
getObjectsWithFlag(flag) {
|
|
1625
|
+
return [...this.flags.entries()].filter(([_, flags]) => flags.has(flag)).map(([id]) => this.allZonesFlattened.find((o) => o.id === id)).filter((z) => z !== void 0);
|
|
1626
|
+
}
|
|
1627
|
+
/* --- SELECTION MANAGEMENT --- */
|
|
1628
|
+
setSelectedZones(objOrIds) {
|
|
1629
|
+
let objs = objOrIds.map((objOrId) => typeof objOrId === "string" ? this.allZonesFlattened.find((o) => o.id === objOrId) : objOrId);
|
|
1630
|
+
const currentSelected = this.getSelectedZones();
|
|
1631
|
+
const toDeselect = currentSelected.filter((o) => !objs.includes(o));
|
|
1632
|
+
const toSelect = objs.filter((o) => !currentSelected.includes(o));
|
|
1633
|
+
toDeselect.forEach((o) => this.clearFlag(o, "selected", true));
|
|
1634
|
+
toSelect.forEach((o) => this.setFlag(o, "selected", true));
|
|
1635
|
+
}
|
|
1636
|
+
getSelectedZones() {
|
|
1637
|
+
return this.getObjectsWithFlag("selected");
|
|
1638
|
+
}
|
|
1639
|
+
/* --- ENGINE API --- */
|
|
1640
|
+
// noinspection JSUnusedGlobalSymbols
|
|
1641
|
+
get pan() {
|
|
1642
|
+
return this.engine.pan;
|
|
1643
|
+
}
|
|
1644
|
+
get zoom() {
|
|
1645
|
+
return this.engine.zoom;
|
|
1646
|
+
}
|
|
1647
|
+
setZoom(zoom, center) {
|
|
1648
|
+
this.engine.setZoom(zoom, center);
|
|
1649
|
+
}
|
|
1650
|
+
// noinspection JSUnusedGlobalSymbols
|
|
1651
|
+
setPan(x, y) {
|
|
1652
|
+
this.engine.setPan(x, y);
|
|
1653
|
+
}
|
|
1654
|
+
get width() {
|
|
1655
|
+
return this.engine.width;
|
|
1656
|
+
}
|
|
1657
|
+
get height() {
|
|
1658
|
+
return this.engine.height;
|
|
1659
|
+
}
|
|
1660
|
+
async setBackgroundImage(imageOrUrl) {
|
|
1661
|
+
this.hideOcr();
|
|
1662
|
+
let preWidth = this.width;
|
|
1663
|
+
let preHeight = this.height;
|
|
1664
|
+
await this.engine.setBackgroundImage(imageOrUrl);
|
|
1665
|
+
if (preWidth !== this.width || preHeight !== this.height) {
|
|
1666
|
+
this.emitExternal(CapturePublicEventType.TemplateChanged, {});
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
switchMode(name) {
|
|
1670
|
+
this.engine.switchMode(name);
|
|
1671
|
+
}
|
|
1672
|
+
get mode() {
|
|
1673
|
+
return this.engine.mode;
|
|
1674
|
+
}
|
|
1675
|
+
/* --- OCR --- */
|
|
1676
|
+
/**
|
|
1677
|
+
* Render the current OCR snapshot as non-interactive polygons on the canvas.
|
|
1678
|
+
*/
|
|
1679
|
+
showOcr() {
|
|
1680
|
+
if (!this.ocrRead || !this.ocrRead.lines || this.ocrRead.lines.length === 0) {
|
|
1681
|
+
return;
|
|
1682
|
+
}
|
|
1683
|
+
this.hideOcr();
|
|
1684
|
+
const allObjects = this.engine.getAllObjects();
|
|
1685
|
+
let maxZ = 0;
|
|
1686
|
+
for (const obj of allObjects) {
|
|
1687
|
+
const z = obj.zIndex ?? 0;
|
|
1688
|
+
if (z > maxZ) {
|
|
1689
|
+
maxZ = z;
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
let currentZ = maxZ + 1;
|
|
1693
|
+
for (const word of this.ocrRead.lines) {
|
|
1694
|
+
const pts = word.polygonPercent.points.map(
|
|
1695
|
+
(p) => (
|
|
1696
|
+
//(typeof (p as any).clone === 'function')
|
|
1697
|
+
//? (p as any).clone() :
|
|
1698
|
+
new import_dytools_canvas_engine.Point(p.x * this.width, p.y * this.height)
|
|
1699
|
+
)
|
|
1700
|
+
);
|
|
1701
|
+
const overlayId = `ocr-${word.ocrTextResultId}`;
|
|
1702
|
+
const overlay = new import_dytools_canvas_engine.PolygonObject(
|
|
1703
|
+
overlayId,
|
|
1704
|
+
pts,
|
|
1705
|
+
"rgba(0, 128, 255, 0.25)",
|
|
1706
|
+
false,
|
|
1707
|
+
// isSelectable
|
|
1708
|
+
false,
|
|
1709
|
+
// isMovable
|
|
1710
|
+
currentZ++
|
|
1711
|
+
);
|
|
1712
|
+
this.engine.addObject(overlay);
|
|
1713
|
+
this.ocrOverlayIds.push(overlayId);
|
|
1714
|
+
}
|
|
1715
|
+
this.emitExternal(CapturePublicEventType.OcrShown, {});
|
|
1716
|
+
}
|
|
1717
|
+
/**
|
|
1718
|
+
* Remove OCR overlay polygons from the canvas.
|
|
1719
|
+
*/
|
|
1720
|
+
hideOcr() {
|
|
1721
|
+
if (!this.ocrOverlayIds || this.ocrOverlayIds.length === 0) {
|
|
1722
|
+
return;
|
|
1723
|
+
}
|
|
1724
|
+
for (const id of this.ocrOverlayIds) {
|
|
1725
|
+
this.engine.removeObject(id);
|
|
1726
|
+
}
|
|
1727
|
+
this.ocrOverlayIds = [];
|
|
1728
|
+
this.emitExternal(CapturePublicEventType.OcrHidden, {});
|
|
1729
|
+
}
|
|
1730
|
+
get isOcrShown() {
|
|
1731
|
+
return this.ocrOverlayIds.length > 0;
|
|
1732
|
+
}
|
|
1733
|
+
setOcrSnapshot(ocrRead) {
|
|
1734
|
+
this.ocrRead = ocrRead;
|
|
1735
|
+
this.emitExternal(CapturePublicEventType.OcrReadLoaded, { ocr: ocrRead });
|
|
1736
|
+
}
|
|
1737
|
+
// noinspection JSUnusedGlobalSymbols
|
|
1738
|
+
getOcrSnapshot() {
|
|
1739
|
+
return this.ocrRead;
|
|
1740
|
+
}
|
|
1741
|
+
setOcrMatchesSnapshot(matches) {
|
|
1742
|
+
const absoluteMatches = matches.map((m) => ({
|
|
1743
|
+
templateZoneId: m.templateZoneId,
|
|
1744
|
+
ocrTextResultId: m.ocrTextResultId,
|
|
1745
|
+
originalText: m.originalText,
|
|
1746
|
+
processedText: m.processedText,
|
|
1747
|
+
polygonPercent: m.polygonPercent,
|
|
1748
|
+
anchorPointPercent: m.anchorPoint,
|
|
1749
|
+
polygonAbsolute: new import_dytools_canvas_engine.Polygon(m.polygonPercent.points.map(
|
|
1750
|
+
(p) => new import_dytools_canvas_engine.Point(p.x * this.engine.width, p.y * this.engine.height)
|
|
1751
|
+
// TODO: This will need to be updated when the background changes.
|
|
1752
|
+
)),
|
|
1753
|
+
anchorPointAbsolute: m.anchorPoint ? new import_dytools_canvas_engine.Point(m.anchorPoint.x * this.engine.width, m.anchorPoint.y * this.engine.height) : null
|
|
1754
|
+
}));
|
|
1755
|
+
this.zoneOcrMatches = absoluteMatches;
|
|
1756
|
+
this.allZonesFlattened.forEach((e) => {
|
|
1757
|
+
this.emitToZone(e.id, CaptureEngineToZoneEventType.CaptureOcrMatchesLoaded, { ocrMatches: absoluteMatches });
|
|
1758
|
+
});
|
|
1759
|
+
this.emitExternal(CapturePublicEventType.OcrMatchesLoaded, { matches });
|
|
1760
|
+
}
|
|
1761
|
+
// noinspection JSUnusedGlobalSymbols
|
|
1762
|
+
getOcrMatchesSnapshot() {
|
|
1763
|
+
return this.zoneOcrMatches;
|
|
1764
|
+
}
|
|
1765
|
+
/* --- SERVER API --- */
|
|
1766
|
+
setServerApi(api) {
|
|
1767
|
+
this.serverApi = api;
|
|
1768
|
+
}
|
|
1769
|
+
// Call the server to OCR an image and load it into the engine.
|
|
1770
|
+
async loadOcrFromImage(file) {
|
|
1771
|
+
if (!this.serverApi?.readImage) {
|
|
1772
|
+
this.emitExternal(CapturePublicEventType.CaptureError, { message: "CaptureEngineServerApi.readImage is not configured." });
|
|
1773
|
+
return;
|
|
1774
|
+
}
|
|
1775
|
+
let ocrRead;
|
|
1776
|
+
try {
|
|
1777
|
+
let ocrReadResult = await this.serverApi.readImage(file);
|
|
1778
|
+
ocrReadResult.throwIfError();
|
|
1779
|
+
ocrRead = ocrReadResult.value;
|
|
1780
|
+
} catch (err) {
|
|
1781
|
+
this.emitExternal(CapturePublicEventType.CaptureError, {
|
|
1782
|
+
error: err instanceof Error ? err : void 0,
|
|
1783
|
+
message: err?.message ?? "Failed to read OCR from image."
|
|
1784
|
+
});
|
|
1785
|
+
return void 0;
|
|
1786
|
+
}
|
|
1787
|
+
return ocrRead;
|
|
1788
|
+
}
|
|
1789
|
+
// Ask the server to match OCR to zones for the current template.
|
|
1790
|
+
async getZoneMatchesFromServer(ocrOverride) {
|
|
1791
|
+
if (!this.serverApi?.matchOcrToZones) {
|
|
1792
|
+
throw new Error("CaptureEngineServerApi.matchOcrToZones is not configured.");
|
|
1793
|
+
}
|
|
1794
|
+
const ocr = ocrOverride ?? this.ocrRead;
|
|
1795
|
+
if (!ocr) {
|
|
1796
|
+
throw new Error("No OCR data available. Call loadOcrFromImage() first or pass ocrOverride.");
|
|
1797
|
+
}
|
|
1798
|
+
const matchesResult = await this.serverApi.matchOcrToZones({
|
|
1799
|
+
captureTemplate: this.getExternalTemplate(),
|
|
1800
|
+
ocr
|
|
1801
|
+
});
|
|
1802
|
+
matchesResult.throwIfError();
|
|
1803
|
+
let matches = matchesResult.value;
|
|
1804
|
+
this.emitExternal(CapturePublicEventType.OcrMatchesLoaded, { matches });
|
|
1805
|
+
return matches;
|
|
1806
|
+
}
|
|
1807
|
+
// Ask the server to fully process the template with OCR.
|
|
1808
|
+
// public async getTemplateResultFromServer(
|
|
1809
|
+
// ocrOverride?: OcrJsonDto
|
|
1810
|
+
// ): Promise<TemplateResult> {
|
|
1811
|
+
// if (!this.serverApi?.processTemplateWithOcr) {
|
|
1812
|
+
// throw new Error("CaptureEngineServerApi.processTemplateWithOcr is not configured.");
|
|
1813
|
+
// }
|
|
1814
|
+
//
|
|
1815
|
+
// const ocr = ocrOverride ?? this.lastOcrDto;
|
|
1816
|
+
// if (!ocr) {
|
|
1817
|
+
// throw new Error("No OCR data available. Call loadOcrFromImage() first or pass ocrOverride.");
|
|
1818
|
+
// }
|
|
1819
|
+
//
|
|
1820
|
+
// const captureTemplateJson = JSON.stringify(this.getExternalTemplate());
|
|
1821
|
+
//
|
|
1822
|
+
// const result = await this.serverApi.processTemplateWithOcr({
|
|
1823
|
+
// captureTemplate: captureTemplateJson,
|
|
1824
|
+
// ocr
|
|
1825
|
+
// });
|
|
1826
|
+
//
|
|
1827
|
+
// this.emitExternal("capture:template:processed", result);
|
|
1828
|
+
// return result;
|
|
1829
|
+
// }
|
|
1830
|
+
};
|
|
1831
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1832
|
+
0 && (module.exports = {
|
|
1833
|
+
CaptureEngine,
|
|
1834
|
+
CaptureEngineToZoneEventType,
|
|
1835
|
+
CapturePublicEventType,
|
|
1836
|
+
CaptureToEngineEventType
|
|
1837
|
+
});
|