From 65b70c19ddcca7cc9ac4b045a22b4af10373bd71 Mon Sep 17 00:00:00 2001 From: YiQianYao <42212176+2912401452@users.noreply.github.com> Date: Sat, 2 Apr 2022 16:23:54 +0800 Subject: [PATCH] Changemarker (#1039) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 修复 Marker GaodeMapV2 在移动端的事件失效 * fix: 修复 iconfont 偏移 * fix: 修复销毁场景时候 webgl 实例未被销毁的问题 * style: lint style --- .../services/interaction/IPickingService.ts | 1 + .../services/interaction/PickingService.ts | 7 + .../core/src/services/scene/SceneService.ts | 5 + packages/layers/src/utils/symbol-layout.ts | 8 +- packages/map/src/map.ts | 3 + packages/maps/src/amap2/map.ts | 3 +- packages/maps/src/map/map.ts | 3 - packages/renderer/src/regl/index.ts | 6 + stories/Map/components/amap2demo_iconfont.tsx | 291 +++--------------- stories/Map/components/bugfix.tsx | 69 ++--- 10 files changed, 95 insertions(+), 301 deletions(-) diff --git a/packages/core/src/services/interaction/IPickingService.ts b/packages/core/src/services/interaction/IPickingService.ts index d6c36b9e96..e3a59c2d97 100644 --- a/packages/core/src/services/interaction/IPickingService.ts +++ b/packages/core/src/services/interaction/IPickingService.ts @@ -7,4 +7,5 @@ export interface IPickingService { box: [number, number, number, number], cb: (...args: any[]) => void, ): Promise; + destroy(): void; } diff --git a/packages/core/src/services/interaction/PickingService.ts b/packages/core/src/services/interaction/PickingService.ts index add727c5f9..c9573b555b 100644 --- a/packages/core/src/services/interaction/PickingService.ts +++ b/packages/core/src/services/interaction/PickingService.ts @@ -174,6 +174,13 @@ export default class PickingService implements IPickingService { // domContainer?.style.setProperty('cursor', 'move'); } + public destroy() { + this.pickingFBO.destroy(); + // this.pickingFBO = null; 清除对 webgl 实例的引用 + // @ts-ignore + this.pickingFBO = null; + } + // 获取容器的大小 - 兼容小程序环境 private getContainerSize(container: HTMLCanvasElement | HTMLElement) { if (!!(container as HTMLCanvasElement).getContext) { diff --git a/packages/core/src/services/scene/SceneService.ts b/packages/core/src/services/scene/SceneService.ts index 6740e31996..d0729db468 100644 --- a/packages/core/src/services/scene/SceneService.ts +++ b/packages/core/src/services/scene/SceneService.ts @@ -411,9 +411,14 @@ export default class Scene extends EventEmitter implements ISceneService { } this.emit('destroy'); + this.pickingService.destroy(); this.layerService.destroy(); // this.rendererService.destroy(); setTimeout(() => { + this.$container?.removeChild(this.canvas); + // this.canvas = null 清除对 webgl 实例的引用 + // @ts-ignore + this.canvas = null; // Tip: 把这一部分销毁放到写下一个事件循环中执行,兼容 L7React 中 scene 和 layer 同时销毁的情况 this.rendererService.destroy(); }); diff --git a/packages/layers/src/utils/symbol-layout.ts b/packages/layers/src/utils/symbol-layout.ts index 47cf5886af..f595af6f68 100644 --- a/packages/layers/src/utils/symbol-layout.ts +++ b/packages/layers/src/utils/symbol-layout.ts @@ -226,7 +226,13 @@ function shapeIconFont( if (glyph) { positionedGlyphs.push({ glyph: iconfont, - x, + // x, + /** + * iconfont + * 在计算大小的时候计算的是 unicode 字符 如  + * 在布局计算 icon 位置的时候应该始终保持居中(且 icon 只占一个字符的位置) + */ + x: glyph.advance / 2, y: y + baselineOffset, vertical: false, // TODO:目前只支持水平方向 scale: 1, diff --git a/packages/map/src/map.ts b/packages/map/src/map.ts index 67053602ca..0177b06331 100644 --- a/packages/map/src/map.ts +++ b/packages/map/src/map.ts @@ -282,6 +282,9 @@ export class Map extends Camera { } public remove() { + this.container.removeChild(this.canvasContainer); + // @ts-ignore + this.canvasContainer = null; if (this.frame) { this.frame.cancel(); this.frame = null; diff --git a/packages/maps/src/amap2/map.ts b/packages/maps/src/amap2/map.ts index ff69734559..ea9ecaf52c 100644 --- a/packages/maps/src/amap2/map.ts +++ b/packages/maps/src/amap2/map.ts @@ -157,7 +157,8 @@ export default class AMapService 'amap-maps', )[0] as HTMLElement; // TODO: amap2 的 amap-maps 新增 z-index=0; 样式,让 marker 中 zIndex 失效 - amap.style.zIndex = 'auto'; + // * 设置 amap.style.zIndex = 'auto'; 会导致 GaodeMapV2 在移动端的事件失效 + // amap.style.zIndex = 'auto'; this.markerContainer = DOM.create('div', 'l7-marker-container2', amap); // this.markerContainer = DOM.create( // 'div', diff --git a/packages/maps/src/map/map.ts b/packages/maps/src/map/map.ts index 773d65efe9..295c022484 100644 --- a/packages/maps/src/map/map.ts +++ b/packages/maps/src/map/map.ts @@ -367,9 +367,6 @@ export default class L7MapService implements IMapService { } public destroy() { - // TODO: 销毁地图可视化层的容器 - this.$mapContainer?.parentNode?.removeChild(this.$mapContainer); - this.eventEmitter.removeAllListeners(); if (this.map) { this.map.remove(); diff --git a/packages/renderer/src/regl/index.ts b/packages/renderer/src/regl/index.ts index 6f22114651..160fb6a747 100644 --- a/packages/renderer/src/regl/index.ts +++ b/packages/renderer/src/regl/index.ts @@ -263,7 +263,13 @@ export default class ReglRendererService implements IRendererService { } public destroy = () => { + // this.canvas = null 清除对 webgl 实例的引用 + // @ts-ignore + this.canvas = null; // @see https://github.com/regl-project/regl/blob/gh-pages/API.md#clean-up this.gl.destroy(); + + // @ts-ignore + this.gl = null; }; } diff --git a/stories/Map/components/amap2demo_iconfont.tsx b/stories/Map/components/amap2demo_iconfont.tsx index 806d467a76..3914ad7211 100644 --- a/stories/Map/components/amap2demo_iconfont.tsx +++ b/stories/Map/components/amap2demo_iconfont.tsx @@ -10,273 +10,60 @@ export default class Amap2demo_iconfont extends React.Component { } public async componentDidMount() { - let fontFamily = 'iconfont'; - let fontPath = - '//at.alicdn.com/t/font_2534097_ao9soua2obv.woff2?t=1622021146076'; - const scene = new Scene({ id: 'map', map: new GaodeMap({ - center: [121, 30.5], - pitch: 0, - style: 'amap://styles/453e2f8e11603fc8f7548fe18959e9e9', - zoom: 9, - zooms: [8, 10], - // viewMode: '2D', + pitch: 20, + style: 'light', + center: [120, 20], + zoom: 3, }), }); this.scene = scene; - - scene.addIconFonts([ - ['smallRain', ''], - ['middleRain', ''], - ['hugeRain', ''], - ['sun', ''], - ['cloud', ''], - ]); - + const fontFamily = 'iconfont'; + // 指定 iconfont 字体文件 + const fontPath = + '//at.alicdn.com/t/font_2534097_fcae9o2mxbv.woff2?t=1622200439140'; + // 全局添加资源 scene.addFontFace(fontFamily, fontPath); + // 全局添加 iconfont 字段的映射; + scene.addIconFont('icon1', ''); scene.on('loaded', () => { - let originData = [ - { - lng: 120, - lat: 30, - iconType: 'sun', - iconColor: '#FFA500', - backgoundColor: '#00BFFF', - temperature: '28℃', - weather: '晴朗', - opacity: 0.5, - strokeWidth2: 1, - stroke: '#f00', - testTextOffset: [5, -55], - }, - { - lng: 120.2, - lat: 30.5, - iconType: 'sun', - iconColor: '#FFA500', - backgoundColor: '#00BFFF', - temperature: '28℃', - weather: '晴朗', - opacity: 0.5, - strokeWidth2: 1, - stroke: '#f00', - testTextOffset: [5, -55], - }, - { - lng: 121.5, - lat: 31.4, - iconType: 'cloud', - iconColor: '#F0F8FF', - backgoundColor: '#1E90FF', - temperature: '22℃', - weather: '多云', - opacity: 0.5, - strokeWidth2: 1, - stroke: '#f00', - testTextOffset: [5, -55], - }, - { - lng: 120, - lat: 31, - iconType: 'cloud', - iconColor: '#F0F8FF', - backgoundColor: '#1E90FF', - temperature: '22℃', - weather: '多云', - opacity: 0.5, - strokeWidth2: 1, - stroke: '#f00', - testTextOffset: [5, -55], - }, - { - lng: 120.6, - lat: 30.8, - iconType: 'cloud', - iconColor: '#F0F8FF', - backgoundColor: '#1E90FF', - temperature: '22℃', - weather: '多云', - opacity: 0.5, - strokeWidth2: 1, - stroke: '#f00', - testTextOffset: [5, -55], - }, - { - lng: 120.5, - lat: 31.3, - iconType: 'cloud', - iconColor: '#F0F8FF', - backgoundColor: '#1E90FF', - temperature: '22℃', - weather: '多云', - opacity: 1, - strokeWidth2: 3, - stroke: '#ff0', - testTextOffset: [5, -55], - }, - { - lng: 121.3, - lat: 30.2, - iconType: 'smallRain', - iconColor: '#6EA0FF', - backgoundColor: '#4678AA', - temperature: '22℃', - weather: '小雨', - opacity: 1, - strokeWidth2: 3, - stroke: '#ff0', - testTextOffset: [5, -55], - }, - { - lng: 121, - lat: 30.5, - iconType: 'smallRain', - iconColor: '#6EA0FF', - backgoundColor: '#4678AA', - temperature: '22℃', - weather: '小雨', - opacity: 1, - strokeWidth2: 3, - stroke: '#ff0', - testTextOffset: [5, -55], - }, - { - lng: 120.6, - lat: 30, - iconType: 'middleRain', - iconColor: '#6495ED', - backgoundColor: '#326EA0', - temperature: '24℃', - weather: '中雨', - opacity: 1, - strokeWidth2: 3, - stroke: '#ff0', - testTextOffset: [5, -55], - }, - { - lng: 120.2, - lat: 29.7, - iconType: 'smallRain', - iconColor: '#6EA0FF', - backgoundColor: '#4678AA', - temperature: '22℃', - weather: '小雨', - opacity: 1, - strokeWidth2: 3, - stroke: '#ff0', - testTextOffset: [5, -55], - }, - { - lng: 121.7, - lat: 29.8, - iconType: 'middleRain', - iconColor: '#6495ED', - backgoundColor: '#326EA0', - temperature: '24℃', - weather: '中雨', - opacity: 1, - strokeWidth2: 3, - stroke: '#ff0', - testTextOffset: [5, -55], - }, - { - lng: 121.5, - lat: 30, - iconType: 'hugeRain', - iconColor: '#4678D2', - backgoundColor: '#285A8C', - temperature: '20℃', - weather: '大雨-', - opacity: 1, - strokeWidth2: 3, - stroke: '#ff0', - testTextOffset: [10, -55], - }, - ]; - - const layer = new PointLayer() - .source(originData, { - parser: { - type: 'json', - x: 'lng', - y: 'lat', + const imageLayer = new PointLayer() + .source( + [ + { + j: 118.234433, + w: 35.007936, + icon: 'icon1', + value: 10, + name: 'AA', + type: 'dibiaoshui', + }, + ], + { + parser: { + type: 'json', + x: 'j', + y: 'w', + }, }, - }) - .shape('circle') - .color('backgoundColor') - .size(40); - scene.addLayer(layer); - - const pointIconFontLayer = new PointLayer({}) - .source(originData, { - parser: { - type: 'json', - x: 'lng', - y: 'lat', - }, - }) - .shape('iconType', 'text') + ) + .color('#44ff00') + .shape('icon', 'text') + // .shape('circle') + // .size(30) .size(30) - .color('iconColor') .style({ - textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left - textOffset: [38, 10], // 文本相对锚点的偏移量 [水平, 垂直] + // textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left + // textOffset: [ 40, 0 ], // 文本相对锚点的偏移量 [水平, 垂直] + padding: [0, 0], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近 + stroke: '#ffffff', // 描边颜色 fontFamily, iconfont: true, textAllowOverlap: true, }); - scene.addLayer(pointIconFontLayer); - - const textLayer = new PointLayer({}) - .source(originData, { - parser: { - type: 'json', - x: 'lng', - y: 'lat', - }, - }) - .shape('temperature', 'text') - .size(10) - .color('#ffffff') - .style({ - textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left - // textOffset: [5, -55], // 文本相对锚点的偏移量 [水平, 垂直] - textOffset: 'testTextOffset', // 文本相对锚点的偏移量 [水平, 垂直] - spacing: 2, // 字符间距 - padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近 - fontFamily: 'Times New Roman', - textAllowOverlap: true, - stroke: 'iconColor', // 描边颜色 - strokeWidth: 'strokeWidth2', // 描边宽度 - opacity: 'opacity', - }); - scene.addLayer(textLayer); - - const textLayer2 = new PointLayer({}) - .source(originData, { - parser: { - type: 'json', - x: 'lng', - y: 'lat', - }, - }) - .shape('weather', 'text') - .size(14) - .color('#ffffff') - .style({ - textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left - textOffset: [5, -15], // 文本相对锚点的偏移量 [水平, 垂直] - spacing: 2, // 字符间距 - padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近 - stroke: '#ffffff', // 描边颜色 - strokeWidth: 0.3, // 描边宽度 - strokeOpacity: 1.0, - fontFamily: 'Times New Roman', - textAllowOverlap: true, - }); - scene.addLayer(textLayer2); + scene.addLayer(imageLayer); }); } diff --git a/stories/Map/components/bugfix.tsx b/stories/Map/components/bugfix.tsx index 2dd6527ad8..0075318739 100644 --- a/stories/Map/components/bugfix.tsx +++ b/stories/Map/components/bugfix.tsx @@ -11,51 +11,32 @@ export default class Amap2demo extends React.Component { } public async componentDidMount() { - const scene = new Scene({ - id: 'map', - map: new GaodeMap({ - // center: [121.434765, 31.256735], - // zoom: 14.83, - pitch: 0, - style: 'light', - center: [122.5, 30], - zoom: 4, - }), - }); - this.scene = scene; - - const layer = new PointLayer() - .source( - [ - { lng: 120, lat: 30, c: '#ff0' }, - { lng: 125, lat: 30, c: '#0f0' }, - ], - { - parser: { - type: 'json', - x: 'lng', - y: 'lat', - }, - }, - ) - .shape('circle') - .size(20) - .color('c'); - - scene.on('loaded', () => { - scene.addLayer(layer); - // layer.on('dataUpdate', (e) => { - // const le = layer.getLegendItems('color') - // console.log(le) - // }) - layer.on('dataUpdate', (e) => { - const le = layer.getLegendItems('color'); - console.log('scale', le); + function initScene() { + return new Promise((resolve, reject) => { + const scene = new Scene({ + id: 'map', + map: new GaodeMapV2({ + // center: [121.434765, 31.256735], + // zoom: 14.83, + pitch: 0, + style: 'light', + center: [122.5, 30], + zoom: 4, + }), + }); + scene.on('loaded', () => { + setTimeout(() => { + resolve(scene); + }, 200); + }); }); - layer.setData([{ lng: 121, lat: 30, c: '#000' }]); - // layer.color('#f00') - scene.render(); - }); + } + + for (let i = 0; i < 20; i++) { + console.log('init ' + (i + 1)); + let scene = await initScene(); + scene.destroy(); + } } public render() {