Ongoing cleanup and refactoring of maps.

This commit is contained in:
Severin Opel 2019-11-25 18:04:11 +01:00
parent 88048f14ec
commit 5305561619
16 changed files with 462 additions and 158 deletions

View File

@ -22,6 +22,19 @@ html.dark-mode {
color: white; color: white;
} }
.dark-mode a{
color: #569CD6;
font-weight: bold;
}
.dark-mode a:hover{
color: white;
}
a{
text-decoration: none;
}
.title { .title {
position: relative; position: relative;
font-size: 2.5rem; font-size: 2.5rem;

172
dist/iwmlib.pixi.js vendored
View File

@ -17203,22 +17203,21 @@
this.debugGraphics.endFill(); this.debugGraphics.endFill();
} }
// if (this.cover) { if (this.cover) {
// // The reference to the element handler needs to be stored, // The reference to the element handler needs to be stored,
// // that we can remove it later on. // that we can remove it later on.
// this._applyInitialCover = this._applyInitialCover.bind(this) this._applyInitialCover = this._applyInitialCover.bind(this);
// } this.displayObject.on('added', this._applyInitialCover);
this._applyInitialCover();
}
} }
// _applyInitialCover() { _applyInitialCover() {
// if (this.debug) console.log('ApplyInitialCover: ', parent) if (this.debug) console.log('ApplyInitialCover: ', parent);
// if (this.displayObject.parent) if (this.displayObject.parent)
// this.forceCover(this.displayObject.parent.width, this.displayObject.parent.height) this.forceCover(this.displayObject.parent.width, this.displayObject.parent.height);
// else { }
// this.displayObject.on('added', eventHandler)
// }
// }
get boundaries() { get boundaries() {
if (this._boundaries) return this._boundaries if (this._boundaries) return this._boundaries
@ -17341,8 +17340,6 @@
if (this.cover) { if (this.cover) {
let minCoverScale = this.calculateMinCoverScale(this.parent.width, this.parent.height); let minCoverScale = this.calculateMinCoverScale(this.parent.width, this.parent.height);
if (scale < minCoverScale) { if (scale < minCoverScale) {
console.error('USE MIN COVER SCALE', minCoverScale, scale);
scale = minCoverScale; scale = minCoverScale;
} }
} }
@ -17458,7 +17455,7 @@
this.projection = projection; this.projection = projection;
if (this.clip) { if (this.opts.clip) {
let _cmin = this.projection.forward(this.opts.clip.min); let _cmin = this.projection.forward(this.opts.clip.min);
let _cmax = this.projection.forward(this.opts.clip.max); let _cmax = this.projection.forward(this.opts.clip.max);
@ -17481,7 +17478,7 @@
} }
toCoordinates(point) { toCoordinates(point) {
if (this.clip) { if (this.opts.clip) {
let min = this.clipExt.point.min; let min = this.clipExt.point.min;
let max = this.clipExt.point.max; let max = this.clipExt.point.max;
@ -17534,24 +17531,28 @@
} }
get clip() { get clip() {
return this.opts.clip let unclipped = {
min: { x: 0, y: 0 },
max: { x: 1, y: 1 }
};
return this.opts.clip ? this.opts.clip : unclipped
} }
/** /**
* Bounds to pixel transforms some bounds in form of {min:{x:minLat, y:minLng},max:{x:maxLat, y:maxLng}} * Bounds to pixel transforms some bounds in form of {min:{x:minLat, y:minLng},max:{x:maxLat, y:maxLng}}
* to pixel coordinates. * to pixel coordinates.
* *
* @param {*} bounds
*/ */
boundsToPixel(bounds) { getBoundaries() {
let min = this.toPixel(bounds.min); // let min = this.toPixel(bounds.min)
let max = this.toPixel(bounds.max); // let max = this.toPixel(bounds.max)
// Y values needs to be swapped, as PIXI has it's origin // Y values needs to be swapped, as PIXI has it's origin
// in the top-left corner and a regular map in the bottom-left corner. // in the top-left corner and a regular map in the bottom-left corner.
let boundaries = { let boundaries = {
min: { x: min.x, y: max.y }, min: { x: 0, y: 0 },
max: { x: max.x, y: min.y } max: { x: 1, y: 1 }
}; };
return boundaries return boundaries
@ -17613,7 +17614,7 @@
* @memberof Projection * @memberof Projection
*/ */
backward(point) { backward(point) {
console.error('You must override the backward fuction in ' + this.name + '.'); console.error('You must override the backward function in ' + this.name + '.');
} }
toString() { toString() {
@ -17625,7 +17626,7 @@
} }
get maxViewport() { get maxViewport() {
return { min: new PIXI.Point(-90, -180), max: new PIXI.Point(90, 180) } return { min: new PIXI.Point(0, 0), max: new PIXI.Point(1, 1) }
} }
} }
@ -17719,10 +17720,12 @@
this.onLoad = new EventHandler('loaded', { listeners: onLoad }); this.onLoad = new EventHandler('loaded', { listeners: onLoad });
this.onTransform = new EventHandler('transform', { listeners: onTransform }); this.onTransform = new EventHandler('transform', { listeners: onTransform });
this.alpha = alpha; this._alpha = alpha;
this.cover = cover; this.cover = cover;
this.debug = debug; this.debug = debug;
//TODO discuss if this is required here. //TODO discuss if this is required here.
// Those are just scatter options and the information // Those are just scatter options and the information
// is redundant in the map class and the scatter. // is redundant in the map class and the scatter.
@ -17800,10 +17803,24 @@
if (this.image.parent) { if (this.image.parent) {
this.image.parent.removeChild(this.image); this.image.parent.removeChild(this.image);
} }
this.image.scatter = null;
if (this.scatter) {
this.scatter.killAnimation();
this.image.scatter = null;
}
} }
} }
remove() {
if (this.image) this.image.mask = null;
this.removeFrame();
this.onTransform.empty();
this.onLoad.empty();
this.unload();
}
/** /**
* Is called when the scatter object is transformed. * Is called when the scatter object is transformed.
* *
@ -17827,12 +17844,7 @@
this.image = image; this.image = image;
if (frame) this.setFrame(frame); if (frame) this.setFrame(frame);
let min = this.mapdata.toPixel(this.viewport.min); let boundaries = this.mapdata.getBoundaries();
let max = this.mapdata.toPixel(this.viewport.max);
let boundaries = {
min: { x: min.x, y: max.y },
max: { x: max.x, y: min.y }
};
let scatterOpts = Object.assign({ let scatterOpts = Object.assign({
cover: this.cover, cover: this.cover,
@ -17851,17 +17863,6 @@
this.image.scatter = scatter == null ? this.scatter : scatter; this.image.scatter = scatter == null ? this.scatter : scatter;
this.onLoad.call(this); this.onLoad.call(this);
// Object.assign(this.image, {
// set scatter (value) {
// console.trace("Scatter set.")
// this._scatter = value
// },
// get scatter (){
// console.trace("Get Scatter.")
// return this._scatter
// }
// })
} }
/** /**
@ -17957,8 +17958,8 @@
console.error('Overload get distance in subclass.'); console.error('Overload get distance in subclass.');
} }
set alpha(value) { get alpha() {
console.error('Overload get alpha in subclass.'); return this._alpha
} }
/** /**
@ -17988,6 +17989,10 @@
return coords return coords
} }
removeFrame() {
this.frame = null;
}
setFrame(frame) { setFrame(frame) {
if (this.debug) console.log('Set Frame: ', frame); if (this.debug) console.log('Set Frame: ', frame);
this.frame = frame; this.frame = frame;
@ -18078,10 +18083,6 @@
return null return null
} }
/**
*
*/
/** /**
* Validates if the map data contains valid data * Validates if the map data contains valid data
* for creating the maps. * for creating the maps.
@ -18414,6 +18415,7 @@
class ImageMap extends GeoMap { class ImageMap extends GeoMap {
constructor(sprite, mapdata, opts = {}) { constructor(sprite, mapdata, opts = {}) {
super(mapdata, opts); super(mapdata, opts);
if (this.debug) console.log('Construct Image Map', sprite, mapdata, opts);
this.sprite = sprite; this.sprite = sprite;
@ -18759,8 +18761,8 @@
_adjustLng(lng, inv = false) { _adjustLng(lng, inv = false) {
let moved = inv ? lng + this.lng0 : lng - this.lng0; let moved = inv ? lng + this.lng0 : lng - this.lng0;
if (moved < -180) moved += 360; // if (moved < -180) moved += 360
if (moved > 180) moved -= 360; // if (moved > 180) moved -= 360
return moved return moved
} }
@ -18781,12 +18783,20 @@
return { low: minIndex, high: maxIndex, ratio, sign } return { low: minIndex, high: maxIndex, ratio, sign }
} }
toString() {
return
}
get name() { get name() {
return 'Robinson Projection' return 'Robinson Projection'
} }
get maxViewport() {
let min = new PIXI.Point(-90, -180);
let max = new PIXI.Point(90, 180);
max.x += this.lng0;
min.x += this.lng0;
console.log({ min, max });
return { min, max }
}
} }
/** /**
@ -19664,6 +19674,7 @@
add(key, map) { add(key, map) {
if (this.maps[key] != null) consol.warn('Key already in mapList. The existing key was overwritten.'); if (this.maps[key] != null) consol.warn('Key already in mapList. The existing key was overwritten.');
if (this.active == null) this.active = key;
map.name = key; map.name = key;
this.maps[key] = map; this.maps[key] = map;
} }
@ -19680,6 +19691,13 @@
console.log(keys, idx, next); console.log(keys, idx, next);
return next return next
} }
cleanup() {
for (let key in this.maps) {
let map = this.maps[key];
map.remove();
}
}
} }
//import { GeoGraphics } from "../pixi/geographics.js" //import { GeoGraphics } from "../pixi/geographics.js"
@ -19903,9 +19921,11 @@
mapList, mapList,
scatterContainer, scatterContainer,
displayObject, displayObject,
{ onTransform = null, onChange = null, focus = null, zoom = null, viewport = null } = {} { onTransform = null, onChange = null, focus = null, zoom = null, viewport = null, name = null } = {}
) { ) {
super(displayObject); super(displayObject, {
name
});
this.transformHandler = new EventHandler('onTransform', { this.transformHandler = new EventHandler('onTransform', {
listeners: onTransform listeners: onTransform
@ -19971,6 +19991,17 @@
return mapLayerClone return mapLayerClone
} }
/**
* Helper function to quickly display the next map.
* Order is defined by the key ordering of the maplist.
*
* @memberof MapLayer
*/
next() {
let nextMap = this.mapList.next();
this.changeMap(nextMap);
}
/** /**
* Changes the map to the specified one, keeping the position and the zoom of the old map. * Changes the map to the specified one, keeping the position and the zoom of the old map.
* *
@ -20082,6 +20113,10 @@
get mapLayer() { get mapLayer() {
return this return this
} }
cleanup() {
this.mapList.cleanup();
}
} }
MapLayer.idx = 0; MapLayer.idx = 0;
@ -20167,11 +20202,22 @@
this._setupKeyboardUtils(); this._setupKeyboardUtils();
} }
logMapBoundaries() {
let map = this.mapLayer.map;
let boundaries = {
min: this.mapLayer.mapview.coordinatesFromWindowPoint(map, { x: 0, y: 0 }),
max: this.mapLayer.mapview.coordinatesFromWindowPoint(map, { x: 0, y: 0 })
};
console.log(JSON.stringify(boundaries));
}
_setupMapLayer() { _setupMapLayer() {
this.mapContainer = new PIXI.Container(); this.mapContainer = new PIXI.Container();
console.log(this.mapList); console.log(this.mapList);
this.mapLayer = new MapLayer(this.mapList, this.scene, this.mapContainer, { this.mapLayer = new MapLayer(this.mapList, this.scene, this.mapContainer, {
name: 'Map Layer', name: 'Root Map Layer',
focus: this.focus, focus: this.focus,
zoom: this.zoom zoom: this.zoom
}); });
@ -21123,12 +21169,11 @@
return false return false
}, },
informationCallback = null, informationCallback = null,
adjustItems = null adjustItems = null,
cleanupItems = null
} = {}) { } = {}) {
const name = this.name[0].toUpperCase() + this.name.slice(1).toLowerCase() + ' Overlay'; const name = this.name[0].toUpperCase() + this.name.slice(1).toLowerCase() + ' Overlay';
let geoLayer = new GeoLayer(new PIXI.Container(), { name }); let geoLayer = new GeoLayer(new PIXI.Container(), { name });
console.log(this);
geoLayer.visibility = this.zoomVisibility; geoLayer.visibility = this.zoomVisibility;
if (this.rescale) geoLayer.rescale = this.rescale; if (this.rescale) geoLayer.rescale = this.rescale;
@ -21141,6 +21186,9 @@
item.overlay = this; item.overlay = this;
let graphics = this.createItem(item, informationCallback); let graphics = this.createItem(item, informationCallback);
geoLayer.addChild(graphics); geoLayer.addChild(graphics);
if (cleanupItems) {
cleanupItems(item);
}
} }
}); });
return geoLayer return geoLayer

View File

@ -999,7 +999,6 @@ export class InteractionMapper extends InteractionDelegate {
if (found != null) { if (found != null) {
this.interaction.addTarget(key, found) this.interaction.addTarget(key, found)
} }
console.log(this.target)
} }
let size = this.interaction.current.size let size = this.interaction.current.size
let limit = this.logInteractionsAbove let limit = this.logInteractionsAbove

View File

@ -46,7 +46,7 @@
] ]
function createApp(view) { function createApp(view) {
let app = new MapApp({ let app = window.GeoPointApp = new MapApp({
view, view,
focus: { x: 0, y: 0 }, focus: { x: 0, y: 0 },
zoom: 1, zoom: 1,
@ -70,11 +70,11 @@
wikimedia wikimedia
], (sprites) => { ], (sprites) => {
let osmMap = new ImageMap(sprites.get(osmworld), new MapData(new Projection.Mercator()), { cover: true }) let osmMap = new ImageMap(sprites.get(osmworld), new MapData(new Projection.Mercator()), { cover: true, debug: true })
let wikimediaMap = new ImageMap(sprites.get(wikimedia), new MapData(new Projection.Robinson(10)), { let wikimediaMap = new ImageMap(sprites.get(wikimedia), new MapData(new Projection.Robinson(10)), {
baseZoomHeight: sprites.get(osmworld).texture.height, baseZoomHeight: sprites.get(osmworld).texture.height,
cover: true cover: true, debug: true
}) })
app.addMaps({ app.addMaps({

View File

@ -86,7 +86,6 @@ export class GeoLayer {
set visibility(value) { set visibility(value) {
let { min = 0, max = Infinity } = value let { min = 0, max = Infinity } = value
console.log(min)
this._visibility = { min, max } this._visibility = { min, max }
} }
@ -224,9 +223,11 @@ export class MapLayer extends GeoLayer {
mapList, mapList,
scatterContainer, scatterContainer,
displayObject, displayObject,
{ onTransform = null, onChange = null, focus = null, zoom = null, viewport = null } = {} { onTransform = null, onChange = null, focus = null, zoom = null, viewport = null, name = null } = {}
) { ) {
super(displayObject) super(displayObject, {
name
})
this.transformHandler = new EventHandler('onTransform', { this.transformHandler = new EventHandler('onTransform', {
listeners: onTransform listeners: onTransform
@ -292,6 +293,17 @@ export class MapLayer extends GeoLayer {
return mapLayerClone return mapLayerClone
} }
/**
* Helper function to quickly display the next map.
* Order is defined by the key ordering of the maplist.
*
* @memberof MapLayer
*/
next() {
let nextMap = this.mapList.next()
this.changeMap(nextMap)
}
/** /**
* Changes the map to the specified one, keeping the position and the zoom of the old map. * Changes the map to the specified one, keeping the position and the zoom of the old map.
* *
@ -304,7 +316,7 @@ export class MapLayer extends GeoLayer {
/* map , /* map ,
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.*/ 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.*/
) { ) {
console.log('Change map to: ', name) console.log('🗺️ Change map to: ', name)
let oldMap = this.map let oldMap = this.map
this.mapList.select(name) this.mapList.select(name)
@ -316,10 +328,8 @@ export class MapLayer extends GeoLayer {
let map = this.map let map = this.map
if (map) { if (map) {
console.log('Load Map')
map.load() map.load()
console.log(this, this.scatterContainer)
this.scatterContainer.addChild(map.image) this.scatterContainer.addChild(map.image)
this.mapview.apply(map) this.mapview.apply(map)
@ -403,6 +413,10 @@ export class MapLayer extends GeoLayer {
get mapLayer() { get mapLayer() {
return this return this
} }
cleanup() {
this.mapList.cleanup()
}
} }
MapLayer.idx = 0 MapLayer.idx = 0

145
lib/pixi/maps/map.html Normal file
View File

@ -0,0 +1,145 @@
<!DOCTYPE html>
<html lang="en" class="dark-mode">
<head>
<meta charset="UTF-8" />
<title>Map</title>
<script src="../../3rdparty/highlight/highlight.pack.js"></script>
<link rel="stylesheet" href="../../../fonts/material-icon-font/material-icons.css">
<link rel='stylesheet' href='../../3rdparty/highlight/styles/vs2015.css'>
<link rel='stylesheet' href='../../../css/doctest.css'>
<script src="../../../dist/iwmlib.3rdparty.js"></script>
<script src="../../../dist/iwmlib.js"></script>
<script src="../../../dist/iwmlib.pixi.js"></script>
<style>
.controls {
display: flex;
}
</style>
</head>
<body onload="Doctest.run()">
<h1>Map</h1>
<p>
The Map class shows a geographical map using a scatter element.
</p>
<h2 id="DeepZoomMap">DeepZoomMap</h2>
<p>Usually a DeepZoomMap will be used to display maps. It uses a <a
href="../deepzoom/deepzoom.html">DeepZoomImage</a> to display the map in different resolutions depending on
the zoom factor.</p>
<canvas id="deepZoomCanvas">
</canvas>
<script>
</script>
<script class="doctest" data-collapsible data-collapsed data-title="Script">
(function () {
// Create the mapapp.
let app = window.DeepZoomMapApp = new MapApp({
view: deepZoomCanvas,
coordsLogging: true,
width: 512,
height: 512
})
// Load or specify a tilesConfig as required by the DeepZoomImage.
const tilesConfig = {
"tileSize": 256,
"format": "png",
"overlap": 0,
"type": "map",
"height": 1024,
"width": 1024,
"path": "../assets/maps/osm",
"urlTileTemplate": "{path}/{level}/{row}/{column}.{format}"
}
// Create a projection.
const projection = new Projection.Mercator()
// Create a map data object.
const osmDeepZoomMapData = new DeepZoomMapData(projection, tilesConfig, { app })
// Create the map
const osmMap = new DeepZoomMap(osmDeepZoomMapData, tilesConfig)
// Add the map to the app.
app.addMap("osm", osmMap)
// Run the app when at least one map is set.
app.setup().run()
})()
</script>
<h2 id="imageMap">ImageMap</h2>
<p>Single images can be also used as maps. This can be useful for examples, debugging purposes or other use-cases
when there are no different tiles required or available.</p>
<canvas id="imageMapCanvas">
</canvas>
<script>
</script>
<script class="doctest" data-collapsible data-collapsed data-title="Script">
(function () {
// Create the mapapp.
let app = window.ImageMapApp = new MapApp({
view: imageMapCanvas,
coordsLogging: true,
width: 512,
height: 512
})
const mapTexture = "../assets/maps/wikimedia-world-robinson/2000px-BlankMap-World.png"
// The images used by the image map need to be loaded beforehand.
// Therefore this loading step is required.
app.loadSprites([mapTexture], sprites => spritesLoaded(sprites), {
resolutionDependent: false
})
spritesLoaded = (sprites) => {
// Create a projection.
const projection = new Projection.Robinson(10)
// Create a map data object.
let mapData = new MapData(projection)
// Create the map
let imageMap = new ImageMap(sprites.get(mapTexture), mapData)
// Add the map to the app.
app.addMap("europe", imageMap)
// Run the app when at least one map is set.
app.setup().run()
}
})()
</script>
</body>
</html>

View File

@ -53,7 +53,7 @@ export class GeoMap {
this.onLoad = new EventHandler('loaded', { listeners: onLoad }) this.onLoad = new EventHandler('loaded', { listeners: onLoad })
this.onTransform = new EventHandler('transform', { listeners: onTransform }) this.onTransform = new EventHandler('transform', { listeners: onTransform })
this.alpha = alpha this._alpha = alpha
this.cover = cover this.cover = cover
this.debug = debug this.debug = debug
@ -134,10 +134,24 @@ export class GeoMap {
if (this.image.parent) { if (this.image.parent) {
this.image.parent.removeChild(this.image) this.image.parent.removeChild(this.image)
} }
this.image.scatter = null
if (this.scatter) {
this.scatter.killAnimation()
this.image.scatter = null
}
} }
} }
remove() {
if (this.image) this.image.mask = null
this.removeFrame()
this.onTransform.empty()
this.onLoad.empty()
this.unload()
}
/** /**
* Is called when the scatter object is transformed. * Is called when the scatter object is transformed.
* *
@ -161,12 +175,7 @@ export class GeoMap {
this.image = image this.image = image
if (frame) this.setFrame(frame) if (frame) this.setFrame(frame)
let min = this.mapdata.toPixel(this.viewport.min) let boundaries = this.mapdata.getBoundaries()
let max = this.mapdata.toPixel(this.viewport.max)
let boundaries = {
min: { x: min.x, y: max.y },
max: { x: max.x, y: min.y }
}
let scatterOpts = Object.assign({ let scatterOpts = Object.assign({
cover: this.cover, cover: this.cover,
@ -185,17 +194,6 @@ export class GeoMap {
this.image.scatter = scatter == null ? this.scatter : scatter this.image.scatter = scatter == null ? this.scatter : scatter
this.onLoad.call(this) this.onLoad.call(this)
// Object.assign(this.image, {
// set scatter (value) {
// console.trace("Scatter set.")
// this._scatter = value
// },
// get scatter (){
// console.trace("Get Scatter.")
// return this._scatter
// }
// })
} }
/** /**
@ -291,8 +289,8 @@ export class GeoMap {
console.error('Overload get distance in subclass.') console.error('Overload get distance in subclass.')
} }
set alpha(value) { get alpha() {
console.error('Overload get alpha in subclass.') return this._alpha
} }
/** /**
@ -322,6 +320,10 @@ export class GeoMap {
return coords return coords
} }
removeFrame() {
this.frame = null
}
setFrame(frame) { setFrame(frame) {
if (this.debug) console.log('Set Frame: ', frame) if (this.debug) console.log('Set Frame: ', frame)
this.frame = frame this.frame = frame
@ -383,7 +385,6 @@ export class GeoMap {
let maps = {} let maps = {}
if (GeoMap._validateJson(json, error)) { if (GeoMap._validateJson(json, error)) {
for (let [mapname, data] of Object.entries(json)) { for (let [mapname, data] of Object.entries(json)) {
console.log(data.tiles, data.tiles.path, root + data.tiles.path)
data.tiles.path = root + data.tiles.path data.tiles.path = root + data.tiles.path
maps[mapname] = GeoMap._createMap(data) maps[mapname] = GeoMap._createMap(data)
maps[mapname].name = mapname maps[mapname].name = mapname
@ -412,10 +413,6 @@ export class GeoMap {
return null return null
} }
/**
*
*/
/** /**
* Validates if the map data contains valid data * Validates if the map data contains valid data
* for creating the maps. * for creating the maps.
@ -525,7 +522,6 @@ export class DeepZoomMap extends GeoMap {
* @param {object} opts - Additional options to specify the behaviour of the deep zoom image. * @param {object} opts - Additional options to specify the behaviour of the deep zoom image.
*/ */
constructor(mapdata, tilesConfig, opts = {}) { constructor(mapdata, tilesConfig, opts = {}) {
if (!tilesConfig.app) console.error('App was not set in the tilesConfig.')
opts = Object.assign( opts = Object.assign(
{ {
maxScale: Math.min(tilesConfig.width, tilesConfig.height) / tilesConfig.tileSize, maxScale: Math.min(tilesConfig.width, tilesConfig.height) / tilesConfig.tileSize,
@ -545,9 +541,7 @@ export class DeepZoomMap extends GeoMap {
if (!(this.mapdata instanceof MapData)) { if (!(this.mapdata instanceof MapData)) {
console.error('Use the MapData object for creating maps!') console.error('Use the MapData object for creating maps!')
} else { } else {
if (this.mapdata instanceof DeepZoomMapData) { if (!(this.mapdata instanceof DeepZoomMapData)) {
if (!this.mapdata.app) console.error('No app was set on the mapdata!')
} else {
console.error('Use the DeepZoomMapData object.') console.error('Use the DeepZoomMapData object.')
} }
} }
@ -559,6 +553,7 @@ export class DeepZoomMap extends GeoMap {
* @private * @private
*/ */
load(container = null, scatter = null) { load(container = null, scatter = null) {
if (!this.mapdata.app) console.error('App was not set in the mapdata.')
this.info = new DeepZoomInfo(this.tilesConfig) this.info = new DeepZoomInfo(this.tilesConfig)
let image = new DeepZoomImage(this.info, { let image = new DeepZoomImage(this.info, {
app: this.mapdata.app, app: this.mapdata.app,
@ -569,7 +564,6 @@ export class DeepZoomMap extends GeoMap {
super.load(image, container, scatter) super.load(image, container, scatter)
console.log('LOADED: ', this.image)
if (this.debug) console.log('Loaded image: ', image, 'With options: ', this.info) if (this.debug) console.log('Loaded image: ', image, 'With options: ', this.info)
} }
@ -748,6 +742,7 @@ DeepZoomMap.tintcolor = 0
export class ImageMap extends GeoMap { export class ImageMap extends GeoMap {
constructor(sprite, mapdata, opts = {}) { constructor(sprite, mapdata, opts = {}) {
super(mapdata, opts) super(mapdata, opts)
if (this.debug) console.log('Construct Image Map', sprite, mapdata, opts)
this.sprite = sprite this.sprite = sprite

View File

@ -88,18 +88,32 @@ export default class MapApp extends PIXIApp {
this._setupKeyboardUtils() this._setupKeyboardUtils()
} }
/**
* Log boundaries for a shown map.
* This is for development purposes only, if you want
* to find the boundaries of a shown map.
*
* @memberof MapApp
*/
logMapBoundaries() {
let map = this.mapLayer.map
let boundaries = {
min: this.mapLayer.mapview.coordinatesFromWindowPoint(map, { x: 0, y: 0 }),
max: this.mapLayer.mapview.coordinatesFromWindowPoint(map, { x: 0, y: 0 })
}
console.log(JSON.stringify(boundaries))
}
_setupMapLayer() { _setupMapLayer() {
this.mapContainer = new PIXI.Container() this.mapContainer = new PIXI.Container()
console.log(this.mapList)
this.mapLayer = new MapLayer(this.mapList, this.scene, this.mapContainer, { this.mapLayer = new MapLayer(this.mapList, this.scene, this.mapContainer, {
name: 'Map Layer', name: 'Root Map Layer',
focus: this.focus, focus: this.focus,
zoom: this.zoom zoom: this.zoom,
onChange: this._mapChanged.bind(this)
}) })
this.mapLayer.changeHandler.add(this._mapChanged.bind(this))
if (this.mapList.map) this.mapLayer.changeMap(this.mapList.map)
} }
setup() { setup() {

View File

@ -145,7 +145,7 @@
<script> <script>
printCoordinates(map_image_1, germany, map_coords_1) printCoordinates(map_image_1, germany, map_coords_1)
</script> </script>
<h2>Clipped And Translated Map</h2> <h2>Translated Map</h2>
<p>Maps can be also translated, if the whole world is shown and clipping is not an option.</p> <p>Maps can be also translated, if the whole world is shown and clipping is not an option.</p>
<p>Coordinates: <p>Coordinates:
<strong id="map_coords_2"></strong> <strong id="map_coords_2"></strong>
@ -160,7 +160,7 @@
// Fake offset by using the old mapdata. // Fake offset by using the old mapdata.
let translation = squared_world.toPixel({ x: 0, y: -140 }) let translation = squared_world.toPixel({ x: 90-10, y: -140 })
console.log(translation) console.log(translation)
@ -168,7 +168,7 @@
// And also translated in hoizontal direction. // And also translated in hoizontal direction.
// The translate option corrects that. // The translate option corrects that.
let translated_world = new MapData(new Projection.Mercator(), { let translated_world = new MapData(new Projection.Mercator(), {
translate: { x: 0, y: 40 }, translate: { x: -10, y: 40 },
}) })
@ -180,7 +180,7 @@
height: size + "px", height: size + "px",
backgroundImage: "url(../assets/maps/osm/0/0/0.png)", backgroundImage: "url(../assets/maps/osm/0/0/0.png)",
backgroundColor: "red", backgroundColor: "red",
backgroundPosition: translation.x * size + "px 0" backgroundPosition: translation.x * size + "px " +translation.y * size + "px"
}) })
//Same as above //Same as above
@ -191,7 +191,9 @@
</script> </script>
<script> <script>
map_image_2.addEventListener("mousemove", (event) => { map_image_2.addEventListener("mousemove", (event) => {
let coords = translated_world.toCoordinates({ x: event.offsetX / event.target.width, y: event.offsetY / event.target.height }) let map = map_image_2
console.log(event.offsetX / map.width)
let coords = translated_world.toCoordinates({ x: event.offsetX / map.offsetWidth, y: event.offsetY / map.offsetHeight })
map_coords_2.innerHTML = "Lat: " + coords.x.toFixed(4) + " Lng: " + coords.y.toFixed(4) map_coords_2.innerHTML = "Lat: " + coords.x.toFixed(4) + " Lng: " + coords.y.toFixed(4)
}) })
</script> </script>

View File

@ -27,7 +27,7 @@ export class MapData {
this.projection = projection this.projection = projection
if (this.clip) { if (this.opts.clip) {
let _cmin = this.projection.forward(this.opts.clip.min) let _cmin = this.projection.forward(this.opts.clip.min)
let _cmax = this.projection.forward(this.opts.clip.max) let _cmax = this.projection.forward(this.opts.clip.max)
@ -49,8 +49,15 @@ export class MapData {
} }
} }
/**
* Transforms a pixel point on the map to a geographical coordinate.
*
* @param {{x,y} | PIXI.Point} point - A pixel position on the map.
* @returns {{x,y} | PIXI.Point} - A geographical coordinate.
* @memberof MapData
*/
toCoordinates(point) { toCoordinates(point) {
if (this.clip) { if (this.opts.clip) {
let min = this.clipExt.point.min let min = this.clipExt.point.min
let max = this.clipExt.point.max let max = this.clipExt.point.max
@ -74,6 +81,13 @@ export class MapData {
return coordinates return coordinates
} }
/**
* Transform a geographical coordinate to a pixel point on the map.
*
* @param {{x,y} | PIXI.Point} coordinates - A point in the form of {x:lat,y:lng}.
* @returns {{x,y} | PIXI.Point} point - A pixel position on the map.
* @memberof MapData
*/
toPixel(coordinates) { toPixel(coordinates) {
let coords = { x: coordinates.x, y: coordinates.y } let coords = { x: coordinates.x, y: coordinates.y }
if (this.opts.translate) { if (this.opts.translate) {
@ -103,24 +117,28 @@ export class MapData {
} }
get clip() { get clip() {
return this.opts.clip let unclipped = {
min: { x: 0, y: 0 },
max: { x: 1, y: 1 }
}
return this.opts.clip ? this.opts.clip : unclipped
} }
/** /**
* Bounds to pixel transforms some bounds in form of {min:{x:minLat, y:minLng},max:{x:maxLat, y:maxLng}} * Bounds to pixel transforms some bounds in form of {min:{x:minLat, y:minLng},max:{x:maxLat, y:maxLng}}
* to pixel coordinates. * to pixel coordinates.
* *
* @param {*} bounds
*/ */
boundsToPixel(bounds) { getBoundaries() {
let min = this.toPixel(bounds.min) // let min = this.toPixel(bounds.min)
let max = this.toPixel(bounds.max) // let max = this.toPixel(bounds.max)
// Y values needs to be swapped, as PIXI has it's origin // Y values needs to be swapped, as PIXI has it's origin
// in the top-left corner and a regular map in the bottom-left corner. // in the top-left corner and a regular map in the bottom-left corner.
let boundaries = { let boundaries = {
min: { x: min.x, y: max.y }, min: { x: 0, y: 0 },
max: { x: max.x, y: min.y } max: { x: 1, y: 1 }
} }
return boundaries return boundaries
@ -133,7 +151,6 @@ export class MapData {
export class DeepZoomMapData extends MapData { export class DeepZoomMapData extends MapData {
constructor(projection, tilesConfig, opts = {}) { constructor(projection, tilesConfig, opts = {}) {
if (!opts.app) console.error('Deepzoom Mapdata needs an app set in the options.')
if (tilesConfig.clip) { if (tilesConfig.clip) {
opts.clip = { opts.clip = {
min: { min: {
@ -147,8 +164,6 @@ export class DeepZoomMapData extends MapData {
} }
} }
console.log(tilesConfig, opts)
super(projection, opts) super(projection, opts)
this.app = opts.app this.app = opts.app
} }

View File

@ -52,6 +52,7 @@ export class MapList {
add(key, map) { add(key, map) {
if (this.maps[key] != null) consol.warn('Key already in mapList. The existing key was overwritten.') if (this.maps[key] != null) consol.warn('Key already in mapList. The existing key was overwritten.')
if (this.active == null) this.active = key
map.name = key map.name = key
this.maps[key] = map this.maps[key] = map
} }
@ -65,7 +66,13 @@ export class MapList {
let idx = keys.indexOf(this.active) let idx = keys.indexOf(this.active)
let next = idx + 1 < keys.length ? keys[idx + 1] : keys[0] let next = idx + 1 < keys.length ? keys[idx + 1] : keys[0]
console.log(keys, idx, next)
return next return next
} }
cleanup() {
for (let key in this.maps) {
let map = this.maps[key]
map.remove()
}
}
} }

View File

@ -184,12 +184,11 @@ export default class Overlay {
return false return false
}, },
informationCallback = null, informationCallback = null,
adjustItems = null adjustItems = null,
cleanupItems = null
} = {}) { } = {}) {
const name = this.name[0].toUpperCase() + this.name.slice(1).toLowerCase() + ' Overlay' const name = this.name[0].toUpperCase() + this.name.slice(1).toLowerCase() + ' Overlay'
let geoLayer = new GeoLayer(new PIXI.Container(), { name }) let geoLayer = new GeoLayer(new PIXI.Container(), { name })
console.log(this)
geoLayer.visibility = this.zoomVisibility geoLayer.visibility = this.zoomVisibility
if (this.rescale) geoLayer.rescale = this.rescale if (this.rescale) geoLayer.rescale = this.rescale
@ -202,6 +201,9 @@ export default class Overlay {
item.overlay = this item.overlay = this
let graphics = this.createItem(item, informationCallback) let graphics = this.createItem(item, informationCallback)
geoLayer.addChild(graphics) geoLayer.addChild(graphics)
if (cleanupItems) {
cleanupItems(item)
}
} }
}) })
return geoLayer return geoLayer

View File

@ -26,7 +26,7 @@ export default class Projection {
* @memberof Projection * @memberof Projection
*/ */
backward(point) { backward(point) {
console.error('You must override the backward fuction in ' + this.name + '.') console.error('You must override the backward function in ' + this.name + '.')
} }
toString() { toString() {
@ -38,6 +38,6 @@ export default class Projection {
} }
get maxViewport() { get maxViewport() {
return { min: new PIXI.Point(-90, -180), max: new PIXI.Point(90, 180) } return { min: new PIXI.Point(0, 0), max: new PIXI.Point(1, 1) }
} }
} }

View File

@ -92,6 +92,10 @@
</div> </div>
<script> <script>
window.examples = []
let boundaries = [ let boundaries = [
{ x: -90, y: -180 }, { x: -90, y: -180 },
{ x: 90, y: 180 }, { x: 90, y: 180 },
@ -247,6 +251,8 @@
let point = createPointAtPoisition(relativePosition) let point = createPointAtPoisition(relativePosition)
mercatorMap.appendChild(point) mercatorMap.appendChild(point)
window.examples.push({ map: mercatorMap, projection: mercatorProjection })
} }
})() })()
@ -317,14 +323,53 @@
let relativePosition = robinsonProjection.forward(position) let relativePosition = robinsonProjection.forward(position)
// Run Test Cases // Run Test Cases
Doctest.expectPointPrecision(robinsonTruth[key], relativePosition,0) Doctest.expectPointPrecision(robinsonTruth[key], relativePosition, 0)
let point = createPointAtPoisition(relativePosition) let point = createPointAtPoisition(relativePosition)
robinsonMap.appendChild(point) robinsonMap.appendChild(point)
} }
window.examples.push({ projection: robinsonProjection, map: robinsonMap })
})() })()
</script> </script>
</section> </section>
<script>
// Put it in a self executing anonymous function to not pollute the window element.
(function () {
window.examples.forEach(({ map, projection }) => {
let display = document.createElement("p")
Object.assign(display.style, {
position: "absolute",
left: 0,
top: 0
})
map.parentNode.appendChild(display)
Object.assign(map.parentNode.style, {
position: "relative"
})
display.innerText = "Hover over Map to display coordinates."
map.addEventListener("mousemove", (event) => {
let mousePosition = { x: event.offsetX, y: event.offsetY }
let normalizedPosition = {
x: mousePosition.x / map.offsetWidth,
y: mousePosition.y / map.offsetHeight
}
let coordinates = projection.backward(normalizedPosition)
display.innerHTML = `<b>lat:</b> ${coordinates.x.toFixed(3)} <br><b>lng:</b> ${coordinates.y.toFixed(3)}`
})
})
})()
</script>
</body> </body>
</html> </html>

View File

@ -117,8 +117,8 @@ export default class Robinson extends Projection {
_adjustLng(lng, inv = false) { _adjustLng(lng, inv = false) {
let moved = inv ? lng + this.lng0 : lng - this.lng0 let moved = inv ? lng + this.lng0 : lng - this.lng0
if (moved < -180) moved += 360 // if (moved < -180) moved += 360
if (moved > 180) moved -= 360 // if (moved > 180) moved -= 360
return moved return moved
} }
@ -139,10 +139,18 @@ export default class Robinson extends Projection {
return { low: minIndex, high: maxIndex, ratio, sign } return { low: minIndex, high: maxIndex, ratio, sign }
} }
toString() {
return
}
get name() { get name() {
return 'Robinson Projection' return 'Robinson Projection'
} }
get maxViewport() {
let min = new PIXI.Point(-90, -180)
let max = new PIXI.Point(90, 180)
max.x += this.lng0
min.x += this.lng0
console.log({ min, max })
return { min, max }
}
} }

View File

@ -349,22 +349,21 @@ export class CoverScatter extends AdvancedScatter {
this.debugGraphics.endFill() this.debugGraphics.endFill()
} }
// if (this.cover) { if (this.cover) {
// // The reference to the element handler needs to be stored, // The reference to the element handler needs to be stored,
// // that we can remove it later on. // that we can remove it later on.
// this._applyInitialCover = this._applyInitialCover.bind(this) this._applyInitialCover = this._applyInitialCover.bind(this)
// } this.displayObject.on('added', this._applyInitialCover)
this._applyInitialCover()
}
} }
// _applyInitialCover() { _applyInitialCover() {
// if (this.debug) console.log('ApplyInitialCover: ', parent) if (this.debug) console.log('ApplyInitialCover: ', parent)
// if (this.displayObject.parent) if (this.displayObject.parent)
// this.forceCover(this.displayObject.parent.width, this.displayObject.parent.height) this.forceCover(this.displayObject.parent.width, this.displayObject.parent.height)
// else { }
// this.displayObject.on('added', eventHandler)
// }
// }
get boundaries() { get boundaries() {
if (this._boundaries) return this._boundaries if (this._boundaries) return this._boundaries
@ -487,8 +486,6 @@ export class CoverScatter extends AdvancedScatter {
if (this.cover) { if (this.cover) {
let minCoverScale = this.calculateMinCoverScale(this.parent.width, this.parent.height) let minCoverScale = this.calculateMinCoverScale(this.parent.width, this.parent.height)
if (scale < minCoverScale) { if (scale < minCoverScale) {
console.error('USE MIN COVER SCALE', minCoverScale, scale)
scale = minCoverScale scale = minCoverScale
} }
} }
@ -546,10 +543,10 @@ export class MapObjectScatter extends CoverScatter {
) )
super(displayObject, renderer, opts) super(displayObject, renderer, opts)
if (!renderer) { // if (!renderer) {
console.error('Renderer was not set!') // console.error('Renderer was not set!')
return // return
} // }
this.cover = opts.cover this.cover = opts.cover
} }