geokernel-electron 1.1.36 → 1.1.37

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.
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geokernel-electron",
3
- "version": "1.1.36",
3
+ "version": "1.1.37",
4
4
  "description": "Electron bindings for the GeoKernel GIS SDK.",
5
5
  "main": "src/index.js",
6
6
  "type": "commonjs",
@@ -274,13 +274,31 @@ const SIGNATURES = Object.freeze({
274
274
  "GeoKernelViewer_ZoomToLayer": ["bool", ["void_p", "int"]],
275
275
  "GeoKernelViewer_ZoomToScreenRect": ["void", ["void_p", "int", "int", "int", "int"]],
276
276
  "GeoKernelViewer_ZoomToSelectedFeatures": ["bool", ["void_p"]],
277
+ "GeoKernelWindow_AddCancellableLayerLoadToolbar": ["bool", ["void_p", "void_p", "wchar_p"]],
278
+ "GeoKernelWindow_AddCommandToolbar": ["bool", ["void_p", "wchar_p", "command_callback", "void_p"]],
279
+ "GeoKernelWindow_AddControlPanel": ["bool", ["void_p", "wchar_p", "control_callback", "void_p"]],
277
280
  "GeoKernelWindow_AddLayerManagementToolbar": ["bool", ["void_p", "void_p", "wchar_p"]],
281
+ "GeoKernelWindow_AddLayerPanel": ["bool", ["void_p", "void_p", "int"]],
282
+ "GeoKernelWindow_AddLayerSelector": ["bool", ["void_p", "void_p", "int"]],
283
+ "GeoKernelWindow_AddLayerStyleToolbar": ["bool", ["void_p", "void_p", "wchar_p"]],
284
+ "GeoKernelWindow_AddLegendPanel": ["bool", ["void_p", "wchar_p"]],
285
+ "GeoKernelWindow_AddLogPanel": ["bool", ["void_p", "wchar_p"]],
278
286
  "GeoKernelWindow_AddMeasureToolbar": ["void", ["void_p", "void_p"]],
279
287
  "GeoKernelWindow_AddNavigationToolbar": ["void", ["void_p", "void_p"]],
288
+ "GeoKernelWindow_AddSpatialIndexBenchmarkToolbar": ["bool", ["void_p", "void_p", "wchar_p"]],
289
+ "GeoKernelWindow_AddViewerPane": ["void_p", ["void_p", "wchar_p"]],
290
+ "GeoKernelWindow_AppendLog": ["void", ["void_p", "wchar_p"]],
291
+ "GeoKernelWindow_ClearLog": ["void", ["void_p"]],
280
292
  "GeoKernelWindow_Create": ["void_p", ["int", "int", "wchar_p"]],
281
293
  "GeoKernelWindow_Destroy": ["void", ["void_p"]],
294
+ "GeoKernelWindow_GetSelectedLayerIndex": ["int", ["void_p"]],
282
295
  "GeoKernelWindow_IsVisible": ["bool", ["void_p"]],
283
296
  "GeoKernelWindow_SetCentralViewer": ["void_p", ["void_p"]],
297
+ "GeoKernelWindow_SetControlValue": ["bool", ["void_p", "int", "double", "wchar_p"]],
298
+ "GeoKernelWindow_SetLegendItemsJson": ["bool", ["void_p", "wchar_p"]],
299
+ "GeoKernelWindow_SetLegendTitle": ["bool", ["void_p", "wchar_p"]],
300
+ "GeoKernelWindow_SetLegendWidth": ["bool", ["void_p", "int"]],
301
+ "GeoKernelWindow_SetStatusText": ["void", ["void_p", "wchar_p"]],
284
302
  "GeoKernelWindow_Show": ["void", ["void_p"]],
285
303
  });
286
304
 
@@ -59,6 +59,18 @@ const GeoKernelViewerSpatialIndexStateCallback = koffi.proto(
59
59
  ["int", "void *"],
60
60
  );
61
61
 
62
+ const GeoKernelWindowCommandCallback = koffi.proto(
63
+ "GeoKernelWindowCommandCallback",
64
+ "void",
65
+ ["int", "void *"],
66
+ );
67
+
68
+ const GeoKernelWindowControlCallback = koffi.proto(
69
+ "GeoKernelWindowControlCallback",
70
+ "void",
71
+ ["int", "double", "str16", "void *"],
72
+ );
73
+
62
74
  const TYPES = Object.freeze({
63
75
  void: "void",
64
76
  void_p: "void *",
@@ -86,6 +98,8 @@ const TYPES = Object.freeze({
86
98
  progress_callback: koffi.pointer(GeoKernelViewerLayerLoadProgressCallback),
87
99
  cancel_callback: koffi.pointer(GeoKernelViewerLayerLoadCancellationCallback),
88
100
  index_state_callback: koffi.pointer(GeoKernelViewerSpatialIndexStateCallback),
101
+ command_callback: koffi.pointer(GeoKernelWindowCommandCallback),
102
+ control_callback: koffi.pointer(GeoKernelWindowControlCallback),
89
103
  });
90
104
 
91
105
  module.exports = {
@@ -97,5 +111,7 @@ module.exports = {
97
111
  GeoKernelViewerRouteSummary,
98
112
  GeoKernelViewerScreenRectangle,
99
113
  GeoKernelViewerSpatialIndexStateCallback,
114
+ GeoKernelWindowCommandCallback,
115
+ GeoKernelWindowControlCallback,
100
116
  TYPES,
101
117
  };
package/src/types.js CHANGED
@@ -13,6 +13,37 @@ const ViewerTool = Object.freeze({
13
13
  EDIT_VERTICES: 9,
14
14
  });
15
15
 
16
+ const ViewerEventType = Object.freeze({
17
+ ACTIVE_TOOL_CHANGED: 1,
18
+ LAYERS_CHANGED: 2,
19
+ LAYER_ADDED: 3,
20
+ LAYER_REMOVED: 4,
21
+ LAYER_VISIBILITY_CHANGED: 5,
22
+ LAYER_EDIT_STATE_CHANGED: 6,
23
+ LAYER_EDIT_SESSION_STARTED: 7,
24
+ LAYER_EDIT_SESSION_COMMITTED: 8,
25
+ LAYER_EDIT_SESSION_ROLLED_BACK: 9,
26
+ LAYER_ORDER_CHANGED: 10,
27
+ SELECTION_CHANGED: 11,
28
+ VISIBLE_EXTENT_CHANGED: 12,
29
+ ZOOM_CHANGED: 13,
30
+ VIEW_CHANGED: 14,
31
+ BUSY_CHANGED: 15,
32
+ PROJECT_OPENED: 16,
33
+ PROJECT_CLOSED: 17,
34
+ MAP_SELECTION_BOX_FINISHED: 18,
35
+ MOUSE_COORDINATES_CHANGED: 19,
36
+ MAP_MOUSE_DOWN: 20,
37
+ MAP_MOUSE_MOVE: 21,
38
+ MAP_MOUSE_UP: 22,
39
+ LAYER_ADDING: 23,
40
+ LAYER_REMOVING: 24,
41
+ INDEX_CREATING: 25,
42
+ INDEX_CREATED: 26,
43
+ INDEX_LOADED: 27,
44
+ RENDER_BACKEND_CHANGED: 28,
45
+ });
46
+
16
47
  const ShapeType = Object.freeze({
17
48
  UNKNOWN: 0,
18
49
  POINT: 1,
@@ -114,6 +145,7 @@ module.exports = {
114
145
  SpatialIndexType,
115
146
  SymbolStyleTarget,
116
147
  ViewerTool,
148
+ ViewerEventType,
117
149
  extent,
118
150
  point,
119
151
  routeSummary,
package/src/viewer.js CHANGED
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
 
3
3
  const fs = require("fs");
4
+ const koffi = require("koffi");
5
+ const { GeoKernelViewerEventData, TYPES } = require("./native-types");
4
6
 
5
7
  const { createNativeLibrary } = require("./native");
6
8
  const { MAP_STYLES, argb } = require("./styles");
@@ -63,10 +65,20 @@ class ViewerWindow {
63
65
  throw new Error("GeoKernelWindow_Create failed.");
64
66
  }
65
67
 
66
- this.viewerHandle = this.library.windowSetCentralViewer(this.windowHandle);
67
- if (!this.viewerHandle) {
68
+ const paneTitles = Array.isArray(options.viewerPanes) ? options.viewerPanes : null;
69
+ const paneHandles = paneTitles?.map((paneTitle) =>
70
+ this.library.function("GeoKernelWindow_AddViewerPane")(this.windowHandle, paneTitle));
71
+ this.viewerHandle = paneHandles?.[0] ?? this.library.windowSetCentralViewer(this.windowHandle);
72
+ if (!this.viewerHandle || paneHandles?.some((handle) => !handle)) {
68
73
  this.library.windowDestroy(this.windowHandle);
69
- throw new Error("GeoKernelWindow_SetCentralViewer failed.");
74
+ throw new Error(paneTitles
75
+ ? "GeoKernelWindow_AddViewerPane failed."
76
+ : "GeoKernelWindow_SetCentralViewer failed.");
77
+ }
78
+
79
+ this.paneFacades = [];
80
+ if (paneHandles) {
81
+ this.paneFacades = paneHandles.slice(1).map((handle) => this._createPaneFacade(handle));
70
82
  }
71
83
 
72
84
  if (options.navigationToolbar !== false) {
@@ -81,15 +93,49 @@ class ViewerWindow {
81
93
  this.addLayerManagementToolbar(options.layerManagementToolbar);
82
94
  }
83
95
 
96
+ if (options.layerPanel) {
97
+ this.addLayerPanel(options.layerPanel);
98
+ }
99
+ if (options.layerSelector) {
100
+ this.addLayerSelector(options.layerSelector);
101
+ }
102
+ if (options.layerStyleToolbar) {
103
+ this.addLayerStyleToolbar(options.layerStyleToolbar);
104
+ }
105
+
84
106
  this.interval = null;
85
107
  this.visibleOnce = false;
86
108
  this.startedAt = 0;
109
+ this.commandCallbacks = [];
110
+ this.controlCallbacks = [];
111
+ this.eventCallbacks = [];
87
112
  }
88
113
 
89
114
  setActivationType(value) {
90
115
  this.library.setActivationType(this.viewerHandle, value);
91
116
  }
92
117
 
118
+ pane(index) {
119
+ if (index === 0) return this;
120
+ return this.paneFacades[index - 1] ?? null;
121
+ }
122
+
123
+ _createPaneFacade(viewerHandle) {
124
+ const pane = Object.create(ViewerWindow.prototype);
125
+ pane.library = this.library;
126
+ pane.windowHandle = this.windowHandle;
127
+ pane.viewerHandle = viewerHandle;
128
+ pane.interval = null;
129
+ pane.visibleOnce = false;
130
+ pane.startedAt = 0;
131
+ pane.commandCallbacks = [];
132
+ pane.controlCallbacks = [];
133
+ pane.eventCallbacks = [];
134
+ pane.paneFacades = [];
135
+ pane.isPaneFacade = true;
136
+ return pane;
137
+ }
138
+
93
139
  setLicenseManagerUrl(value) {
94
140
  this.library.setLicenseManagerUrl(this.viewerHandle, value ?? "");
95
141
  }
@@ -113,6 +159,148 @@ class ViewerWindow {
113
159
  }
114
160
  }
115
161
 
162
+ addLayerPanel(options = {}) {
163
+ const features =
164
+ (options.allowReorder === true ? 1 : 0) |
165
+ (options.allowVisibility === true ? 2 : 0);
166
+ const ok = this.library.function("GeoKernelWindow_AddLayerPanel")(
167
+ this.windowHandle,
168
+ this.viewerHandle,
169
+ features,
170
+ );
171
+ if (!ok) {
172
+ throw new Error("GeoKernelWindow_AddLayerPanel failed.");
173
+ }
174
+ }
175
+
176
+ addLayerSelector(options = {}) {
177
+ const actions = { zoom: 1 };
178
+ const action = actions[options.action] ?? 0;
179
+ const ok = this.library.function("GeoKernelWindow_AddLayerSelector")(
180
+ this.windowHandle,
181
+ this.viewerHandle,
182
+ action,
183
+ );
184
+ if (!ok) {
185
+ throw new Error("GeoKernelWindow_AddLayerSelector failed.");
186
+ }
187
+ }
188
+
189
+ addLayerStyleToolbar(options = {}) {
190
+ const ok = this.library.function("GeoKernelWindow_AddLayerStyleToolbar")(
191
+ this.windowHandle,
192
+ this.viewerHandle,
193
+ jsonText(options),
194
+ );
195
+ if (!ok) {
196
+ throw new Error("GeoKernelWindow_AddLayerStyleToolbar failed.");
197
+ }
198
+ }
199
+
200
+ addSpatialIndexBenchmarkToolbar(options = {}) {
201
+ const ok = this.library.function("GeoKernelWindow_AddSpatialIndexBenchmarkToolbar")(
202
+ this.windowHandle,
203
+ this.viewerHandle,
204
+ jsonText(options),
205
+ );
206
+ if (!ok) throw new Error("GeoKernelWindow_AddSpatialIndexBenchmarkToolbar failed.");
207
+ }
208
+
209
+ addCancellableLayerLoadToolbar(options = {}) {
210
+ const ok = this.library.function("GeoKernelWindow_AddCancellableLayerLoadToolbar")(
211
+ this.windowHandle, this.viewerHandle, jsonText(options),
212
+ );
213
+ if (!ok) throw new Error("GeoKernelWindow_AddCancellableLayerLoadToolbar failed.");
214
+ }
215
+
216
+ addCommandToolbar(commands, onCommand) {
217
+ const callback = koffi.register((commandId) => onCommand(commandId), TYPES.command_callback);
218
+ this.commandCallbacks.push(callback);
219
+ const ok = this.library.function("GeoKernelWindow_AddCommandToolbar")(
220
+ this.windowHandle, jsonText({ commands }), callback, null,
221
+ );
222
+ if (!ok) throw new Error("GeoKernelWindow_AddCommandToolbar failed.");
223
+ }
224
+
225
+ addControlPanel(configuration, onChange) {
226
+ const callback = koffi.register(
227
+ (controlId, numericValue, textValue) => onChange(controlId, numericValue, textValue ?? ""),
228
+ TYPES.control_callback,
229
+ );
230
+ this.controlCallbacks.push(callback);
231
+ const ok = this.library.function("GeoKernelWindow_AddControlPanel")(
232
+ this.windowHandle, jsonText(configuration), callback, null,
233
+ );
234
+ if (!ok) throw new Error("GeoKernelWindow_AddControlPanel failed.");
235
+ }
236
+
237
+ setControlValue(controlId, value) {
238
+ const numericValue = typeof value === "number" ? value : 0;
239
+ const textValue = typeof value === "string" ? value : null;
240
+ return this.library.function("GeoKernelWindow_SetControlValue")(
241
+ this.windowHandle, Number(controlId), numericValue, textValue,
242
+ );
243
+ }
244
+
245
+ setStatusText(text) {
246
+ this.library.function("GeoKernelWindow_SetStatusText")(this.windowHandle, text ?? "");
247
+ }
248
+
249
+ addLogPanel(title = "Event log") {
250
+ const ok = this.library.function("GeoKernelWindow_AddLogPanel")(this.windowHandle, title);
251
+ if (!ok) throw new Error("GeoKernelWindow_AddLogPanel failed.");
252
+ }
253
+
254
+ addLegendPanel(title = "Legend") {
255
+ const ok = this.library.function("GeoKernelWindow_AddLegendPanel")(this.windowHandle, title);
256
+ if (!ok) throw new Error("GeoKernelWindow_AddLegendPanel failed.");
257
+ }
258
+
259
+ setLegendTitle(title) {
260
+ return this.library.function("GeoKernelWindow_SetLegendTitle")(this.windowHandle, title);
261
+ }
262
+
263
+ setLegendWidth(width) {
264
+ return this.library.function("GeoKernelWindow_SetLegendWidth")(this.windowHandle, Number(width));
265
+ }
266
+
267
+ setLegendItems(items) {
268
+ return this.library.function("GeoKernelWindow_SetLegendItemsJson")(
269
+ this.windowHandle, jsonText(items),
270
+ );
271
+ }
272
+
273
+ appendLog(text) {
274
+ this.library.function("GeoKernelWindow_AppendLog")(this.windowHandle, text ?? "");
275
+ }
276
+
277
+ clearLog() {
278
+ this.library.function("GeoKernelWindow_ClearLog")(this.windowHandle);
279
+ }
280
+
281
+ selectedLayerIndex() {
282
+ return this.library.function("GeoKernelWindow_GetSelectedLayerIndex")(this.windowHandle);
283
+ }
284
+
285
+ setEventCallback(onEvent) {
286
+ this.library.function("GeoKernelViewer_SetEventCallback")(this.viewerHandle, null, null);
287
+ for (const callback of this.eventCallbacks) koffi.unregister(callback);
288
+ this.eventCallbacks = [];
289
+ if (typeof onEvent !== "function") return;
290
+
291
+ const callback = koffi.register((dataPointer, text) => {
292
+ const data = koffi.decode(dataPointer, GeoKernelViewerEventData);
293
+ onEvent({
294
+ ...data,
295
+ extent: { ...data.extent },
296
+ screenRectangle: { ...data.screenRectangle },
297
+ text: text ?? "",
298
+ });
299
+ }, TYPES.event_callback);
300
+ this.eventCallbacks.push(callback);
301
+ this.library.function("GeoKernelViewer_SetEventCallback")(this.viewerHandle, callback, null);
302
+ }
303
+
116
304
  getTool() {
117
305
  return this._call("GeoKernelViewer_GetTool");
118
306
  }
@@ -208,11 +396,42 @@ class ViewerWindow {
208
396
  return this._call("GeoKernelViewer_AddEmptyVectorLayer", name, Number(shapeType), jsonText(style));
209
397
  }
210
398
 
399
+ beginEditLayer(index) { return this._call("GeoKernelViewer_BeginEditLayer", Number(index)); }
400
+ commitEditLayer(index) { return this._call("GeoKernelViewer_CommitEditLayer", Number(index)); }
401
+ rollbackEditLayer(index) { return this._call("GeoKernelViewer_RollbackEditLayer", Number(index)); }
402
+ isLayerEditing(index) { return this._call("GeoKernelViewer_IsLayerEditing", Number(index)); }
403
+ setActiveEditLayerIndex(index) { return this._call("GeoKernelViewer_SetActiveEditLayerIndex", Number(index)); }
404
+ addPointToEditLayer(index, x, y) { return this._call("GeoKernelViewer_AddPointToEditLayer", Number(index), Number(x), Number(y)); }
405
+ addPolylineToEditLayer(index, points) {
406
+ const xy = xyArray(points);
407
+ return this._call("GeoKernelViewer_AddPolylineToEditLayer", Number(index), xy, xy.length / 2);
408
+ }
409
+ addPolygonToEditLayer(index, points) {
410
+ const xy = xyArray(points);
411
+ return this._call("GeoKernelViewer_AddPolygonToEditLayer", Number(index), xy, xy.length / 2);
412
+ }
413
+
211
414
  addPointLayer(name, points, style) {
212
415
  const xy = xyArray(points);
213
416
  return this._call("GeoKernelViewer_AddPointLayer", name, xy, xy.length / 2, jsonText(style));
214
417
  }
215
418
 
419
+ addAttributedPointLayer(name, points, attributes, style, sourceEpsg = 4326) {
420
+ if (!Array.isArray(attributes) || attributes.length !== points.length) {
421
+ throw new Error("Attributed point layers require one attribute object per point.");
422
+ }
423
+ const xy = xyArray(points);
424
+ return this._call(
425
+ "GeoKernelViewer_AddAttributedPointLayer",
426
+ name,
427
+ xy,
428
+ xy.length / 2,
429
+ jsonText(attributes),
430
+ jsonText(style),
431
+ Number(sourceEpsg),
432
+ );
433
+ }
434
+
216
435
  addPolylineLayer(name, parts, style) {
217
436
  const arrays = partsArrays(parts);
218
437
  return this._call("GeoKernelViewer_AddPolylineLayer", name, arrays.xy, arrays.counts, arrays.counts.length, jsonText(style));
@@ -227,6 +446,10 @@ class ViewerWindow {
227
446
  this.library.setMapBackgroundColor(this.viewerHandle, argb(color));
228
447
  }
229
448
 
449
+ invalidateRenderCache(clearTileCache = false, clearLayerCache = false) {
450
+ this._call("GeoKernelViewer_InvalidateRenderCache", Boolean(clearTileCache), Boolean(clearLayerCache));
451
+ }
452
+
230
453
  getBackground() {
231
454
  return this._call("GeoKernelViewer_GetMapBackgroundColor");
232
455
  }
@@ -345,7 +568,7 @@ class ViewerWindow {
345
568
  options.colorRampName ?? "Unique",
346
569
  options.categoryLimit ?? 64,
347
570
  options.reverseColorRamp ?? false,
348
- options.sampleLimit ?? 0,
571
+ options.sampleLimit ?? 5000,
349
572
  options.styleTarget ?? 0,
350
573
  options.startSize ?? 4.0,
351
574
  options.endSize ?? 14.0,
@@ -366,7 +589,7 @@ class ViewerWindow {
366
589
  breaks.length,
367
590
  options.colorRampMode ?? 0,
368
591
  options.reverseColorRamp ?? false,
369
- options.sampleLimit ?? 0,
592
+ options.sampleLimit ?? 5000,
370
593
  options.styleTarget ?? 0,
371
594
  options.startSize ?? 4.0,
372
595
  options.endSize ?? 18.0,
@@ -521,6 +744,14 @@ class ViewerWindow {
521
744
  this._call("GeoKernelViewer_ClearShapes");
522
745
  }
523
746
 
747
+ clearSelectedFeatures() {
748
+ this._call("GeoKernelViewer_ClearSelectedFeatures");
749
+ }
750
+
751
+ selectedFeatureCount() {
752
+ return this._call("GeoKernelViewer_GetSelectedFeatureCount");
753
+ }
754
+
524
755
  clearLayers() {
525
756
  this._call("GeoKernelViewer_ClearLayers");
526
757
  }
@@ -566,6 +797,27 @@ class ViewerWindow {
566
797
  this.interval = null;
567
798
  }
568
799
 
800
+ for (const pane of this.paneFacades) {
801
+ if (pane.viewerHandle) {
802
+ pane.library.function("GeoKernelViewer_SetEventCallback")(pane.viewerHandle, null, null);
803
+ for (const callback of pane.eventCallbacks) koffi.unregister(callback);
804
+ pane.eventCallbacks = [];
805
+ pane.clearAll();
806
+ pane.viewerHandle = null;
807
+ }
808
+ }
809
+ this.paneFacades = [];
810
+
811
+ if (this.viewerHandle) {
812
+ this.library.function("GeoKernelViewer_SetEventCallback")(this.viewerHandle, null, null);
813
+ }
814
+ for (const callback of this.eventCallbacks) koffi.unregister(callback);
815
+ this.eventCallbacks = [];
816
+ for (const callback of this.commandCallbacks) koffi.unregister(callback);
817
+ this.commandCallbacks = [];
818
+ for (const callback of this.controlCallbacks) koffi.unregister(callback);
819
+ this.controlCallbacks = [];
820
+
569
821
  if (this.viewerHandle) {
570
822
  this.clearAll();
571
823
  this.viewerHandle = null;