@treasuryspatial/map-kit 0.1.2 → 0.1.4

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.
@@ -13,6 +13,7 @@ export type MapThreeLayerOptions = {
13
13
  id: string;
14
14
  zOffsetMeters?: number;
15
15
  onInit?: (scene: THREE.Scene, renderer: THREE.WebGLRenderer, camera: THREE.Camera) => void;
16
+ debug?: boolean;
16
17
  };
17
18
  export declare function createMapThreeLayer(options: MapThreeLayerOptions): MapThreeLayer;
18
19
  //# sourceMappingURL=mapThreeLayer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mapThreeLayer.d.ts","sourceRoot":"","sources":["../src/mapThreeLayer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,QAAQ,CAAC,oBAAoB,CAAC;IACrC,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,IAAI,KAAK,IAAI,CAAC;IAC9C,SAAS,EAAE,CAAC,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,KAAK,IAAI,CAAC;IACjE,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,KAAK,IAAI,CAAC;CAC5F,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CA4FhF"}
1
+ {"version":3,"file":"mapThreeLayer.d.ts","sourceRoot":"","sources":["../src/mapThreeLayer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,QAAQ,CAAC,oBAAoB,CAAC;IACrC,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,IAAI,KAAK,IAAI,CAAC;IAC9C,SAAS,EAAE,CAAC,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,KAAK,IAAI,CAAC;IACjE,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,KAAK,IAAI,CAAC;IAC3F,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAyMhF"}
@@ -1,20 +1,53 @@
1
1
  import mapboxgl from 'mapbox-gl';
2
2
  import * as THREE from 'three';
3
3
  export function createMapThreeLayer(options) {
4
- const { id, zOffsetMeters = 0.02, onInit } = options;
4
+ const { id, zOffsetMeters = 0.02, onInit, debug = false } = options;
5
5
  let mapRef = null;
6
6
  let scene = null;
7
7
  let camera = null;
8
8
  let renderer = null;
9
+ let screenScene = null;
10
+ let screenCamera = null;
11
+ let screenMaterial = null;
12
+ let screenQuad = null;
13
+ let renderTarget = null;
9
14
  let rootGroup = null;
10
15
  let meshGroup = null;
11
16
  let mercatorOrigin = null;
12
17
  let meterScale = 1;
13
18
  let zOffset = zOffsetMeters;
19
+ let targetWidth = 0;
20
+ let targetHeight = 0;
21
+ let renderDisabled = false;
22
+ let errorCount = 0;
23
+ const log = (...args) => {
24
+ if (!debug)
25
+ return;
26
+ console.info(`[map-kit:${id}]`, ...args);
27
+ };
28
+ const logError = (message, err) => {
29
+ console.error(`[map-kit:${id}] ${message}`, err);
30
+ };
31
+ const logGlError = (gl, label) => {
32
+ if (!debug)
33
+ return;
34
+ const error = gl.getError();
35
+ if (error !== gl.NO_ERROR) {
36
+ log(`GL error (${label})`, error);
37
+ }
38
+ };
39
+ const checkFramebuffer = (gl, label) => {
40
+ if (!debug)
41
+ return;
42
+ const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
43
+ if (status !== gl.FRAMEBUFFER_COMPLETE) {
44
+ log(`Framebuffer incomplete (${label})`, status);
45
+ }
46
+ };
14
47
  const layer = {
15
48
  id,
16
49
  type: 'custom',
17
- renderingMode: '3d',
50
+ renderingMode: '2d',
18
51
  onAdd: (map, gl) => {
19
52
  mapRef = map;
20
53
  scene = new THREE.Scene();
@@ -29,6 +62,28 @@ export function createMapThreeLayer(options) {
29
62
  renderer.outputColorSpace = THREE.SRGBColorSpace;
30
63
  renderer.toneMapping = THREE.NeutralToneMapping;
31
64
  renderer.toneMappingExposure = 1.05;
65
+ renderer.setClearColor(0x000000, 0);
66
+ const canvas = map.getCanvas();
67
+ targetWidth = canvas.width;
68
+ targetHeight = canvas.height;
69
+ renderTarget = new THREE.WebGLRenderTarget(targetWidth, targetHeight, {
70
+ depthBuffer: true,
71
+ stencilBuffer: false,
72
+ });
73
+ renderTarget.texture.colorSpace = THREE.SRGBColorSpace;
74
+ renderTarget.texture.premultiplyAlpha = true;
75
+ log('renderTarget', { width: targetWidth, height: targetHeight });
76
+ screenScene = new THREE.Scene();
77
+ screenCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
78
+ screenMaterial = new THREE.MeshBasicMaterial({
79
+ map: renderTarget.texture,
80
+ transparent: true,
81
+ depthTest: false,
82
+ depthWrite: false,
83
+ });
84
+ screenMaterial.premultipliedAlpha = true;
85
+ screenQuad = new THREE.Mesh(new THREE.PlaneGeometry(2, 2), screenMaterial);
86
+ screenScene.add(screenQuad);
32
87
  rootGroup = new THREE.Group();
33
88
  rootGroup.matrixAutoUpdate = false;
34
89
  scene.add(rootGroup);
@@ -37,20 +92,65 @@ export function createMapThreeLayer(options) {
37
92
  if (onInit && renderer && camera)
38
93
  onInit(scene, renderer, camera);
39
94
  },
40
- render: (_gl, matrix) => {
41
- if (!renderer || !scene || !camera || !rootGroup)
95
+ prerender: (_gl, matrix) => {
96
+ if (renderDisabled)
97
+ return;
98
+ if (!renderer || !scene || !camera || !rootGroup || !renderTarget)
99
+ return;
100
+ try {
101
+ camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);
102
+ if (mercatorOrigin) {
103
+ const translate = new THREE.Matrix4().makeTranslation(mercatorOrigin.x, mercatorOrigin.y, (mercatorOrigin.z ?? 0) + zOffset * meterScale);
104
+ const scale = new THREE.Matrix4().makeScale(meterScale, -meterScale, meterScale);
105
+ rootGroup.matrix = new THREE.Matrix4().multiplyMatrices(translate, scale);
106
+ rootGroup.matrixWorldNeedsUpdate = true;
107
+ }
108
+ const canvas = mapRef?.getCanvas();
109
+ if (canvas && (canvas.width !== targetWidth || canvas.height !== targetHeight)) {
110
+ targetWidth = canvas.width;
111
+ targetHeight = canvas.height;
112
+ renderTarget.setSize(targetWidth, targetHeight);
113
+ log('renderTarget resized', { width: targetWidth, height: targetHeight });
114
+ }
115
+ renderer.setRenderTarget(renderTarget);
116
+ renderer.clear(true, true, true);
117
+ const gl = renderer.getContext();
118
+ checkFramebuffer(gl, 'prerender');
119
+ renderer.render(scene, camera);
120
+ logGlError(gl, 'prerender');
121
+ renderer.setRenderTarget(null);
122
+ }
123
+ catch (err) {
124
+ errorCount += 1;
125
+ logError('prerender failed', err);
126
+ if (errorCount > 2) {
127
+ renderDisabled = true;
128
+ log('render disabled after repeated errors');
129
+ }
130
+ }
131
+ },
132
+ render: (gl) => {
133
+ if (renderDisabled)
42
134
  return;
43
- camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);
44
- if (mercatorOrigin) {
45
- const translate = new THREE.Matrix4().makeTranslation(mercatorOrigin.x, mercatorOrigin.y, (mercatorOrigin.z ?? 0) + zOffset * meterScale);
46
- const scale = new THREE.Matrix4().makeScale(meterScale, -meterScale, meterScale);
47
- rootGroup.matrix = new THREE.Matrix4().multiplyMatrices(translate, scale);
48
- rootGroup.matrixWorldNeedsUpdate = true;
135
+ if (!renderer || !screenScene || !screenCamera)
136
+ return;
137
+ try {
138
+ renderer.resetState();
139
+ gl.disable(gl.DEPTH_TEST);
140
+ gl.enable(gl.BLEND);
141
+ gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
142
+ renderer.render(screenScene, screenCamera);
143
+ logGlError(gl, 'render');
144
+ mapRef?.triggerRepaint();
145
+ }
146
+ catch (err) {
147
+ errorCount += 1;
148
+ logError('render failed', err);
149
+ if (errorCount > 2) {
150
+ renderDisabled = true;
151
+ log('render disabled after repeated errors');
152
+ }
49
153
  }
50
- renderer.resetState();
51
- renderer.clearDepth();
52
- renderer.render(scene, camera);
53
- mapRef?.triggerRepaint();
54
154
  },
55
155
  };
56
156
  return {
@@ -78,9 +178,19 @@ export function createMapThreeLayer(options) {
78
178
  if (rootGroup) {
79
179
  rootGroup.clear();
80
180
  }
181
+ if (screenQuad) {
182
+ screenQuad.geometry.dispose();
183
+ }
184
+ screenMaterial?.dispose();
185
+ renderTarget?.dispose();
81
186
  meshGroup = null;
82
187
  scene = null;
83
188
  camera = null;
189
+ screenScene = null;
190
+ screenCamera = null;
191
+ screenMaterial = null;
192
+ screenQuad = null;
193
+ renderTarget = null;
84
194
  renderer = null;
85
195
  mapRef = null;
86
196
  mercatorOrigin = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treasuryspatial/map-kit",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "main": "./dist/index.js",