From 285e41434ac9d1eb418f2a82962f6dd10446aac5 Mon Sep 17 00:00:00 2001 From: Severin Opel Date: Wed, 13 Nov 2019 12:42:06 +0100 Subject: [PATCH] Continued refactoring of the maps library. --- lib/pixi/maps/geographics.html | 10 +- lib/pixi/maps/geographics.js | 8 + lib/pixi/maps/geolayer.js | 164 +++++++++++++-------- lib/pixi/maps/mapapp.html | 9 +- lib/pixi/maps/mapapp.js | 15 +- lib/pixi/maps/mapview.js | 43 ++++-- lib/pixi/maps/overlay.js | 7 +- lib/pixi/maps/projections/projections.html | 4 +- lib/pixi/maps/scatter.js | 41 +++--- lib/pixi/maps/utils.js | 10 +- 10 files changed, 193 insertions(+), 118 deletions(-) diff --git a/lib/pixi/maps/geographics.html b/lib/pixi/maps/geographics.html index 2cc9a28..ec075e9 100644 --- a/lib/pixi/maps/geographics.html +++ b/lib/pixi/maps/geographics.html @@ -5,7 +5,10 @@ GeoGraphics - + + + + @@ -67,11 +70,11 @@ wikimedia ], (sprites) => { - let osmMap = new ImageMap(sprites.get(osmworld), new MapData(new Projection.Mercator()), { cover: false }) + let osmMap = new ImageMap(sprites.get(osmworld), new MapData(new Projection.Mercator()), { cover: true }) let wikimediaMap = new ImageMap(sprites.get(wikimedia), new MapData(new Projection.Robinson(10)), { baseZoomHeight: sprites.get(osmworld).texture.height, - cover: false + cover: true }) app.addMaps({ @@ -89,7 +92,6 @@ function enableSwitch(button, app) { button.addEventListener("click", () => { let next = app.mapList.next() - console.log(app.mapList) app.selectMap(next) }) } diff --git a/lib/pixi/maps/geographics.js b/lib/pixi/maps/geographics.js index 5b028dd..ae09aad 100644 --- a/lib/pixi/maps/geographics.js +++ b/lib/pixi/maps/geographics.js @@ -127,6 +127,14 @@ export class GeoGraphics { return this._position } + get layer() { + return this._layer ? this._layer : null + } + + setLayer(layer) { + this._layer = layer + } + // get map() { // if ( // this.graphics.layer && diff --git a/lib/pixi/maps/geolayer.js b/lib/pixi/maps/geolayer.js index 319346d..726ef0c 100644 --- a/lib/pixi/maps/geolayer.js +++ b/lib/pixi/maps/geolayer.js @@ -1,10 +1,8 @@ import { GeoMap } from './map.js' import MapView from './mapview.js' import { EventHandler } from './utils.js' - -import { PIXILayer } from '../../../../src/layers/js/layer.js' -import Logging from '../../logging.js' import { GeoGraphics } from './geographics.js' +import { MapList } from './maplist.js' //import { GeoGraphics } from "../pixi/geographics.js" /** @@ -13,7 +11,7 @@ import { GeoGraphics } from './geographics.js' * of the Adaption. */ export class GeoLayer { - constructor(displayObject) { + constructor(displayObject, opts = {}) { if (displayObject == null || !(displayObject instanceof PIXI.DisplayObject)) { console.error( `You need to provide a displayObject to make a ${this.constructor.name} out of it.`, @@ -22,15 +20,14 @@ export class GeoLayer { return null } else { this.geographics = [] - displayObject.map = this + // displayObject.map = this this.displayObject = displayObject - this.layers = [] - this.pixiAddChild = displayObject.addChild.bind(displayObject) displayObject.addChild = (...elements) => { elements.forEach(element => { if (element instanceof GeoGraphics) { + element.setLayer(this) this.geographics.push(element) this.pixiAddChild(element.graphics) } else { @@ -39,6 +36,62 @@ export class GeoLayer { }) } } + + this.name = opts['name'] != null ? opts.name : 'Unnamed Layer' + this.parent = null + this.parentMapLayerTransformedHandler = new EventHandler('onParentMapLayerTransformed') + this.layers = [] + this._visibility = { min: 0, max: Number.MAX_VALUE } + } + + parentMapLayerTransformed(mapLayer) { + this.layers.forEach(layer => { + if (!(layer instanceof MapList)) { + layer.parentMapLayerTransformed() + } + }) + + this.parentMapLayerTransformedHandler.call(null, mapLayer) + + this.rescaleChildren() + } + + rescaleChildren() { + let map = this.map + + if (this.rescale) { + if (map != null) { + let scale = map.image.scatter.scale + + this.displayObject.children.forEach(graphics => { + graphics.scale.set(1 / scale, 1 / scale) + }) + } + } + + let mapLayer = this.mapLayer + if (this.visibility && mapLayer != null) { + const zoom = mapLayer.mapview.zoom + + // TODO + // Currently I dont know what elemnts was. + // We just log an error and resolve this on a later point. + if (zoom > this.visibility.min && zoom < this.visibility.max) { + this.displayObject.children.forEach(it => (it.visible = true)) + } else { + this.displayObject.children.forEach(it => (it.visible = false)) + } + } + } + + set visibility(value) { + let { min = 0, max = Infinity } = value + console.log(min) + this._visibility = { min, max } + } + + get visibility() { + return this._visibility } addChild(element) { @@ -60,6 +113,8 @@ export class GeoLayer { this.layers.forEach(layer => { if (layer.adapt) layer.adapt(map) }) + + this.rescaleChildren() } else console.error('There was no map specified.', this) } @@ -72,19 +127,54 @@ export class GeoLayer { // } else super.place(geographic) // } + removeFromParent() { + if (this.parent) { + this.parent.removeLayer(this) + } + } + + removeLayer(layer) { + let idx = this.layers.indexOf(layer) + if (idx != -1) { + layer.parent = null + this.layers.splice(idx, 1) + + if (layer.displayObject.parent) { + layer.displayObject.parent.removeChild(layer.displayObject) + } + } else console.warn('Tried to remove layer that was not set.', this, layer) + } + + set parent(parent) { + this._parent = parent + } + + get parent() { + return this._parent + } + addLayer(layer) { if (layer instanceof GeoLayer || layer instanceof MapLayer) { + layer.removeFromParent() + this.layers.push(layer) + layer.parent = this + layer.parentChanged() + this.displayObject.addChild(layer.displayObject) if (this.map) layer.geographics.forEach(geographics => geographics.adaptTo(this.map)) } else console.error('Could not place layer. Only MapLayer and GeoLayers can be child layers of GeoLayers.', layer) } + parentChanged() { + this.rescaleChildren() + } + //GeoLayers have to be children of a map layer, // therefore we can recursively get the map. get map() { - return this._mapLayer.map + return this.mapLayer ? this.mapLayer.map : null } get mapLayer() { @@ -120,18 +210,12 @@ export class MapLayer extends GeoLayer { constructor( scatterContainer, displayObject, - { onTransform = null, onChange = null, focus = null, zoom = null, viewport = null } = {} + { onTransform = null, onChange = null, focus = null, zoom = null, viewport = null, mapList = null } = {} ) { super(displayObject) - let onTransformListeners = [ - () => { - this.labelVisibility() - } - ] - if (onTransform) onTransformListeners.push(onTransform) this.transformHandler = new EventHandler('onTransform', { - listeners: onTransformListeners + listeners: onTransform }) this.scatterContainer = scatterContainer @@ -146,6 +230,7 @@ export class MapLayer extends GeoLayer { viewport }) + this.mapList = mapList this._map = null // //TODO Implement error handling here. @@ -154,46 +239,6 @@ export class MapLayer extends GeoLayer { this.dynamicElements = new Map() } - labelVisibility() { - const visibility = this.childrenVisibility - - if (visibility) { - const zoom = this.mapview.zoom - - const min = visibility.min || 0 - const max = visibility.max || Number.MAX_VALUE - - // TODO - // Currently I dont know what elemnts was. - // We just log an error and resolve this on a later point. - if (this.elements) { - if (zoom > min && zoom < max) { - this.elements.forEach(it => (it.visible = true)) - - this.elements.forEach(it => { - const scale = 1 / it.parent.scale.x - - // it.children are poi groups - // it.children[0] is the poi group of the tübingen poi - // it.children[0].children are the text containers (not PIXI.Text), about 20 pieces - - if (it.children.length > 0) { - it.children[0].children.forEach(poi => { - if (poi.children.length === 1) { - poi.scale.set(scale, scale) - } - }) - } - }) - } else { - this.elements.forEach(it => (it.visible = false)) - } - }else{ - console.error("DEBUG: Elements was not defined.") - } - } - } - adapt() { this.layers.forEach(layer => { if (layer.adapt) layer.adapt(this.map) @@ -209,6 +254,7 @@ export class MapLayer extends GeoLayer { transformed(e) { this.mapview.transformed(this.map) + this.layers.forEach(layer => layer.parentMapLayerTransformed(this)) this.transformHandler.call(this) } @@ -243,8 +289,7 @@ export class MapLayer extends GeoLayer { useScatterAsContainer = true // If set to false, the normal container is used. This is necessary when using submaps and the container need to be a RigidContainer.*/ ) { if (map instanceof GeoMap) { - - console.log("Change map to: " , map) + console.log('Change map to: ', map) let oldMap = this.map if (oldMap) oldMap.unload() @@ -252,10 +297,9 @@ export class MapLayer extends GeoLayer { this.map.load() this.scatterContainer.addChild(this.map.image) - console.log(this.map.image.parent) + this.mapview.apply(this.map) map.image.addChild(this.displayObject) - this.mapview.update(this.map) // A geolayer's displayObject is on the parent layer. // A maplayer's displayobject is always the child of the map. diff --git a/lib/pixi/maps/mapapp.html b/lib/pixi/maps/mapapp.html index 309cd39..6cb455f 100644 --- a/lib/pixi/maps/mapapp.html +++ b/lib/pixi/maps/mapapp.html @@ -110,23 +110,26 @@ }) function ready(sprites) { + + const cover = true + // When resources are loaded, the ImageMap can be instantiated. let imageMap = new ImageMap(sprites.get(europe), europeData, { coordsLogging: true, maxScale: 1, - cover: false + cover }) let testMapData = new DeepZoomMapData(new Projection.Mercator(), testConfig.tiles, { app }) - let testMap = new DeepZoomMap(testMapData, Object.assign({}, testConfig.tiles, { app }), { cover: false }) + let testMap = new DeepZoomMap(testMapData, Object.assign({}, testConfig.tiles, { app }), { cover }) app.addMap("test", testMap) let osmMapData = new DeepZoomMapData(new Projection.Mercator(), osmConfig.tiles, { app }) - let deepZoomMap = new DeepZoomMap(osmMapData, Object.assign({}, osmConfig.tiles, { app }), { cover: false }) + let deepZoomMap = new DeepZoomMap(osmMapData, Object.assign({}, osmConfig.tiles, { app }), { cover }) app.addMap("osm", deepZoomMap) // Finally apply the map to the MapApp diff --git a/lib/pixi/maps/mapapp.js b/lib/pixi/maps/mapapp.js index 7bd46d8..03ec525 100644 --- a/lib/pixi/maps/mapapp.js +++ b/lib/pixi/maps/mapapp.js @@ -105,7 +105,7 @@ export default class MapApp extends PIXIApp { super.setup() // TODO get access to fps display - let fpsDisplay + let fpsDisplay = null this.stage.children.forEach(element => { if (element.refreshFps) fpsDisplay = element }) @@ -114,8 +114,7 @@ export default class MapApp extends PIXIApp { this.ui = new PIXI.Container() this.scene.addChild(this.ui) - - if (this.fpsLogging && fpsDisplay) this.ui.addChild(fpsDisplay) + if (this.fpsLogging != null && fpsDisplay != null) this.ui.addChild(fpsDisplay) if (this.coordsLogging) { this.coordsDisplay = new CoordinateDisplay(this) @@ -216,10 +215,11 @@ export default class MapApp extends PIXIApp { lastMap.flushHandlers() } - this.map.onTransform.add(this.transformed.bind(this)) - this.transformed() this.onMapChanged.call(this, this.map) + + this.map.onTransform.add(this.transformed.bind(this)) + if (this.ui && this.ui.parent) { const parent = this.ui.parent @@ -249,11 +249,6 @@ export default class MapApp extends PIXIApp { this.overlayElements.set(layer, obj) } - - addMapOverlay(layer) { - this.mapLayer.place(layer) - } - /** * Copies the current coordinates to the clipboard. */ diff --git a/lib/pixi/maps/mapview.js b/lib/pixi/maps/mapview.js index 69c90fd..3c28d0c 100644 --- a/lib/pixi/maps/mapview.js +++ b/lib/pixi/maps/mapview.js @@ -27,7 +27,7 @@ export default class MapView { return this._zoom } - update(map) { + apply(map) { map.moveTo(this._focus, this._zoom) } @@ -36,7 +36,7 @@ export default class MapView { this.updateFocusPoint(map) } - applyCameraPosition(map) { + updatePosition(map) { this.updateFocusPoint(map) this.updateZoom(map) } @@ -58,24 +58,39 @@ export default class MapView { } mapPointToWindowPoint(map, point) { - let container = map.image.parent + let windowPoint = { x: 0, y: 0 } - let _point = new PIXI.Point( - map.scatter.position.x + map.scatter.scale * point.x, - map.scatter.position.y + map.scatter.scale * point.y - ) + if (map['image'] && map.image['parent']) { + let container = map.image.parent - return container.toGlobal(_point) + windowPoint = new PIXI.Point( + map.scatter.position.x + map.scatter.scale * point.x, + map.scatter.position.y + map.scatter.scale * point.y + ) + + windowPoint = container.toGlobal(windowPoint) + } else { + console.error(this._noParentError) + } + + return windowPoint } windowPointToMapPoint(map, point) { - let offset = map.image.parent.toGlobal({ x: 0, y: 0 }) - let _point = new PIXI.Point( - (point.x - map.scatter.position.x - offset.x) / map.scatter.scale, - (point.y - map.scatter.position.y - offset.y) / map.scatter.scale - ) + let pointOnMap = { x: 0, y: 0 } + if (map['image'] && map.image['parent']) { + let offset = map.image.parent.toGlobal({ x: 0, y: 0 }) + pointOnMap = new PIXI.Point( + (point.x - map.scatter.position.x - offset.x) / map.scatter.scale, + (point.y - map.scatter.position.y - offset.y) / map.scatter.scale + ) + } else console.error(this._noParentError) - return _point + return pointOnMap + } + + get _noParentError() { + return 'Cannot compute map point when map has no parent.' } /** diff --git a/lib/pixi/maps/overlay.js b/lib/pixi/maps/overlay.js index af800a9..37cbec0 100644 --- a/lib/pixi/maps/overlay.js +++ b/lib/pixi/maps/overlay.js @@ -78,6 +78,7 @@ export default class Overlay { scale: 1, rescale: false, popoverOffset: { x: 0, y: 0 }, + zoomVisibility: { min: 0, max: Number.MAX_VALUE }, /** * The following Attributes are taken from the TextStyle class @@ -187,6 +188,10 @@ export default class Overlay { } = {}) { const name = this.name[0].toUpperCase() + this.name.slice(1).toLowerCase() + ' Overlay' let geoLayer = new GeoLayer(new PIXI.Container(), { name }) + + console.log(this) + geoLayer.visibility = this.zoomVisibility + if (this.rescale) geoLayer.rescale = this.rescale this.items.forEach(item => { if (!excludeItems(item)) { @@ -201,7 +206,6 @@ export default class Overlay { }) return geoLayer } - getItemProperty(item, property) { let propertyValue = null const propertyExistsOnItem = item[property] !== undefined @@ -508,7 +512,6 @@ export default class Overlay { maxWidth: 350 }) - if (geographics.map) { const scale = 1 / geographics.map.scatter.scale popup.scale.set(scale, scale) diff --git a/lib/pixi/maps/projections/projections.html b/lib/pixi/maps/projections/projections.html index 2e0d35d..86c7f58 100644 --- a/lib/pixi/maps/projections/projections.html +++ b/lib/pixi/maps/projections/projections.html @@ -243,7 +243,7 @@ let calculatedCoordinates = mercatorProjection.backward(relativePosition) // Testcases for the backwards transformation. - Doctest.expect(coordinates, calculatedCoordinates) + Doctest.expectPointPrecision(coordinates, calculatedCoordinates) let point = createPointAtPoisition(relativePosition) mercatorMap.appendChild(point) @@ -317,7 +317,7 @@ let relativePosition = robinsonProjection.forward(position) // Run Test Cases - Doctest.expect(robinsonTruth[key], relativePosition) + Doctest.expectPointPrecision(robinsonTruth[key], relativePosition,0) let point = createPointAtPoisition(relativePosition) robinsonMap.appendChild(point) diff --git a/lib/pixi/maps/scatter.js b/lib/pixi/maps/scatter.js index 99359cc..97b92e1 100644 --- a/lib/pixi/maps/scatter.js +++ b/lib/pixi/maps/scatter.js @@ -89,7 +89,7 @@ export class AdvancedScatterContainer extends ScatterContainer { let interactionManager = this.renderer.plugins.interaction let displayObject = interactionManager.hitTest(local, this) - console.log(displayObject.dontBlockScatter, displayObject.parent) + if (displayObject.dontBlockScatter && displayObject.parent != null) { displayObject = interactionManager.hitTest(local, displayObject.parent) } @@ -97,7 +97,7 @@ export class AdvancedScatterContainer extends ScatterContainer { if (displayObject != null && displayObject.scatter != null) this.hitScatter = displayObject.scatter if (this.claimEvents) event.claimedByScatter = this.hitScatter - console.log(displayObject) + return this.hitScatter } } @@ -331,26 +331,22 @@ export class CoverScatter extends AdvancedScatter { this.debugGraphics.endFill() } - if (this.cover) { - // The reference to the element handler needs to be stored, - // that we can remove it later on. - const eventHandler = this._applyInitialCover.bind(this, null, true) - this._applyInitialCover(eventHandler) - } + // if (this.cover) { + // // The reference to the element handler needs to be stored, + // // that we can remove it later on. + // this._applyInitialCover = this._applyInitialCover.bind(this) + // } } - _applyInitialCover(eventHandler, removeListener = false) { - if (this.debug) console.log('ApplyInitialCover: ', parent) - if (removeListener) { - this.displayObject.off('added', eventHandler) - } + // _applyInitialCover() { + // if (this.debug) console.log('ApplyInitialCover: ', parent) - if (this.displayObject.parent) - this.forceCover(this.displayObject.parent.width, this.displayObject.parent.height) - else { - this.displayObject.on('added', eventHandler) - } - } + // if (this.displayObject.parent) + // this.forceCover(this.displayObject.parent.width, this.displayObject.parent.height) + // else { + // this.displayObject.on('added', eventHandler) + // } + // } get boundaries() { if (this._boundaries) return this._boundaries @@ -472,7 +468,11 @@ export class CoverScatter extends AdvancedScatter { if (this.scalable && this.parent != null) { if (this.cover) { let minCoverScale = this.calculateMinCoverScale(this.parent.width, this.parent.height) - scale = scale < minCoverScale ? minCoverScale : scale + if (scale < minCoverScale) { + console.error('USE MIN COVER SCALE', minCoverScale, scale) + + scale = minCoverScale + } } this.scale = scale } @@ -528,7 +528,6 @@ export class MapObjectScatter extends CoverScatter { ) super(displayObject, renderer, opts) - if (!renderer) { console.error('Renderer was not set!') return diff --git a/lib/pixi/maps/utils.js b/lib/pixi/maps/utils.js index fe6ae95..6b9fb06 100644 --- a/lib/pixi/maps/utils.js +++ b/lib/pixi/maps/utils.js @@ -331,8 +331,14 @@ export class EventHandler { } call(context, ...args) { - this.listeners.forEach(listener => listener.call(context, ...args)) - this.onces.forEach(listener => listener.call(context, ...args)) + if (context == null) { + this.listeners.forEach(listener => listener(...args)) + this.onces.forEach(listener => listener(...args)) + } else { + this.listeners.forEach(listener => listener.call(context, ...args)) + this.onces.forEach(listener => listener.call(context, ...args)) + } + this.onces = [] }