From 81c4dfaa214ee01333623cc9a2bc039b6f0a15d0 Mon Sep 17 00:00:00 2001 From: Oleg Kalyanov Date: Fri, 29 Sep 2023 06:26:24 +0700 Subject: [PATCH] Remove methods and types (#25) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix plugin on mapgl styles reload * removeModels method * Add removeRealtyScene method * Init fix. Min|max zoom. Stats * Remove redundant from npm package. Now tests have individual data mocks * REmove min|max zoom * Tests * Types * remove some fixes * Style change test * Fix review * Fix review * Ru » En --- .gitignore | 3 + demo/index.html | 24 +- demo/index.ts | 179 ++++---- demo/mocks.ts | 403 ++++++++++++++++++ jest.config.js | 1 + package.json | 4 +- src/control/control.module.css | 3 + src/index.ts | 1 + src/plugin.ts | 181 ++++---- src/poiGroups.ts | 9 +- src/realtyScene/realtyScene.ts | 152 ++++--- src/types/events.ts | 2 +- src/types/index.ts | 3 + src/types/plugin.ts | 8 +- src/utils/common.ts | 55 +++ test/index.ts | 6 +- test/mocks/index.ts | 15 + test/mocks/models.ts | 18 + test/mocks/poi.ts | 39 ++ .../mocks/realtyScene.ts | 4 +- test/puppeteer/utils.ts | 10 + .../plugin/add_realty_scene-snap.png | Bin 41282 -> 40709 bytes .../plugin/change_style-snap.png | Bin 0 -> 13700 bytes .../plugin/remove_models-snap.png | Bin 0 -> 482 bytes .../plugin/remove_realty_scene-snap.png | Bin 0 -> 482 bytes test/screenshots/plugin.screen.ts | 228 +++++----- test/test.d.ts | 4 +- test/utils.ts | 67 --- tsconfig.json | 2 +- tsconfig.test.json | 5 + webpack.config.js | 3 + 31 files changed, 1030 insertions(+), 399 deletions(-) create mode 100644 demo/mocks.ts create mode 100644 src/types/index.ts create mode 100644 test/mocks/index.ts create mode 100644 test/mocks/models.ts create mode 100644 test/mocks/poi.ts rename demo/realtySceneData.ts => test/mocks/realtyScene.ts (99%) create mode 100644 test/screenshots/__screenshots__/plugin/change_style-snap.png create mode 100644 test/screenshots/__screenshots__/plugin/remove_models-snap.png create mode 100644 test/screenshots/__screenshots__/plugin/remove_realty_scene-snap.png delete mode 100644 test/utils.ts create mode 100644 tsconfig.test.json diff --git a/.gitignore b/.gitignore index 52dd560..6dd59c3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ dist/ node_modules/ +__diff_output__ .vscode/ + +.DS_Store diff --git a/demo/index.html b/demo/index.html index 036f8f5..563b040 100644 --- a/demo/index.html +++ b/demo/index.html @@ -8,27 +8,29 @@ html, body { height: 100%; - padding: 0; margin: 0; + padding: 0; } - .outer { - display: flex; - height: 100%; - align-items: center; - justify-content: center; + body { + padding: 12px; } #container { - height: 50%; + height: 400px; width: 800px; } + + #stats { + background-color: rgba(255, 255, 255, 0.8); + max-width: 100%; + overflow-y: auto; + } -
-
-
-
+
+

Stats

+
diff --git a/demo/index.ts b/demo/index.ts index dee5a49..e8c05f5 100644 --- a/demo/index.ts +++ b/demo/index.ts @@ -1,7 +1,9 @@ import { load } from '@2gis/mapgl'; import { GltfPlugin } from '../src/index'; -import { realtyScene } from './realtySceneData'; +import { REALTY_SCENE, REALTY_SCENE_1 } from './mocks'; + +let isDarkTheme = false; async function start() { const mapglAPI = await load(); @@ -18,9 +20,10 @@ async function start() { (window as any).map = map; const plugin = new GltfPlugin(map, { - modelsLoadStrategy: 'waitAll', + modelsLoadStrategy: 'dontWaitAll', modelsBaseUrl: 'https://disk.2gis.com/digital-twin/models_s3/realty_ads/zgktechnology/', dracoScriptsUrl: 'libs/draco/', + floorsControl: { position: 'centerRight' }, poiConfig: { primary: { fontSize: 14, @@ -34,12 +37,87 @@ async function start() { }, }); - const defaultState = { - modelId: '03a234cb', - // floorId: '235034', - }; + (window as any).gltfPlugin = plugin; + (window as any).realtyScene = REALTY_SCENE; + + new mapglAPI.Control(map, '', { + position: 'topLeft', + }) + .getContainer() + .addEventListener('click', () => { + plugin.removeRealtyScene(); + plugin.addRealtyScene(REALTY_SCENE, { modelId: '03a234cb', floorId: '235034' }); + }); + + new mapglAPI.Control(map, '', { + position: 'topLeft', + }) + .getContainer() + .addEventListener('click', () => { + plugin.removeRealtyScene(); + }); + + new mapglAPI.Control(map, '', { + position: 'topLeft', + }) + .getContainer() + .addEventListener('click', () => { + plugin.removeRealtyScene(); + plugin.addRealtyScene(REALTY_SCENE_1, { modelId: 'ds321ba234cb' }); + }); + + new mapglAPI.Control(map, '', { + position: 'topLeft', + }) + .getContainer() + .addEventListener('click', () => { + plugin.removeRealtyScene(); + }); + + new mapglAPI.Control(map, '', { + position: 'topLeft', + }) + .getContainer() + .addEventListener('click', () => { + plugin.addModel(REALTY_SCENE[0]); + }); + + new mapglAPI.Control(map, '', { + position: 'topLeft', + }) + .getContainer() + .addEventListener('click', () => { + plugin.removeModel(REALTY_SCENE[0].modelId); + }); - plugin.addRealtyScene(realtyScene); + new mapglAPI.Control(map, '', { + position: 'topLeft', + }) + .getContainer() + .addEventListener('click', () => { + plugin.addModels(REALTY_SCENE.slice(1)); + }); + + new mapglAPI.Control(map, '', { + position: 'topLeft', + }) + .getContainer() + .addEventListener('click', () => { + plugin.removeModels(REALTY_SCENE.slice(1).map((m) => m.modelId)); + }); + + new mapglAPI.Control(map, '', { + position: 'topLeft', + }) + .getContainer() + .addEventListener('click', () => { + map.setStyleById( + isDarkTheme + ? 'c080bb6a-8134-4993-93a1-5b4d8c36a59b' + : 'e05ac437-fcc2-4845-ad74-b1de9ce07555', + ); + isDarkTheme = !isDarkTheme; + }); (['click'] as const).forEach((eventName) => { plugin.on(eventName, (e) => { @@ -47,80 +125,21 @@ async function start() { }); }); - /* - const models: ModelOptions[] = []; - for (let i = 0; i < 10; i++) { - let lonRnd = (Math.random() / 100) * (Math.random() > 0.5 ? 1 : -1); - let latRnd = (Math.random() / 100) * (Math.random() > 0.5 ? 1 : -1); - models.push({ - modelId: i, - coordinates: [82.8865 + lonRnd, 54.9809 + latRnd], - modelUrl: 'models/cube_draco.glb', - rotateX: 90, - scale: 3000, - linkedIds: ['141373143530065', '70030076379181421'], - userData: { - test: 'Test userData ' + i, - }, - }); - } - - plugin - .addModels(models) - .then(() => { - console.log('Models are loaded'); - }) - .catch((e) => { - console.error(e); - }); + const statsTable = document.getElementById('stats'); - plugin.addPoiGroup( - { - id: 1, - type: 'primary', - minZoom: 15, - elevation: 130, - fontSize: 16, - fontColor: '#3a3a3a', - data: [ - { - coordinates: [82.886454, 54.980388], - elevation: 130, - label: '3к\n78.4 м²', - userData: { - url: 'https://a101.ru/kvartiry/360810/', - }, - }, - ], - }, - { - modelId: '12345', - floorId: '234234', - }, - ); - - plugin.addPoiGroup( - { - id: 2, - type: 'secondary', - minZoom: 17, - elevation: 30, - data: [ - { - coordinates: [82.886554, 54.980988], - label: '10 м²', - userData: { - url: 'https://a101.ru/kvartiry/360810/', - }, - }, - ], - }, - { - modelId: '12345', - floorId: '234234', - }, - ); - */ + const printStats = () => { + if (!statsTable) { + return; + } + statsTable.innerHTML = `
${JSON.stringify(
+            plugin.getModelRendererInfo(),
+            null,
+            2,
+        )}
`; + + requestAnimationFrame(printStats); + }; + requestAnimationFrame(printStats); } start(); diff --git a/demo/mocks.ts b/demo/mocks.ts new file mode 100644 index 0000000..bd053ba --- /dev/null +++ b/demo/mocks.ts @@ -0,0 +1,403 @@ +import { BuildingOptions } from '../src/types/realtyScene'; + +export const REALTY_SCENE: BuildingOptions[] = [ + { + modelId: '03a234cb', + coordinates: [47.245286302641034, 56.134743473834099], + modelUrl: 'zgktechnology1.glb', + rotateX: 90, + rotateY: -15.1240072739039, + scale: 191.637678, + linkedIds: ['70030076555821177'], + mapOptions: { + center: [47.24547737708662, 56.134591508663135], + pitch: 40, + zoom: 19, + rotation: -41.4, + }, + popupOptions: { + coordinates: [47.24511721603574, 56.13451456056651], + title: 'Корпус 1. 11 этажей', + description: 'Срок сдачи: IV кв. 2024 г.
15 мин. пешком до ст. м. Московская', + }, + floors: [ + { + id: '235034', + text: '1-10', + modelUrl: 'zgktechnology1_floor2.glb', + mapOptions: { + center: [47.24524342863023, 56.13449524271827], + pitch: 40, + zoom: 20, + rotation: -57.5, + }, + poiGroups: [ + { + id: 1111, + type: 'primary', + minZoom: 19.5, + elevation: 5, + fontSize: 12, + fontColor: '#3a3a3a', + data: [ + { + coordinates: [47.245048150280994, 56.134470449142164], + label: '3к\n78.4 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.24520807647288, 56.13443854463778], + label: '2к\n67 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.245350349632965, 56.134414208205776], + label: '1к\n40 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.24542896512635, 56.13448965532694], + label: '3к\n90 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.24510451854659, 56.134541185948585], + label: '3к\n77.2 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + ], + }, + ], + }, + { + id: '000034', + text: '11', + modelUrl: 'zgktechnology1_floor11.glb', + mapOptions: { + center: [47.24556663327373, 56.13456998211929], + pitch: 40, + zoom: 19.5, + rotation: -62.6, + }, + poiGroups: [ + { + id: 1111, + type: 'primary', + minZoom: 19, + elevation: 35, + fontSize: 12, + fontColor: '#3a3a3a', + data: [ + { + coordinates: [47.245048150280994, 56.134470449142164], + label: '3к\n78.4 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.24520807647288, 56.13443854463778], + label: '2к\n67 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.245350349632965, 56.134414208205776], + label: '1к\n40 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.24542896512635, 56.13448965532694], + label: '3к\n90 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.24510451854659, 56.134541185948585], + label: '3к\n77.2 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + ], + }, + ], + }, + ], + }, + { + modelId: '1ba234cb', + coordinates: [47.245286302641034, 56.134743473834099], + modelUrl: 'zgktechnology2.glb', + rotateX: 90, + rotateY: -15.1240072739039, + scale: 191.637678, + linkedIds: ['70030076555823021'], + mapOptions: { + center: [47.245008950283065, 56.1344698491912], + pitch: 45, + zoom: 18.7, + rotation: -129, + }, + popupOptions: { + coordinates: [47.24448882381944, 56.13468481517748], + title: 'Корпус 1. 16 этажей', + description: 'Срок сдачи: IV кв. 2024 г.
15 мин. пешком до ст. м. Московская', + }, + floors: [ + { + id: 'aaa777', + text: '2-15', + modelUrl: 'zgktechnology2_floor2.glb', + mapOptions: { + center: [47.24463456947374, 56.134675042798094], + pitch: 35, + zoom: 20, + rotation: -130, + }, + poiGroups: [ + { + id: 1111, + type: 'primary', + minZoom: 19.7, + elevation: 7, + fontSize: 12, + fontColor: '#3a3a3a', + data: [ + { + coordinates: [47.24452417991248, 56.13469284843933], + label: '1к\n27 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.24457199258783, 56.13477179423035], + label: '2к\n54.4 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.244491707517696, 56.13463324895681], + label: '1к\n27 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.244467722972786, 56.13455859493207], + label: '3к\n67 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.24459718584492, 56.13483803780593], + label: '1к\n30 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.24474865936005, 56.13481340001352], + label: '2к\n45 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.244714550432995, 56.13474141463477], + label: '3к\n54.4 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.24464159162246, 56.134578465378226], + label: '1к\n33 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.24461054223749, 56.13451937931448], + label: '2к\n45 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + ], + }, + ], + }, + { + id: 'bbb555', + text: '16', + modelUrl: 'zgktechnology2_floor16.glb', + mapOptions: { + center: [47.24498428988907, 56.134514900849325], + pitch: 35, + zoom: 19.2, + rotation: -130, + }, + poiGroups: [ + { + id: 1111, + type: 'primary', + minZoom: 18.9, + elevation: 53, + fontSize: 12, + fontColor: '#3a3a3a', + data: [ + { + coordinates: [47.24452417991248, 56.13469284843933], + label: '1к\n27 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.24457199258783, 56.13477179423035], + label: '2к\n54.4 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.244491707517696, 56.13463324895681], + label: '1к\n27 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.244467722972786, 56.13455859493207], + label: '3к\n67 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.24459718584492, 56.13483803780593], + label: '1к\n30 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.24474865936005, 56.13481340001352], + label: '2к\n45 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.244714550432995, 56.13474141463477], + label: '3к\n54.4 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.24464159162246, 56.134578465378226], + label: '1к\n33 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + { + coordinates: [47.24461054223749, 56.13451937931448], + label: '2к\n45 м²', + userData: { + url: 'https://a101.ru/kvartiry/360810/', + }, + }, + ], + }, + ], + }, + ], + }, + { + modelId: 'eda234cb', + coordinates: [47.245286302641034, 56.134743473834099], + modelUrl: 'zgktechnology_construction.glb', + rotateX: 90, + rotateY: -15.1240072739039, + scale: 191.637678, + linkedIds: ['70030076561388553'], + interactive: false, + }, +]; + +export const REALTY_SCENE_1: BuildingOptions[] = [ + { + modelId: 'ds321ba234cb', + coordinates: [47.245286302641034, 56.134743473834099], + modelUrl: 'zgktechnology2.glb', + rotateX: 90, + rotateY: -15.1240072739039, + scale: 191.637678, + linkedIds: ['70030076555823021', '70030076555821177', '70030076555823021'], + mapOptions: { + center: [47.245008950283065, 56.1344698491912], + pitch: 45, + zoom: 18.7, + rotation: -129, + }, + popupOptions: { + coordinates: [47.24448882381944, 56.13468481517748], + title: 'Корпус 1. 16 этажей', + description: 'Срок сдачи: IV кв. 2024 г.
15 мин. пешком до ст. м. Московская', + }, + floors: [ + { + id: '432aaa777', + text: '2-15', + modelUrl: 'zgktechnology2_floor2.glb', + mapOptions: { + center: [47.24463456947374, 56.134675042798094], + pitch: 35, + zoom: 20, + rotation: -130, + }, + }, + { + id: '4321bbb555', + text: '16', + modelUrl: 'zgktechnology2_floor16.glb', + mapOptions: { + center: [47.24498428988907, 56.134514900849325], + pitch: 35, + zoom: 19.2, + rotation: -130, + }, + }, + ], + }, + { + modelId: '345feda234cb', + coordinates: [47.245286302641034, 56.134743473834099], + modelUrl: 'zgktechnology_construction.glb', + rotateX: 90, + rotateY: -15.1240072739039, + scale: 191.637678, + linkedIds: ['70030076561388553'], + interactive: false, + }, +]; diff --git a/jest.config.js b/jest.config.js index a00a286..f13d1a6 100644 --- a/jest.config.js +++ b/jest.config.js @@ -29,6 +29,7 @@ module.exports = { preset: 'ts-jest', globals: { 'ts-jest': { + tsConfig: 'tsconfig.test.json', diagnostics: { // Игнорируем воргинги про esModuleInterop, которые нам чинить, кажется не требуется // потому что в тестах импорты работают без проблем. diff --git a/package.json b/package.json index 8299285..6e990c0 100644 --- a/package.json +++ b/package.json @@ -8,9 +8,7 @@ "type": "git", "url": "https://github.com/2gis/mapgl-gltf.git" }, - "files": [ - "dist/*" - ], + "files": ["dist/libs", "dist/types"], "scripts": { "build": "npm run build:bundle && npm run build:typings && npm run build:transpile && npm run build:docs", "build:bundle": "webpack --env type=production", diff --git a/src/control/control.module.css b/src/control/control.module.css index 0c404f6..da6670f 100644 --- a/src/control/control.module.css +++ b/src/control/control.module.css @@ -125,6 +125,9 @@ position: relative; text-align: center; height: 100%; + display: flex; + align-items: center; + justify-content: center; } ._hasResult:after { diff --git a/src/index.ts b/src/index.ts index 52ee077..278d684 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,3 +16,4 @@ if (typeof window !== 'undefined') { } export { GltfPlugin }; +export * from './types'; diff --git a/src/plugin.ts b/src/plugin.ts index bab746d..9489d69 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -17,12 +17,15 @@ import type { } from './types/plugin'; import type { BuildingOptions } from './types/realtyScene'; import type { GltfPluginEventTable } from './types/events'; +import { applyOptionalDefaults, disposeObject } from './utils/common'; export class GltfPlugin extends Evented { + private isThreeJsInitialized = false; private renderer = new THREE.WebGLRenderer(); private camera = new THREE.PerspectiveCamera(); private scene = new THREE.Scene(); private tmpMatrix = new THREE.Matrix4(); + private viewport: DOMRect; private map: MapGL; private options = defaultOptions; @@ -35,6 +38,8 @@ export class GltfPlugin extends Evented { private realtyScene?: RealtyScene; private modelOptions = new Map(); + private linkedIds = new Set(); + /** * The main class of the plugin * @@ -63,7 +68,8 @@ export class GltfPlugin extends Evented { super(); this.map = map; - this.options = { ...this.options, ...pluginOptions }; + + this.options = applyOptionalDefaults(pluginOptions ?? {}, this.options); this.viewport = this.map.getContainer().getBoundingClientRect(); @@ -76,13 +82,44 @@ export class GltfPlugin extends Evented { this.poiGroups = new PoiGroups(this.map, this.options.poiConfig); - map.once('idle', () => { - this.poiGroups.addIcons(); - this.addThreeJsLayer(); + this.map.once('idle', () => { + // It's important to add all style layers before binding even handlers. + this.onStyleLoad(); this.initEventHandlers(); + + // Also, we need to add all style layer again after each initialization of the new map style. + // But there is no need to bind event handlers. + this.map.on('styleload', this.onStyleLoad); + }); + } + + private onStyleLoad = () => { + const hiddenIds = Array.from(this.linkedIds); + if (hiddenIds.length) { + this.map.setHiddenObjects(hiddenIds); + } + + this.addThreeJsLayer(); + this.poiGroups.onMapStyleUpdate(); + }; + + private addLinkedIds(modelOptions: ModelOptions[], ids?: Id[]) { + modelOptions.forEach(({ modelId, linkedIds }) => { + if (linkedIds?.length && (!ids || ids.some((id) => id === modelId))) { + linkedIds.forEach((id) => this.linkedIds.add(id)); + } }); } + private removeLinkedIds(modelId: Id) { + const linkedIds = this.modelOptions.get(modelId.toString())?.linkedIds; + linkedIds?.forEach((id) => this.linkedIds.delete(id)); + } + + private getLinkedIds() { + return Array.from(this.linkedIds); + } + /** * Add the list of models to the map * Use this method if you want to add @@ -91,26 +128,10 @@ export class GltfPlugin extends Evented { * @param modelOptions An array of models' options */ public async addModels(modelOptions: ModelOptions[]) { - await this.waitForPluginInit; - - const loadedModels = this.startModelLoading(modelOptions); - - return Promise.all(loadedModels).then(() => { - if (this.options.modelsLoadStrategy === 'waitAll') { - for (let options of modelOptions) { - this.modelOptions.set(String(options.modelId), options); - if (options.linkedIds) { - this.map.setHiddenObjects(options.linkedIds); - } - } - const ids = modelOptions.map((opt) => opt.modelId); - for (let id of ids) { - this.addModelFromCache(id); - } - this.map.triggerRerender(); - } - this.invalidateViewport(); - }); + return this.addModelsPartially( + modelOptions, + modelOptions.map((opt) => opt.modelId), + ); } /** @@ -126,25 +147,45 @@ export class GltfPlugin extends Evented { public async addModelsPartially(modelOptions: ModelOptions[], ids: Id[]) { await this.waitForPluginInit; + this.addLinkedIds(modelOptions, ids); + const loadedModels = this.startModelLoading(modelOptions, ids); return Promise.all(loadedModels).then(() => { + for (let options of modelOptions) { + this.modelOptions.set(String(options.modelId), options); + } + if (this.options.modelsLoadStrategy === 'waitAll') { - for (let options of modelOptions) { - this.modelOptions.set(String(options.modelId), options); - if (options.linkedIds) { - this.map.setHiddenObjects(options.linkedIds); - } - } + this.map.setHiddenObjects(this.getLinkedIds()); for (let id of ids) { this.addModelFromCache(id); } this.map.triggerRerender(); } + this.invalidateViewport(); }); } + /** + * Remove models from the map and cache or from the map only + * + * @param id An array of models identifiers to delete + * @param preserveCache Flag to keep the model in the cache + */ + public async removeModels(ids: Id[], preserveCache?: boolean) { + ids.forEach((id) => this.removeModel(id, preserveCache)); + } + + /** + * @internal + * @hidden + */ + public getModelRendererInfo = () => { + return this.renderer.info; + }; + /** * Add model to the map * @@ -153,6 +194,8 @@ export class GltfPlugin extends Evented { public async addModel(modelOptions: ModelOptions) { await this.waitForPluginInit; + this.addLinkedIds([modelOptions]); + return this.loader.loadModel(modelOptions).then(() => { this.modelOptions.set(String(modelOptions.modelId), modelOptions); if (modelOptions.linkedIds) { @@ -171,20 +214,22 @@ export class GltfPlugin extends Evented { * @param preserveCache Flag to keep the model in the cache */ public removeModel(id: Id, preserveCache?: boolean) { + this.removeLinkedIds(id); + const model = this.models.get(String(id)); - if (model === undefined) { - return; + if (model !== undefined) { + this.scene.remove(model); + disposeObject(model); + this.map.triggerRerender(); } - this.scene.remove(model); + if (!preserveCache) { const options = this.modelOptions.get(String(id)); if (options !== undefined && options.linkedIds !== undefined) { this.map.unsetHiddenObjects(options.linkedIds); } this.models.delete(String(id)); - this.disposeObject(model); } - this.map.triggerRerender(); } /** @@ -227,23 +272,34 @@ export class GltfPlugin extends Evented { this.models, this.options, ); + return this.realtyScene.addRealtyScene(scene, state); } - private invalidateViewport() { + /** + * Remove interactive realty scene from the map + * + * @param preserveCache Flag to keep the model in the cache + */ + public removeRealtyScene(preserveCache?: boolean) { + if (!this.realtyScene) { + return; + } + + this.realtyScene.destroy(preserveCache); + this.realtyScene = undefined; + } + + private invalidateViewport = () => { const container = this.map.getContainer(); this.viewport = container.getBoundingClientRect(); this.eventSource?.updateViewport(this.viewport); - } + }; - private initEventHandlers() { - this.map.on('resize', () => { - this.invalidateViewport(); - }); + private initEventHandlers = () => { + this.map.on('resize', this.invalidateViewport); - window.addEventListener('resize', () => { - this.invalidateViewport(); - }); + window.addEventListener('resize', this.invalidateViewport); this.eventSource = new EventSource(this.map, this.viewport, this.camera, this.scene); for (let eventName of this.eventSource.getEvents()) { @@ -251,7 +307,7 @@ export class GltfPlugin extends Evented { this.emit(eventName, e); }); } - } + }; private render() { this.camera.projectionMatrix.fromArray(this.map.getProjectionMatrixForGltfPlugin()); @@ -286,6 +342,12 @@ export class GltfPlugin extends Evented { } private initThree() { + if (this.isThreeJsInitialized) { + return; + } + + this.isThreeJsInitialized = true; + this.camera = new THREE.PerspectiveCamera(); this.renderer = new THREE.WebGLRenderer({ @@ -306,7 +368,7 @@ export class GltfPlugin extends Evented { private addThreeJsLayer() { this.map.addLayer({ - id: 'threeJsLayer', + id: 'gltf-plugin-style-layer', type: 'custom', onAdd: () => this.initThree(), render: () => this.render(), @@ -337,31 +399,4 @@ export class GltfPlugin extends Evented { } return Boolean(model); } - - /** - * Delete from memory all allocated objects by Object3D - * https://threejs.org/docs/#manual/en/introduction/How-to-dispose-of-objects - */ - private disposeObject(inputObj: THREE.Object3D) { - inputObj.traverse((obj) => { - if (obj instanceof THREE.Mesh) { - const geometry = obj.geometry; - const material = obj.material; - - if (geometry) { - geometry.dispose(); - } - - if (material) { - const texture = material.map; - - if (texture) { - texture.dispose(); - } - - material.dispose(); - } - } - }); - } } diff --git a/src/poiGroups.ts b/src/poiGroups.ts index e93da69..0f69cb5 100644 --- a/src/poiGroups.ts +++ b/src/poiGroups.ts @@ -8,10 +8,11 @@ type FeaturePoint = Feature; export class PoiGroups { private poiSources = new Map(); + private activePoiGroupOptions?: PoiGroupOptions; constructor(private map: MapGL, private poiConfig: PluginOptions['poiConfig']) {} - public addIcons() { + public onMapStyleUpdate() { this.map.addIcon('km_pillar_gray_border', { url: 'https://disk.2gis.com/styles/d7e8aed1-4d3f-472a-a1e4-337f4b31ab8a/km_pillar_gray_border', // @ts-ignore @@ -20,9 +21,14 @@ export class PoiGroups { stretchX: [[4, 24]], stretchY: [[4, 24]], }); + + if (this.activePoiGroupOptions) { + this.addPoiStyleLayer(this.activePoiGroupOptions); + } } public async add(groupOptions: PoiGroupOptions, state?: BuildingState) { + this.activePoiGroupOptions = groupOptions; const { id, data } = groupOptions; const actualId = String(id); if (this.poiSources.get(actualId) !== undefined) { @@ -47,6 +53,7 @@ export class PoiGroups { } public remove(origId: Id) { + this.activePoiGroupOptions = undefined; const id = String(origId); const source = this.poiSources.get(id); this.poiSources.delete(id); diff --git a/src/realtyScene/realtyScene.ts b/src/realtyScene/realtyScene.ts index c9818df..c50fc17 100644 --- a/src/realtyScene/realtyScene.ts +++ b/src/realtyScene/realtyScene.ts @@ -16,7 +16,11 @@ import type { PopupOptions, } from '../types/realtyScene'; import type { ControlShowOptions, FloorLevel, FloorChangeEvent } from '../control/types'; -import type { PoiGeoJsonProperties } from '../types/events'; +import type { + GltfPluginModelEvent, + GltfPluginPoiEvent, + PoiGeoJsonProperties, +} from '../types/events'; export class RealtyScene { private activeBuilding?: BuildingOptions; @@ -148,63 +152,59 @@ export class RealtyScene { const controlOptions = this.createControlOptions(scene, state); this.control?.show(controlOptions); if (state.floorId) { - this.eventSource?.setCurrentFloorId(state.floorId); + this.eventSource.setCurrentFloorId(state.floorId); } } // bind all events - this.bindRealtySceneEvents(scene); + this.bindRealtySceneEvents(); }); } - private bindRealtySceneEvents(scene: BuildingOptions[]) { - if (this.control === undefined) { - return; - } + public destroy(preserveCache?: boolean) { + this.unbindRealtySceneEvents(); - this.control.on('floorChange', (ev) => { - this.floorChangeHandler(ev); - }); + this.plugin.removeModels( + this.scene?.reduce((agg, opts) => { + agg.push(opts.modelId); + opts.floors?.forEach((floor) => agg.push(floor.id)); - this.plugin.on('click', (ev) => { - if (ev.target.type === 'model') { - const id = ev.target.modelId; - if (this.isFacadeBuilding(id)) { - this.buildingClickHandler(scene, id); - } - } + return agg; + }, []) ?? [], + preserveCache, + ); - if (ev.target.type === 'poi') { - this.poiClickHandler(ev.target.data); - } - }); + this.clearPoiGroups(); + this.eventSource.setCurrentFloorId(null); - this.plugin.on('mouseover', (ev) => { - if (ev.target.type === 'model') { - const id = ev.target.modelId; - if (this.isFacadeBuilding(id)) { - this.container.style.cursor = 'pointer'; - this.toggleHighlightModel(id); - let popupOptions = this.getPopupOptions(id); - if (popupOptions) { - this.showPopup(popupOptions); - } - } - } - }); + this.control?.destroy(); + this.control = undefined; - this.plugin.on('mouseout', (ev) => { - if (ev.target.type === 'model') { - const id = ev.target.modelId; - if (this.isFacadeBuilding(id)) { - this.container.style.cursor = ''; - this.hidePopup(); - if (this.prevHoveredModelId !== null) { - this.toggleHighlightModel(id); - } - } - } - }); + this.popup?.destroy(); + this.popup = null; + + this.activeBuilding = undefined; + this.activeModelId = undefined; + this.activePoiGroupIds = []; + this.buildingFacadeIds = []; + this.prevHoveredModelId = null; + this.scene = null; + } + + private bindRealtySceneEvents() { + this.plugin.on('click', this.onSceneClick); + this.plugin.on('mouseover', this.onSceneMouseOver); + this.plugin.on('mouseout', this.onSceneMouseOut); + + this.control?.on('floorChange', this.floorChangeHandler); + } + + private unbindRealtySceneEvents() { + this.plugin.off('click', this.onSceneClick); + this.plugin.off('mouseover', this.onSceneMouseOver); + this.plugin.off('mouseout', this.onSceneMouseOut); + + this.control?.off('floorChange', this.floorChangeHandler); } private createControlOptions(scene: BuildingOptions[], buildingState: BuildingState) { @@ -282,7 +282,50 @@ export class RealtyScene { return building.popupOptions; } - private poiClickHandler(data: PoiGeoJsonProperties) { + private onSceneMouseOver = (ev: GltfPluginPoiEvent | GltfPluginModelEvent) => { + if (ev.target.type === 'model') { + const id = ev.target.modelId; + if (this.isFacadeBuilding(id)) { + this.container.style.cursor = 'pointer'; + this.toggleHighlightModel(id); + let popupOptions = this.getPopupOptions(id); + if (popupOptions) { + this.showPopup(popupOptions); + } + } + } + }; + private onSceneMouseOut = (ev: GltfPluginPoiEvent | GltfPluginModelEvent) => { + if (ev.target.type === 'model') { + const id = ev.target.modelId; + if (this.isFacadeBuilding(id)) { + this.container.style.cursor = ''; + this.hidePopup(); + if (this.prevHoveredModelId !== null) { + this.toggleHighlightModel(id); + } + } + } + }; + + private onSceneClick = (ev: GltfPluginPoiEvent | GltfPluginModelEvent) => { + if (this.scene === null) { + return; + } + + if (ev.target.type === 'model') { + const id = ev.target.modelId; + if (this.isFacadeBuilding(id)) { + this.buildingClickHandler(this.scene, id); + } + } + + if (ev.target.type === 'poi') { + this.poiClickHandler(ev.target.data); + } + }; + + private poiClickHandler = (data: PoiGeoJsonProperties) => { const url: string | undefined = data.userData.url; if (url !== undefined) { const a = document.createElement('a'); @@ -290,9 +333,9 @@ export class RealtyScene { a.setAttribute('target', '_blank'); a.click(); } - } + }; - private floorChangeHandler(ev: FloorChangeEvent) { + private floorChangeHandler = (ev: FloorChangeEvent) => { const model = this.activeBuilding; if (model !== undefined && model.floors !== undefined) { if (this.popup !== null) { @@ -346,9 +389,9 @@ export class RealtyScene { } } } - } + }; - private buildingClickHandler(scene: BuildingOptions[], modelId: Id) { + private buildingClickHandler = (scene: BuildingOptions[], modelId: Id) => { const selectedBuilding = scene.find((model) => model.modelId === modelId); if (selectedBuilding === undefined) { return; @@ -428,7 +471,7 @@ export class RealtyScene { } this.activeBuilding = selectedBuilding; - } + }; private addFloorPoi(floorOptions?: BuildingFloorOptions) { if (floorOptions === undefined) { @@ -460,11 +503,14 @@ export class RealtyScene { this.activePoiGroupIds = []; } + // TODO: Don't mutate scene data. private makeUniqueFloorIds(scene: BuildingOptions[]) { for (let scenePart of scene) { const floors = scenePart.floors ?? []; for (let floor of floors) { - floor.id = createCompoundId(scenePart.modelId, floor.id); + if (!floor.id.toString().startsWith(scenePart.modelId.toString())) { + floor.id = createCompoundId(scenePart.modelId, floor.id); + } } } } diff --git a/src/types/events.ts b/src/types/events.ts index d0451eb..2d68965 100644 --- a/src/types/events.ts +++ b/src/types/events.ts @@ -1,4 +1,4 @@ -import type { Id, ModelOptions, PoiOptions } from '../types/plugin'; +import type { Id, ModelOptions, PoiOptions } from './plugin'; export type PoiGeoJsonProperties = PoiOptions & { /** diff --git a/src/types/index.ts b/src/types/index.ts new file mode 100644 index 0000000..324ca4f --- /dev/null +++ b/src/types/index.ts @@ -0,0 +1,3 @@ +export * from './events'; +export * from './plugin'; +export * from './realtyScene'; diff --git a/src/types/plugin.ts b/src/types/plugin.ts index e0e9304..284f4d6 100644 --- a/src/types/plugin.ts +++ b/src/types/plugin.ts @@ -2,8 +2,9 @@ export type Id = string | number; export type ColorModelString = `${'rgb' | 'hsl'}(${string})`; export type HexColorString = `#${string}`; + /** - * Color represantation can be rgb(), hsl(), or hex value + * Color representation can be rgb(), hsl(), or hex value */ export type ColorRepresentation = ColorModelString | HexColorString | number; @@ -20,7 +21,7 @@ export interface AmbientLightOptions { * Numeric value of the light's strength/intensity. * @default 3 */ - intencity: number; + intencity: number; // TODO: MAJOR. Rename to «intensity» in the next major release. } /** @@ -64,6 +65,7 @@ export interface ControlOptions { * Options for the highlight color of hovered models */ export interface HightlightOptions { + // TODO: MAJOR. Rename to «HighlightOptions» in the next major release. /** * Color of the hover * @default '#ffffff' @@ -73,7 +75,7 @@ export interface HightlightOptions { * Intensity of the color on the hover in the range from 0 to 1 * @default 0.0 */ - intencity: number; + intencity: number; // TODO: MAJOR. Rename to «intensity» in the next major release. } /** diff --git a/src/utils/common.ts b/src/utils/common.ts index b0a5891..5285874 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -1,3 +1,5 @@ +import * as THREE from 'three'; + export function clamp(value: number, min: number, max: number): number { value = Math.max(value, min); value = Math.min(value, max); @@ -22,3 +24,56 @@ export function createCompoundId(modelId: string | number, floorId?: string | nu } return `${modelId}_${floorId}`; } + +export type RequiredExcept = T & Required>; + +type RequiredOptional = Exclude< + { + [K in keyof T]: T extends Record ? never : K; + }[keyof T], + undefined +>; + +export type DefaultOptionalOptions = Required>>; + +export function applyOptionalDefaults( + params: T, + defaults: DefaultOptionalOptions, +): Required { + const result = { ...params }; + for (const keyString in defaults) { + const key = keyString as keyof DefaultOptionalOptions; + if (result[key] === undefined) { + result[key] = defaults[key]; + } + } + // мы точно уверенны что вернем Required + return result as Required; +} + +/** + * Delete from memory all allocated objects by Object3D + * https://threejs.org/docs/#manual/en/introduction/How-to-dispose-of-objects + */ +export function disposeObject(inputObj: THREE.Object3D) { + inputObj.traverse((obj) => { + if (obj instanceof THREE.Mesh) { + const geometry = obj.geometry; + const material = obj.material; + + if (geometry) { + geometry.dispose(); + } + + if (material) { + const texture = material.map; + + if (texture) { + texture.dispose(); + } + + material.dispose(); + } + } + }); +} diff --git a/test/index.ts b/test/index.ts index e8b0107..ead18dd 100644 --- a/test/index.ts +++ b/test/index.ts @@ -1,7 +1,5 @@ import { GltfPlugin } from '../src'; -import { OBJECTS_FOR_TESTS } from './utils'; -import { realtyScene } from '../demo/realtySceneData'; +import { MOCKS } from './mocks'; window.GltfPlugin = GltfPlugin; -window.OBJECTS_FOR_TESTS = OBJECTS_FOR_TESTS; // storage for any data for tests -window.OBJECTS_FOR_TESTS.mapRealtyScene = realtyScene; +window.MOCKS = MOCKS; // storage for any data for tests diff --git a/test/mocks/index.ts b/test/mocks/index.ts new file mode 100644 index 0000000..65b7cab --- /dev/null +++ b/test/mocks/index.ts @@ -0,0 +1,15 @@ +import { MODEL_CUBE_BIG, MODEL_CUBE_SMALL } from './models'; +import { POI_ASCII_LETTERS, POI_ENG_RUS_LETTERS } from './poi'; +import { REALTY_SCENE } from './realtyScene'; + +export const MOCKS = { + models: { + cubeBig: MODEL_CUBE_BIG, + cubeSmall: MODEL_CUBE_SMALL, + }, + poi: { + asciiLetters: POI_ASCII_LETTERS, + engRusLetters: POI_ENG_RUS_LETTERS, + }, + realtyScene: REALTY_SCENE, +}; diff --git a/test/mocks/models.ts b/test/mocks/models.ts new file mode 100644 index 0000000..373c3a5 --- /dev/null +++ b/test/mocks/models.ts @@ -0,0 +1,18 @@ +import { BuildingOptions } from '../../src/types/realtyScene'; + +export const MODEL_CUBE_BIG: BuildingOptions = { + modelId: 1, + coordinates: [82.886554, 54.98085], + modelUrl: 'models/cube_draco.glb', + rotateX: 90, + scale: 500, +}; + +export const MODEL_CUBE_SMALL: BuildingOptions = { + modelId: 2, + coordinates: [82.886454, 54.980588], + modelUrl: 'models/cube_draco.glb', + rotateX: 90, + rotateY: 31, + scale: 250, +}; diff --git a/test/mocks/poi.ts b/test/mocks/poi.ts new file mode 100644 index 0000000..4237560 --- /dev/null +++ b/test/mocks/poi.ts @@ -0,0 +1,39 @@ +import { PoiGroupOptions } from '../../src/types/plugin'; + +export const POI_ASCII_LETTERS: PoiGroupOptions = { + id: 1, + type: 'primary', + minZoom: 12, + elevation: 40, + fontSize: 10, + fontColor: '#aa3a3a', + data: [ + { + coordinates: [82.886454, 54.98075], + elevation: 30, + label: '@<>?|!@#$%\n^&*()_+-=\n3к\n78.4 м²', + userData: { + url: 'https://example.com/', + }, + }, + ], +}; + +export const POI_ENG_RUS_LETTERS: PoiGroupOptions = { + id: 2, + type: 'secondary', + minZoom: 12, + elevation: 20, + fontSize: 10, + fontColor: '#3a3a3a', + data: [ + { + coordinates: [82.886104, 54.98075], + elevation: 30, + label: 'qwe RTY пои ГРУП', + userData: { + url: 'https://example.com/', + }, + }, + ], +}; diff --git a/demo/realtySceneData.ts b/test/mocks/realtyScene.ts similarity index 99% rename from demo/realtySceneData.ts rename to test/mocks/realtyScene.ts index 0aa0f49..405c6f2 100644 --- a/demo/realtySceneData.ts +++ b/test/mocks/realtyScene.ts @@ -1,6 +1,6 @@ -import type { BuildingOptions } from '../src/types/realtyScene'; +import type { BuildingOptions } from '../../src/types/realtyScene'; -export const realtyScene: BuildingOptions[] = [ +export const REALTY_SCENE: BuildingOptions[] = [ { modelId: '03a234cb', coordinates: [47.245286302641034, 56.134743473834099], diff --git a/test/puppeteer/utils.ts b/test/puppeteer/utils.ts index ffe1679..7dd6da7 100644 --- a/test/puppeteer/utils.ts +++ b/test/puppeteer/utils.ts @@ -29,6 +29,16 @@ export const blankStyle: any = { layers: [], }; +// тип any, так как возможность задавать стиль напрямую не публичная +export const blankDarkStyle: any = { + version: 0, + name: 'empty', + background: { + color: '#424242', + }, + layers: [], +}; + export function makeScreenshotsPath(relativePath: string) { return `test/screenshots/__screenshots__/${relativePath}`; } diff --git a/test/screenshots/__screenshots__/plugin/add_realty_scene-snap.png b/test/screenshots/__screenshots__/plugin/add_realty_scene-snap.png index 337e9fb9484715c7837f9ad738aff27283cdaf4e..75328734a9b9e25a271f1570bdbca8285bc951df 100644 GIT binary patch literal 40709 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%0DJmtosx{rbE)pXhth7tQJ8M8ve) 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 N002ovPDHLkV1iBW3`76` literal 41282 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 O0000qNR2}49n7@a{d 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 z�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 literal 0 HcmV?d00001 diff --git a/test/screenshots/__screenshots__/plugin/remove_models-snap.png b/test/screenshots/__screenshots__/plugin/remove_models-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..6c12b57aee0580bb3e92020af36782965f8d6beb GIT binary patch literal 482 zcmeAS@N?(olHy`uVBq!ia0vp^(?FPm4M^HB7Cr(}jKx9jP7LeL$-D%z=Xkm}hE&XX zd+8u&g8{>V1GoORzu{@h-|f<@P%ivr;_IE)tsiXoS<3J~MMvnEQsO8V1GoORzu{@h-|f<@P%ivr;_IE)tsiXoS<3J~MMvnEQsO8 & { + ambientColor?: string; + modelsBaseUrl?: string; + } = {}, +) => { + await initMapWithOptions(page, { + style: blankStyle, + styleOptions: { + fontsPath: defaultFontsPath, + }, + // @ts-ignore + copyright: false, + zoomControl: false, + key: API_KEY, + zoom: 17.5, + center: opts.center ?? [82.88688745100029, 54.98064452796862], + rotation: opts.rotation ?? -111, + pitch: 45, + }); + + await page.evaluate( + ({ modelsUrl, color }) => { + window.gltfPlugin = new window.GltfPlugin(window.map, { + modelsLoadStrategy: 'dontWaitAll', + dracoScriptsUrl: 'libs/draco/', + ambientLight: { + color: color || '#ffffff', + intencity: 2.5, + }, + modelsBaseUrl: modelsUrl || undefined, + }); + }, + { + modelsUrl: opts.modelsBaseUrl ?? '', + color: opts.ambientColor ?? '', + }, + ); + + await waitForReadiness(page); +}; + /** * Tests for public methods new Gltf Plugin. * Only happy-path - * - **/ -describe('plugin', () => { + */ +describe('GltfPlugin', () => { let page: Page; - const dirPath = makeScreenshotsPath('plugin'); beforeEach(async () => { page = await pageSetUp(); - await initMapWithOptions(page, { - style: blankStyle, - styleOptions: { - fontsPath: defaultFontsPath, - }, - // @ts-ignore - copyright: false, - zoomControl: false, - key: API_KEY, - zoom: 17.5, - center: [82.88688745100029, 54.98064452796862], - rotation: -111, - pitch: 45, - }); - - await page.evaluate(() => { - window.gltfPlugin = new window.GltfPlugin(window.map, { - modelsLoadStrategy: 'dontWaitAll', - dracoScriptsUrl: 'libs/draco/', - ambientLight: { color: '#ffffff', intencity: 2.5 }, - }); - }); - await waitForReadiness(page); }); afterEach(async () => { @@ -51,50 +72,31 @@ describe('plugin', () => { }); // Case for verify another ambient light at the scene - it('_constructor', async () => { - await page.close(); - page = await pageSetUp(); - await initMapWithOptions(page, { - style: blankStyle, - styleOptions: { - fontsPath: defaultFontsPath, - }, - // @ts-ignore - copyright: false, - zoomControl: false, - key: API_KEY, - zoom: 17.5, - center: [82.88688745100029, 54.98064452796862], - rotation: -111, - pitch: 45, - }); + it('#_constructor', async () => { + await init(page, { ambientColor: '#ff0000' }); await page.evaluate(() => { - window.gltfPlugin = new window.GltfPlugin(window.map, { - modelsLoadStrategy: 'dontWaitAll', - dracoScriptsUrl: 'libs/draco/', - ambientLight: { color: '#ff0000', intencity: 2.5 }, - }); - return window.gltfPlugin.addModel(window.OBJECTS_FOR_TESTS.models.cubeBig); + return window.gltfPlugin.addModel(window.MOCKS.models.cubeBig); }); - await waitForReadiness(page); await makeSnapshot(page, dirPath, '_constructor'); }); - it('addModel', async () => { + it('#addModel', async () => { + await init(page); await page.evaluate(() => { - return window.gltfPlugin.addModel(window.OBJECTS_FOR_TESTS.models.cubeBig); + return window.gltfPlugin.addModel(window.MOCKS.models.cubeBig); }); await waitForReadiness(page); await makeSnapshot(page, dirPath, 'add_model'); }); - it('addModels', async () => { + it('#addModels', async () => { + await init(page); await page.evaluate(() => { return window.gltfPlugin.addModels([ - window.OBJECTS_FOR_TESTS.models.cubeBig, - window.OBJECTS_FOR_TESTS.models.cubeSmall, + window.MOCKS.models.cubeBig, + window.MOCKS.models.cubeSmall, ]); }); @@ -102,82 +104,112 @@ describe('plugin', () => { await makeSnapshot(page, dirPath, 'add_models'); }); - it('addPoiGroup', async () => { + it('#addPoiGroup', async () => { + await init(page); await page.evaluate(() => { - window.gltfPlugin.addPoiGroup(window.OBJECTS_FOR_TESTS.poi.asciiLetters); - window.gltfPlugin.addPoiGroup(window.OBJECTS_FOR_TESTS.poi.engRusLetters); + window.gltfPlugin.addPoiGroup(window.MOCKS.poi.asciiLetters); + window.gltfPlugin.addPoiGroup(window.MOCKS.poi.engRusLetters); }); await waitForReadiness(page); await makeSnapshot(page, dirPath, 'add_poi_group'); }); - it('removeModel', async () => { + it('#removeModel', async () => { + await init(page); await page.evaluate(() => { - return window.gltfPlugin.addModel(window.OBJECTS_FOR_TESTS.models.cubeBig); + return window.gltfPlugin.addModel(window.MOCKS.models.cubeBig); }); await page.evaluate(() => { - window.gltfPlugin.removeModel(window.OBJECTS_FOR_TESTS.models.cubeBig.modelId); + window.gltfPlugin.removeModel(window.MOCKS.models.cubeBig.modelId); }); await waitForReadiness(page); await makeSnapshot(page, dirPath, 'remove_model'); }); - it('removePoiGroup', async () => { + it('#removeModels', async () => { + await init(page); await page.evaluate(() => { - window.gltfPlugin.addPoiGroup(window.OBJECTS_FOR_TESTS.poi.asciiLetters); + return window.gltfPlugin.addModels([ + window.MOCKS.models.cubeBig, + window.MOCKS.models.cubeSmall, + ]); }); await page.evaluate(() => { - window.gltfPlugin.removePoiGroup(window.OBJECTS_FOR_TESTS.poi.asciiLetters.id); + window.gltfPlugin.removeModels([ + window.MOCKS.models.cubeBig.modelId, + window.MOCKS.models.cubeSmall.modelId, + ]); }); await waitForReadiness(page); - await makeSnapshot(page, dirPath, 'remove_poi_group'); + await makeSnapshot(page, dirPath, 'remove_models'); }); - it('addRealtyScene', async () => { - page = await pageSetUp(); - await initMapWithOptions(page, { - style: blankStyle, - styleOptions: { - fontsPath: defaultFontsPath, - }, - // @ts-ignore - copyright: false, - zoomControl: false, - key: API_KEY, - zoom: 17.5, - center: [47.245286302641034, 56.134743473834099], - rotation: 330, - pitch: 45, - }); - + it('#removePoiGroup', async () => { + await init(page); await page.evaluate(() => { - window.gltfPlugin = new window.GltfPlugin(window.map, { - modelsLoadStrategy: 'dontWaitAll', - dracoScriptsUrl: 'libs/draco/', - modelsBaseUrl: - 'https://disk.2gis.com/digital-twin/models_s3/realty_ads/zgktechnology/', - }); + window.gltfPlugin.addPoiGroup(window.MOCKS.poi.asciiLetters); }); - await waitForReadiness(page); await page.evaluate(() => { - return window.gltfPlugin.addRealtyScene(window.OBJECTS_FOR_TESTS.mapRealtyScene); + window.gltfPlugin.removePoiGroup(window.MOCKS.poi.asciiLetters.id); }); await waitForReadiness(page); - await makeSnapshot(page, dirPath, 'add_realty_scene'); + await makeSnapshot(page, dirPath, 'remove_poi_group'); }); - it('addModelsPartially', async () => { + it('#addModelsPartially', async () => { + await init(page); await page.evaluate(() => { return window.gltfPlugin.addModelsPartially( - [ - window.OBJECTS_FOR_TESTS.models.cubeBig, - window.OBJECTS_FOR_TESTS.models.cubeSmall, - ], - [window.OBJECTS_FOR_TESTS.models.cubeBig.modelId], + [window.MOCKS.models.cubeBig, window.MOCKS.models.cubeSmall], + [window.MOCKS.models.cubeBig.modelId], ); }); await waitForReadiness(page); await makeSnapshot(page, dirPath, 'add_models_partially'); }); + + describe('Realty scene', () => { + beforeEach(async () => { + await init(page, { + center: [47.245286302641034, 56.134743473834099], + rotation: 330, + modelsBaseUrl: + 'https://disk.2gis.com/digital-twin/models_s3/realty_ads/zgktechnology/', + }); + }); + + it('#addRealtyScene', async () => { + await page.evaluate(() => { + return window.gltfPlugin.addRealtyScene(window.MOCKS.realtyScene); + }); + await waitForReadiness(page); + await makeSnapshot(page, dirPath, 'add_realty_scene'); + }); + + it('#removeRealtyScene', async () => { + await page.evaluate(() => { + return window.gltfPlugin.addRealtyScene(window.MOCKS.realtyScene); + }); + await waitForReadiness(page); + await page.evaluate(() => { + return window.gltfPlugin.removeRealtyScene(); + }); + await waitForReadiness(page); + await makeSnapshot(page, dirPath, 'remove_realty_scene'); + }); + }); + + it('The model does not disappear after changing the map style.', async () => { + await init(page); + await page.evaluate(() => { + return window.gltfPlugin.addModel(window.MOCKS.models.cubeBig); + }); + await page.evaluate((style) => { + return (window.map as any).setStyle(style); + }, blankDarkStyle); + + await waitForReadiness(page); + await makeSnapshot(page, dirPath, 'change_style'); + }); }); diff --git a/test/test.d.ts b/test/test.d.ts index 795a8c2..d549a9b 100644 --- a/test/test.d.ts +++ b/test/test.d.ts @@ -1,6 +1,6 @@ import type { Map } from '@2gis/mapgl/types'; import { GltfPlugin } from '../src'; -import { OBJECTS_FOR_TESTS } from './utils'; +import { MOCKS } from './mocks'; declare global { interface Window { @@ -8,6 +8,6 @@ declare global { gltfPlugin: GltfPlugin; GltfPlugin: typeof GltfPlugin; ready: boolean; - OBJECTS_FOR_TESTS: OBJECTS_FOR_TESTS; + MOCKS: typeof MOCKS; } } diff --git a/test/utils.ts b/test/utils.ts deleted file mode 100644 index c5a82f5..0000000 --- a/test/utils.ts +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @param ms - * Pause script exec of milliseconds - * */ -export function sleep(ms: number) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} -/** - * Models and poi's for create objects at the scene - * */ -export const OBJECTS_FOR_TESTS = { - models: { - cubeBig: { - modelId: 1, - coordinates: [82.886554, 54.98085], - modelUrl: 'models/cube_draco.glb', - rotateX: 90, - scale: 500, - }, - cubeSmall: { - modelId: 2, - coordinates: [82.886454, 54.980588], - modelUrl: 'models/cube_draco.glb', - rotateX: 90, - rotateY: 31, - scale: 250, - }, - }, - poi: { - asciiLetters: { - id: 1, - type: 'primary', - minZoom: 12, - elevation: 40, - fontSize: 10, - fontColor: '#aa3a3a', - data: [ - { - coordinates: [82.886454, 54.98075], - elevation: 30, - label: '@<>?|!@#$%\n^&*()_+-=\n3к\n78.4 м²', - userData: { - url: 'https://example.com/', - }, - }, - ], - }, - engRusLetters: { - id: 2, - type: 'secondary', - minZoom: 12, - elevation: 20, - fontSize: 10, - fontColor: '#3a3a3a', - data: [ - { - coordinates: [82.886104, 54.98075], - elevation: 30, - label: 'qwe RTY пои ГРУП', - userData: { - url: 'https://example.com/', - }, - }, - ], - }, - }, -}; diff --git a/tsconfig.json b/tsconfig.json index 2f545a6..f8fa97d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,5 +12,5 @@ "outDir": "dist/", "sourceMap": true, }, - "include": ["project.d.ts","modules.d.ts", "src/**/*.ts", "test/test.d.ts"] + "include": ["project.d.ts", "modules.d.ts", "src/**/*.ts"] } diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 0000000..902fb3e --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + + "include": ["project.d.ts", "modules.d.ts", "src/**/*.ts", "test/test.d.ts"] +} diff --git a/webpack.config.js b/webpack.config.js index 1337055..fe33f74 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -27,6 +27,9 @@ module.exports = function (env, _argv) { { test: /\.ts$/, loader: 'ts-loader', + options: { + configFile: env.type === 'test' ? 'tsconfig.test.json' : 'tsconfig.json', + }, }, // For CSS modules {