UNPKG

@senx/discovery-widgets

Version:

Discovery Widgets Elements

973 lines (972 loc) 59.2 kB
/* * Copyright 2022-2025 SenX S.A.S. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { h } from "@stencil/core"; import { DataModel } from "../../model/types"; import { Param } from "../../model/param"; import { Logger } from "../../utils/logger"; import { GTSLib } from "../../utils/gts.lib"; import { Utils } from "../../utils/utils"; import Leaflet from "leaflet"; import { MapLib } from "../../utils/map-lib"; import { ColorLib } from "../../utils/color-lib"; import { AntPath, antPath } from "leaflet-ant-path"; import domtoimage from "dom-to-image"; import "leaflet-edgebuffer"; import "leaflet.heat"; import "leaflet.markercluster"; import { v4 } from "uuid"; export class DiscoveryMapComponent { constructor() { this.options = new Param(); this.debug = false; this.parsing = false; this.toDisplay = []; this.defOptions = Object.assign(Object.assign({}, new Param()), { map: { tiles: [], animate: false, } }); this.divider = 1000; this.pathData = []; this.positionData = []; this.geoJson = []; this.pathDataLayer = Leaflet.featureGroup(); this.positionDataLayer = Leaflet.featureGroup(); this.tileLayerGroup = Leaflet.featureGroup(); this.geoJsonLayer = Leaflet.featureGroup(); this.poiLayer = new Leaflet.LayerGroup(); this.heatmapLayer = Leaflet.featureGroup(); this.shadowHeatmapLayer = Leaflet.featureGroup(); this.firstDraw = true; this.initial = true; this.hidden = {}; this.markerOver = false; this.tileLayers = []; this.pois = []; } updateRes(newValue, oldValue) { if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) { this.result = GTSLib.getData(this.result); this.initial = true; setTimeout(() => { var _a; return this.drawMap((_a = this.result) !== null && _a !== void 0 ? _a : new DataModel(), true, true); }); } } optionsUpdate(newValue, oldValue) { var _a, _b; (_a = this.LOG) === null || _a === void 0 ? void 0 : _a.debug(['optionsUpdate'], newValue, oldValue); let opts = newValue; if (!!newValue && typeof newValue === 'string') { opts = JSON.parse(newValue); } if (!Utils.deepEqual(opts, this.innerOptions)) { this.innerOptions = Utils.clone(opts); setTimeout(() => { var _a; return this.drawMap((_a = this.result) !== null && _a !== void 0 ? _a : new DataModel(), true, true); }); (_b = this.LOG) === null || _b === void 0 ? void 0 : _b.debug(['optionsUpdate 2'], { options: this.innerOptions, newValue, oldValue }); } } async resize() { const dims = Utils.getContentBounds(this.el.parentElement); this.width = dims.w; this.height = dims.h; if (this.map) { this.map.invalidateSize(); } return Promise.resolve(); } async export(_type = 'png') { return await domtoimage.toPng(this.mapElement, { height: this.height, width: this.width }); } async show(regexp) { var _a, _b; GTSLib.flatDeep(((_a = this.result) !== null && _a !== void 0 ? _a : new DataModel()).data).forEach(gts => { var _a, _b, _c, _d; const gtsName = (_d = (_c = ((_b = ((_a = this.result) !== null && _a !== void 0 ? _a : new DataModel()).params) !== null && _b !== void 0 ? _b : [])[gts.id]) === null || _c === void 0 ? void 0 : _c.key) !== null && _d !== void 0 ? _d : GTSLib.serializeGtsMetadata(gts); if (new RegExp(regexp).test(gtsName)) { this.hidden[gts.id] = false; } }); this.drawMap((_b = this.result) !== null && _b !== void 0 ? _b : new DataModel(), true); return Promise.resolve(); } async hide(regexp) { var _a, _b; GTSLib.flatDeep(((_a = this.result) !== null && _a !== void 0 ? _a : new DataModel()).data).forEach(gts => { var _a, _b, _c, _d; const gtsName = (_d = (_c = ((_b = ((_a = this.result) !== null && _a !== void 0 ? _a : new DataModel()).params) !== null && _b !== void 0 ? _b : [])[gts.id]) === null || _c === void 0 ? void 0 : _c.key) !== null && _d !== void 0 ? _d : GTSLib.serializeGtsMetadata(gts); if (new RegExp(regexp).test(gtsName)) { this.hidden[gts.id] = true; } }); this.drawMap((_b = this.result) !== null && _b !== void 0 ? _b : new DataModel(), true); return Promise.resolve(); } async hideById(id) { var _a; Object.keys(this.hidden).forEach(k => { if (new RegExp(id.toString()).test(k)) { this.hidden[k] = true; } }); this.drawMap((_a = this.result) !== null && _a !== void 0 ? _a : new DataModel(), true); return Promise.resolve(); } async showById(id) { var _a; Object.keys(this.hidden).forEach(k => { if (new RegExp(id.toString()).test(k)) { this.hidden[k] = false; } }); this.drawMap((_a = this.result) !== null && _a !== void 0 ? _a : new DataModel(), true); return Promise.resolve(); } // noinspection JSUnusedGlobalSymbols componentWillLoad() { var _a, _b; this.parsing = true; this.LOG = new Logger(DiscoveryMapComponent, this.debug); if (typeof this.options === 'string') { this.innerOptions = JSON.parse(this.options); } else { this.innerOptions = this.options; } this.result = GTSLib.getData(this.result); this.divider = GTSLib.getDivider((_a = this.innerOptions.timeUnit) !== null && _a !== void 0 ? _a : 'us'); (_b = this.LOG) === null || _b === void 0 ? void 0 : _b.debug(['componentWillLoad'], { type: this.type, options: this.innerOptions, toDisplay: this.toDisplay, }); const dims = Utils.getContentBounds(this.el.parentElement); this.width = dims.w; this.height = dims.h - 100; this.parsing = false; } // noinspection JSUnusedGlobalSymbols componentDidLoad() { var _a; this.drawMap((_a = this.result) !== null && _a !== void 0 ? _a : new DataModel()); } drawMap(data, isRefresh = false, optionUpdate) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22; let tilesPromise; let zoomPromise; this.tileLayers = []; let options = Utils.mergeDeep(this.defOptions, (_a = this.innerOptions) !== null && _a !== void 0 ? _a : {}); (_b = this.LOG) === null || _b === void 0 ? void 0 : _b.debug(['drawMap', 'this.options 2 '], Object.assign({}, data.globalParams)); options = Utils.mergeDeep(options, (_c = data.globalParams) !== null && _c !== void 0 ? _c : {}); optionUpdate = JSON.stringify(options) !== JSON.stringify(this.innerOptions); this.innerOptions = Utils.clone(options); this.divider = GTSLib.getDivider((_d = this.innerOptions.timeUnit) !== null && _d !== void 0 ? _d : 'us'); if (this.map) { this.map.invalidateSize(true); } (_e = this.LOG) === null || _e === void 0 ? void 0 : _e.debug(['drawMap', 'data'], data); (_f = this.LOG) === null || _f === void 0 ? void 0 : _f.debug(['drawMap', 'this.height'], this.height); (_g = this.LOG) === null || _g === void 0 ? void 0 : _g.debug(['drawMap', 'this.options'], Object.assign({}, this.innerOptions)); const dataList = GTSLib.flatDeep(GTSLib.flattenGtsIdArray(data.data, 0).res); data.params = (_h = data.params) !== null && _h !== void 0 ? _h : []; const params = data.params; this.mapOpts = (_j = this.innerOptions.map) !== null && _j !== void 0 ? _j : {}; dataList.forEach(g => { if (GTSLib.isGts(g)) { if (!this.hidden[g.id]) { this.hidden[g.id] = false; } } }); this.pathData = (_k = MapLib.toLeafletMapPaths({ gts: dataList, params, globalParams: this.innerOptions, }, this.hidden, this.innerOptions.scheme)) !== null && _k !== void 0 ? _k : []; this.positionData = (_l = MapLib.toLeafletMapPositionArray({ gts: dataList, params, globalParams: this.innerOptions, }, this.hidden, this.innerOptions.scheme)) !== null && _l !== void 0 ? _l : []; this.geoJson = MapLib.toGeoJSON({ gts: dataList, params }); if (this.mapOpts.mapType !== 'NONE') { const map = (_m = MapLib.mapTypes[this.mapOpts.mapType || 'DEFAULT']) !== null && _m !== void 0 ? _m : MapLib.mapTypes.DEFAULT; const mapOpts = { maxNativeZoom: (_o = this.mapOpts.maxNativeZoom) !== null && _o !== void 0 ? _o : 19, maxZoom: (_p = this.mapOpts.maxZoom) !== null && _p !== void 0 ? _p : 40, edgeBufferTiles: 5, }; if (map.attribution) { mapOpts.attribution = map.attribution; } if (map.subdomains) { mapOpts.subdomains = map.subdomains; } (_q = this.LOG) === null || _q === void 0 ? void 0 : _q.debug(['displayMap'], { isRefresh, optionUpdate }); if (!isRefresh || optionUpdate) { (_r = this.LOG) === null || _r === void 0 ? void 0 : _r.debug(['displayMap'], 'map', map); this.tileLayers.push(map.link); if (!!this.tilesLayer && this.tilesLayer._url !== map.link) { this.tileLayerGroup.removeLayer(this.tilesLayer); this.tilesLayer = undefined; } if (!this.tilesLayer) { this.tilesLayer = Leaflet.tileLayer(map.link, mapOpts); this.tilesLayer.addTo(this.tileLayerGroup); tilesPromise = new Promise(resolve => setTimeout(() => this.tilesLayer.on('load', () => resolve()))); } } } if (this.map) { (_s = this.LOG) === null || _s === void 0 ? void 0 : _s.debug(['displayMap'], 'map exists'); this.pathDataLayer.clearLayers(); this.positionDataLayer.clearLayers(); this.geoJsonLayer.clearLayers(); this.heatmapLayer.clearLayers(); this.shadowHeatmapLayer.clearLayers(); this.poiLayer.clearLayers(); } else { this.mainLayer = new Leaflet.LayerGroup([this.tileLayerGroup, this.heatmapLayer, this.geoJsonLayer, this.pathDataLayer, this.positionDataLayer]); this.map = Leaflet.map(this.mapElement, { preferCanvas: true, layers: this.mainLayer, zoomAnimation: true, maxBoundsViscocity: 1, worldCopyJump: true, maxBounds: new Leaflet.LatLngBounds(new Leaflet.latLng(-89.98155760646617, -180), new Leaflet.LatLng(89.99346179538875, 180)), maxZoom: (_t = this.mapOpts.maxZoom) !== null && _t !== void 0 ? _t : 19, }); this.geoJsonLayer.bringToBack(); Leaflet.control.scale().addTo(this.map); this.map.on('load', () => { var _a; return (_a = this.LOG) === null || _a === void 0 ? void 0 : _a.debug(['displayMap', 'load'], this.map.getCenter().lng, this.currentLong, this.map.getZoom()); }); this.map.on('zoomend', () => { if (!this.firstDraw) { this.currentZoom = this.map.getZoom(); this.geoBounds.emit(this.map.getBounds().toBBoxString()); } }); this.map.on('moveend', () => { if (!this.firstDraw) { this.currentLat = this.map.getCenter().lat; this.currentLong = this.map.getCenter().lng; } }); } const pathDataSize = ((_u = this.pathData) !== null && _u !== void 0 ? _u : []).length; for (let i = 0; i < pathDataSize; i++) { const path = this.pathData[i]; if (path) { this.updateGtsPath(path, data.params[i]); } } (_v = this.LOG) === null || _v === void 0 ? void 0 : _v.debug(['displayMap'], 'pathData', this.pathData); const positionsSize = ((_w = this.positionData) !== null && _w !== void 0 ? _w : []).length; for (let i = 0; i < positionsSize; i++) { const pData = this.positionData[i]; if (pData) { this.updatePositionArray(pData, data.params[i], i); } } (_x = this.LOG) === null || _x === void 0 ? void 0 : _x.debug(['displayMap'], 'positionData', this.positionData); ((_y = this.mapOpts.tiles) !== null && _y !== void 0 ? _y : []).forEach(t => { var _a, _b, _c, _d, _e, _f, _g, _h; (_a = this.LOG) === null || _a === void 0 ? void 0 : _a.debug(['displayMap'], t); const tile = { subdomains: 'abcd', maxNativeZoom: (_b = this.mapOpts.maxNativeZoom) !== null && _b !== void 0 ? _b : 19, maxZoom: (_c = this.mapOpts.maxZoom) !== null && _c !== void 0 ? _c : 19, }; if (typeof t === 'string') { tile.url = t; } else if (typeof t === 'object') { tile.url = t.url; tile.maxZoom = (_d = this.mapOpts.maxZoom) !== null && _d !== void 0 ? _d : 19; tile.maxNativeZoom = (_f = (_e = t.maxNativeZoom) !== null && _e !== void 0 ? _e : this.mapOpts.maxNativeZoom) !== null && _f !== void 0 ? _f : 19; } this.tileLayers.push(tile.url); const l = Leaflet.tileLayer(tile.url, { subdomains: 'abcd', maxNativeZoom: (_g = tile.maxNativeZoom) !== null && _g !== void 0 ? _g : 19, maxZoom: (_h = this.mapOpts.maxZoom) !== null && _h !== void 0 ? _h : 19, }); if (!this.tileLayerGroup.getLayers().find((l) => l._url === t.url)) { this.tileLayerGroup.addLayer(l); } }); if (!isRefresh || optionUpdate) { this.tileLayerGroup.getLayers().forEach((l) => { if (!this.tileLayers.includes(l._url)) { this.tileLayerGroup.removeLayer(l); } }); } const geoJsonSize = ((_z = this.geoJson) !== null && _z !== void 0 ? _z : []).length; for (let i = 0; i < geoJsonSize; i++) { const m = this.geoJson[i]; if (m) { const color = ColorLib.getColor(i, this.innerOptions.scheme); const opts = { style: () => { var _a, _b; return ({ color: (data.params && data.params[i]) ? (_a = data.params[i].datasetColor) !== null && _a !== void 0 ? _a : color : color, fillColor: (data.params && data.params[i]) ? ColorLib.transparentize((_b = data.params[i].fillColor) !== null && _b !== void 0 ? _b : color) : ColorLib.transparentize(color), }); }, }; if (m.geometry.type === 'Point') { opts.pointToLayer = (geoJsonPoint, latlng) => { var _a; return Leaflet.marker(latlng, { icon: this.icon(color, (data.params && data.params[i]) ? ((_a = data.params[i].map) !== null && _a !== void 0 ? _a : { marker: 'circle' }).marker : 'circle', (data.params && data.params[i]), 0), riseOnHover: true, opacity: 1, }); }; } let display = ''; const geoShape = Leaflet.geoJSON(m, opts); if (m.properties) { Object.keys(m.properties).forEach(k => display += `<b>${k}</b>: ${m.properties[k]}<br />`); geoShape.bindPopup(display); } geoShape.addTo(this.geoJsonLayer); } } let hasHeatmap = false; // HeatMap const size = (dataList !== null && dataList !== void 0 ? dataList : []).length; for (let i = 0; i < size; i++) { let p = (params !== null && params !== void 0 ? params : [])[i]; if (!p) { p = Object.assign({}, new Param()); } if (!!((_0 = p.map) === null || _0 === void 0 ? void 0 : _0.heatmap) && dataList[i].v[0] && dataList[i].v[0].length >= 3) { const g = dataList[i]; let max = Number.MIN_SAFE_INTEGER; let min = Number.MAX_SAFE_INTEGER; hasHeatmap = true; const hasHeatmapData = g.v.map((v) => { max = Math.max(max, v[v.length - 1]); min = Math.min(min, v[v.length - 1]); Leaflet.circleMarker([v[1], v[2]], { radius: 1 }).addTo(this.shadowHeatmapLayer); return [v[1], v[2], v[v.length - 1]]; }); Leaflet.heatLayer(hasHeatmapData, { radius: (_4 = (_2 = (_1 = p.map) === null || _1 === void 0 ? void 0 : _1.heatRadius) !== null && _2 !== void 0 ? _2 : (_3 = this.innerOptions.map) === null || _3 === void 0 ? void 0 : _3.heatRadius) !== null && _4 !== void 0 ? _4 : 25, minOpacity: (_8 = (_6 = (_5 = p.map) === null || _5 === void 0 ? void 0 : _5.heatOpacity) !== null && _6 !== void 0 ? _6 : (_7 = this.innerOptions.map) === null || _7 === void 0 ? void 0 : _7.heatOpacity) !== null && _8 !== void 0 ? _8 : 0.05, maxZoom: 0, max, blur: (_12 = (_10 = (_9 = p.map) === null || _9 === void 0 ? void 0 : _9.heatBlur) !== null && _10 !== void 0 ? _10 : (_11 = this.innerOptions.map) === null || _11 === void 0 ? void 0 : _11.heatBlur) !== null && _12 !== void 0 ? _12 : 15, }).addTo(this.heatmapLayer); } } if (this.pathData.length > 0 || this.positionData.length > 0 || this.geoJson.length > 0 || hasHeatmap) { // Fit map to curves const group = Leaflet.featureGroup([this.geoJsonLayer, this.positionDataLayer, this.pathDataLayer, this.shadowHeatmapLayer]); this.bounds = group.getBounds(); setTimeout(() => { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w; if (!!this.bounds && this.bounds.isValid()) { if ((this.currentLat || this.mapOpts.startLat) && (this.currentLong || this.mapOpts.startLong)) { (_a = this.LOG) === null || _a === void 0 ? void 0 : _a.debug(['displayMap', 'setView'], 'fitBounds', 'already have bounds'); if (this.mapOpts.track) { this.map.setView({ lat: (_c = (_b = this.mapOpts.startLat) !== null && _b !== void 0 ? _b : this.bounds.getCenter().lat) !== null && _c !== void 0 ? _c : 0, lng: (_e = (_d = this.mapOpts.startLong) !== null && _d !== void 0 ? _d : this.bounds.getCenter().lng) !== null && _e !== void 0 ? _e : 0, }, (_g = (_f = this.mapOpts.startZoom) !== null && _f !== void 0 ? _f : this.map.getBoundsZoom(this.bounds)) !== null && _g !== void 0 ? _g : 10, { animate: true }); } else { this.map.setView({ lat: (_j = (_h = this.currentLat) !== null && _h !== void 0 ? _h : this.mapOpts.startLat) !== null && _j !== void 0 ? _j : 0, lng: (_l = (_k = this.currentLong) !== null && _k !== void 0 ? _k : this.mapOpts.startLong) !== null && _l !== void 0 ? _l : 0, }, (_o = (_m = this.currentZoom) !== null && _m !== void 0 ? _m : this.mapOpts.startZoom) !== null && _o !== void 0 ? _o : 10, { animate: false }); } } else if (this.map && this.bounds) { (_p = this.LOG) === null || _p === void 0 ? void 0 : _p.debug(['displayMap', 'setView'], 'fitBounds', 'this.bounds', this.bounds); this.map.fitBounds(this.bounds, { padding: [1, 1], animate: false, duration: 0 }); } this.currentLat = this.map.getCenter().lat; this.currentLong = this.map.getCenter().lng; } else { (_q = this.LOG) === null || _q === void 0 ? void 0 : _q.debug(['displayMap', 'setView'], 'invalid bounds', { lat: this.currentLat, lng: this.currentLong }); this.map.setView({ lat: (_s = (_r = this.currentLat) !== null && _r !== void 0 ? _r : this.mapOpts.startLat) !== null && _s !== void 0 ? _s : 0, lng: (_u = (_t = this.currentLong) !== null && _t !== void 0 ? _t : this.mapOpts.startLong) !== null && _u !== void 0 ? _u : 0, }, (_w = (_v = this.currentZoom) !== null && _v !== void 0 ? _v : this.mapOpts.startZoom) !== null && _w !== void 0 ? _w : 10, { animate: false, duration: 0, }); zoomPromise = new Promise(resolve => this.map.once('moveend zoomend', () => resolve())); } }, 10); } else { (_13 = this.LOG) === null || _13 === void 0 ? void 0 : _13.debug(['displayMap', 'no data'], 'lost', this.currentZoom, this.mapOpts.startZoom); if (!this.mapOpts.track) { this.currentLat = (_14 = this.mapOpts.startLat) !== null && _14 !== void 0 ? _14 : 0; this.currentLong = (_15 = this.mapOpts.startLong) !== null && _15 !== void 0 ? _15 : 0; this.currentZoom = (_16 = this.mapOpts.startZoom) !== null && _16 !== void 0 ? _16 : 2; } this.map.setView([ (_18 = (_17 = this.currentLat) !== null && _17 !== void 0 ? _17 : this.mapOpts.startLat) !== null && _18 !== void 0 ? _18 : 0, (_20 = (_19 = this.currentLong) !== null && _19 !== void 0 ? _19 : this.mapOpts.startLong) !== null && _20 !== void 0 ? _20 : 0, ], (_22 = (_21 = this.currentZoom) !== null && _21 !== void 0 ? _21 : this.mapOpts.startZoom) !== null && _22 !== void 0 ? _22 : 2, { animate: false, duration: 0, }); zoomPromise = new Promise(resolve => setTimeout(() => this.map.once('moveend zoomend', () => resolve()))); } this.firstDraw = false; this.poiLayer.addTo(this.map); // this.patchMapTileGapBug(); void Promise.all([zoomPromise, tilesPromise]) .then(() => setTimeout(() => { if (this.initial) { this.draw.emit(); this.initial = false; } }, 500)); } icon(color, marker = '', param, i) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t; const c = `${ColorLib.sanitizeColor(color).slice(1)}`; let iconUrl; let iconSize = [20, 20]; let iconAnchor = [10, 10]; if (((_a = param === null || param === void 0 ? void 0 : param.map) === null || _a === void 0 ? void 0 : _a.iconSize) || ((_c = (_b = this.innerOptions) === null || _b === void 0 ? void 0 : _b.map) === null || _c === void 0 ? void 0 : _c.iconSize)) { const size = (_h = (_e = (_d = param === null || param === void 0 ? void 0 : param.map) === null || _d === void 0 ? void 0 : _d.iconSize) !== null && _e !== void 0 ? _e : (_g = (_f = this.innerOptions) === null || _f === void 0 ? void 0 : _f.map) === null || _g === void 0 ? void 0 : _g.iconSize) !== null && _h !== void 0 ? _h : [48, 48]; iconSize = GTSLib.isArray(size) ? size : [size, size]; iconAnchor = [iconSize[0] / 2, iconSize[0] / 2]; } const mark = GTSLib.isArray(marker) ? (_j = marker[i]) !== null && _j !== void 0 ? _j : 'circle' : (_k = marker) !== null && _k !== void 0 ? _k : 'circle'; if (mark.startsWith('http') || mark.startsWith('data:image')) { iconUrl = mark; } else if (mark.startsWith('<svg')) { iconUrl = 'data:image/svg+xml;base64,' + window.btoa(mark); } else { iconAnchor = [10, 22]; const margin = 2; if (((_l = param === null || param === void 0 ? void 0 : param.map) === null || _l === void 0 ? void 0 : _l.iconSize) || ((_o = (_m = this.innerOptions) === null || _m === void 0 ? void 0 : _m.map) === null || _o === void 0 ? void 0 : _o.iconSize)) { const size = (_t = (_q = (_p = param === null || param === void 0 ? void 0 : param.map) === null || _p === void 0 ? void 0 : _p.iconSize) !== null && _q !== void 0 ? _q : (_s = (_r = this.innerOptions) === null || _r === void 0 ? void 0 : _r.map) === null || _s === void 0 ? void 0 : _s.iconSize) !== null && _t !== void 0 ? _t : iconSize; iconSize = GTSLib.isArray(size) ? size : [size, size]; iconAnchor = [iconSize[0] / 2, iconSize[1] - margin]; } iconUrl = `https://www.mapmarker.io/api/v2/font-awesome/v5/pin?icon=fa-${mark}-solid&size=${iconSize[0]}&color=fff&background=${c}`; } return Leaflet.icon({ iconUrl, iconAnchor, iconSize }); } getGTSDots(gts, param) { var _a, _b, _c, _d, _e, _f, _g, _h, _j; const dots = []; let icon; let size; switch (gts.render) { case 'path': { icon = this.icon(gts.color, gts.marker, param, 0); size = ((_a = gts.path) !== null && _a !== void 0 ? _a : []).length; for (let i = 0; i < size; i++) { const g = gts.path[i]; if (i < size - 1 || !gts.marker) { const marker = Leaflet.circleMarker(g, { radius: (_b = gts.baseRadius) !== null && _b !== void 0 ? _b : MapLib.BASE_RADIUS, color: gts.color, fillColor: gts.color, fillOpacity: 1, riseOnHover: true, }); this.addPopup(gts, g.val, g.ts, marker, 0); dots.push(marker); } else { const marker = Leaflet.marker(g, { icon, riseOnHover: true, opacity: 1 }); this.addPopup(gts, g.val, g.ts, marker, icon.options.iconAnchor[1] * -1); dots.push(marker); } } break; } case 'marker': if (!GTSLib.isArray(gts.marker)) { icon = this.icon(gts.color, gts.marker, param, 0); } size = ((_c = gts.path) !== null && _c !== void 0 ? _c : []).length; for (let i = 0; i < size; i++) { if (GTSLib.isArray(gts.marker)) { icon = this.icon(gts.color, gts.marker, param, i); } const g = gts.path[i]; const marker = Leaflet.marker(g, { icon, riseOnHover: true, opacity: 1 }); this.addPopup(gts, g.val, g.ts, marker, 0); dots.push(marker); } break; case 'weightedDots': size = ((_d = gts.path) !== null && _d !== void 0 ? _d : []).length; for (let i = 0; i < size; i++) { const p = gts.path[i]; let v = parseInt(p.val, 10); if (isNaN(v)) { v = 0; } const radius = 50 * v / (((_e = gts.maxValue) !== null && _e !== void 0 ? _e : 1) - ((_f = gts.minValue) !== null && _f !== void 0 ? _f : 0)); const marker = Leaflet.circleMarker(p, { radius: radius === 0 ? 1 : radius, color: (_g = gts.borderColor) !== null && _g !== void 0 ? _g : 'transparent', fillColor: gts.color, fillOpacity: 0.5, riseOnHover: true, weight: 1, }); this.addPopup(gts, p.val, p.ts, marker, 0); dots.push(marker); } break; case 'dots': default: size = ((_h = gts.path) !== null && _h !== void 0 ? _h : []).length; for (let i = 0; i < size; i++) { const g = gts.path[i]; const marker = Leaflet.circleMarker(g, { radius: (_j = gts.baseRadius) !== null && _j !== void 0 ? _j : MapLib.BASE_RADIUS, color: gts.color, riseOnHover: true, fillColor: gts.color, fillOpacity: 1, }); this.addPopup(gts, g.val, g.ts, marker, 0); dots.push(marker); } break; } return dots; } updateGtsPath(gts, param) { const path = MapLib.pathDataToLeaflet(gts.path); const group = Leaflet.featureGroup(); if ((path !== null && path !== void 0 ? path : []).length > 1 && !!gts.line && (gts.render === 'dots' || gts.render === 'path')) { if (this.mapOpts.animate) { group.addLayer(new AntPath(path !== null && path !== void 0 ? path : [], { delay: 800, dashArray: [10, 100], weight: 5, color: ColorLib.transparentize(gts.color, 0.5), pulseColor: gts.color, paused: false, reverse: false, hardwareAccelerated: true, hardwareAcceleration: true, })); } else { group.addLayer(Leaflet.polyline(path !== null && path !== void 0 ? path : [], { color: gts.color, opacity: 0.5 })); } } const dots = this.getGTSDots(gts, param); const size = (dots !== null && dots !== void 0 ? dots : []).length; for (let i = 0; i < size; i++) { group.addLayer(dots[i]); } this.pathDataLayer.addLayer(group); } addPopup(positionData, value, ts, marker, offset) { var _a, _b, _c, _d; if (positionData) { let date = ts; if (ts && ((_a = this.innerOptions.timeMode) !== null && _a !== void 0 ? _a : 'date') === 'date') { date = ((_b = GTSLib.toISOString(ts !== null && ts !== void 0 ? ts : 0, this.divider, this.innerOptions.timeZone, this.innerOptions.timeFormat)) !== null && _b !== void 0 ? _b : '') .replace('T', ' ').replace(/\+[0-9]{2}:[0-9]{2}$/gi, ''); } let content = ''; content = `${date ? `<p>${date}</p>` : ''}<p><b>${positionData.key}</b>: ${value === 0 ? 0 : value !== null && value !== void 0 ? value : 'na'}</p>`; Object.keys((_c = positionData.properties) !== null && _c !== void 0 ? _c : []) .forEach(k => content += `<b>${k}</b>: ${decodeURIComponent(positionData.properties[k])}<br />`); if (positionData.tooltip[ts]) { content += positionData.tooltip[ts]; } marker.on('mouseover', () => { var _a; marker.openPopup(); this.markerOver = true; if (this.popupTimeout) { clearTimeout(this.popupTimeout); } this.popupTimeout = setTimeout(() => { if (marker.isPopupOpen() && !this.markerOver) marker.closePopup(); }, (_a = this.innerOptions.tooltipDelay) !== null && _a !== void 0 ? _a : 3000); this.dataPointOver.emit({ date: ts, name: positionData.key, value, meta: positionData.properties, }); }); this.markersRef = Object.assign({}, (_d = this.markersRef) !== null && _d !== void 0 ? _d : {}); if (!this.markersRef[positionData.key]) { this.markersRef[positionData.key] = {}; } this.markersRef[positionData.key][ts] = marker; marker.bindPopup(content, { autoClose: true, offset: new Leaflet.Point(0, offset) }); } marker.on('mouseout', () => this.markerOver = false); marker.on('click', () => { const date = this.innerOptions.timeMode === 'date' ? GTSLib.zonedTimeToUtc(ts, 1, this.innerOptions.timeZone) * this.divider : ts; this.dataPointSelected.emit({ date, name: positionData.key, value, meta: positionData.properties }); if (this.innerOptions.poi) { if (this.pois.find(p => p.lat === marker.getLatLng().lat && p.lng === marker.getLatLng().lng && p.name === positionData.key)) { this.pois = this.pois.filter(p => p.lat !== marker.getLatLng().lat && p.lng !== marker.getLatLng().lng && p.name !== positionData.key); } else { this.pois.push({ date, name: positionData.key, value, meta: positionData.properties, uid: v4(), lat: marker.getLatLng().lat, lng: marker.getLatLng().lng, }); } this.poiLayer.clearLayers(); this.poi.emit(this.pois); this.pois.forEach(p => { const icon = this.icon(this.innerOptions.poiColor, undefined, this.innerOptions, 0); const m = Leaflet.marker([p.lat, p.lng], { icon, riseOnHover: true, opacity: 1 }); this.poiLayer.addLayer(m); }); } }); } async setFocus(regexp, ts) { var _a; Object.keys((_a = this.markersRef) !== null && _a !== void 0 ? _a : {}) .filter(s => new RegExp(regexp).test(s)) .forEach(k => { if (this.markersRef[k][ts]) { this.markersRef[k][ts].openPopup(); } }); return Promise.resolve(); } async unFocus() { Object.keys(this.markersRef) .forEach(k => { var _a; (Object.keys((_a = this.markersRef[k]) !== null && _a !== void 0 ? _a : {})) .forEach(ts => { if (this.markersRef[k][ts]) { if (this.markersRef[k][ts].isPopupOpen() && !this.markerOver) this.markersRef[k][ts].closePopup(); } }); }); return Promise.resolve(); } updatePositionArray(positionData, param, dataIndex) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x; const opts = {}; if ((_a = this.mapOpts) === null || _a === void 0 ? void 0 : _a.maxClusterRadius) opts.maxClusterRadius = this.mapOpts.maxClusterRadius; if ((_b = this.mapOpts) === null || _b === void 0 ? void 0 : _b.clusterCustomIcon) { opts.iconCreateFunction = (cluster) => { var _a; const ico = this.icon(GTSLib.isArray(positionData.color) ? (_a = positionData.color[0]) !== null && _a !== void 0 ? _a : ColorLib.getColor(dataIndex, this.innerOptions.scheme) : positionData.color, positionData.marker, param, 0); const icoHtmlElt = ico.createIcon(); const icoW = parseInt(icoHtmlElt.style.getPropertyValue('width'), 10); const icoH = parseInt(icoHtmlElt.style.getPropertyValue('height'), 10); const icoMarginLeft = icoHtmlElt.style.getPropertyValue('margin-left'); const icoMarginTop = icoHtmlElt.style.getPropertyValue('margin-top'); // remove shift from ico, to apply it to the parent div later on icoHtmlElt.style.removeProperty('margin-left'); icoHtmlElt.style.removeProperty('margin-top'); // 30 pixel is hardcoded for the cluster child count indicator const html = `<div style="margin-left:${icoMarginLeft};margin-top:${icoMarginTop};"> <div style="position:absolute">${icoHtmlElt.outerHTML}</div> <div style="position:absolute;left:${(icoW / 2) - 15}px;top:${(icoH / 2) - 15}px;width:30px;height:30px;border-radius:50%;background-color:rgba(255,255,255,0.8);text-align:center;line-height: 30px;"> ${cluster.getChildCount()} </div> </div>`; return Leaflet.divIcon({ html: html }); }; } const group = ((_c = this.innerOptions.map) === null || _c === void 0 ? void 0 : _c.cluster) ? Leaflet.markerClusterGroup(opts) : Leaflet.featureGroup(); const path = MapLib.updatePositionArrayToLeaflet(positionData.positions); if (((_d = positionData.positions) !== null && _d !== void 0 ? _d : []).length > 1 && !!positionData.line) { if (this.mapOpts.animate) { group.addLayer(antPath(path !== null && path !== void 0 ? path : [], { delay: 800, dashArray: [10, 100], weight: 5, color: ColorLib.transparentize(positionData.color, 0.5), pulseColor: positionData.color, paused: false, reverse: false, hardwareAccelerated: true, hardwareAcceleration: true, })); } else { group.addLayer(Leaflet.polyline(path !== null && path !== void 0 ? path : [], { color: positionData.color, opacity: 0.5 })); } } let icon; let result; let inStep; let size; (_e = this.LOG) === null || _e === void 0 ? void 0 : _e.debug(['updatePositionArray'], positionData); switch (positionData.render) { case 'marker': size = ((_f = positionData.positions) !== null && _f !== void 0 ? _f : []).length; for (let i = 0; i < size; i++) { const p = positionData.positions[i]; icon = this.icon(GTSLib.isArray(positionData.color) ? (_g = positionData.color[i]) !== null && _g !== void 0 ? _g : ColorLib.getColor(dataIndex, this.innerOptions.scheme) : positionData.color, positionData.marker, param, GTSLib.isArray(positionData.marker) ? i : 0); const marker = Leaflet.marker({ lat: p[0], lng: p[1] }, { icon, riseOnHover: true, opacity: 1 }); this.addPopup(positionData, p[2], undefined, marker, 0); group.addLayer(marker); } (_h = this.LOG) === null || _h === void 0 ? void 0 : _h.debug(['updatePositionArray', 'build marker'], icon); break; case 'coloredWeightedDots': (_j = this.LOG) === null || _j === void 0 ? void 0 : _j.debug(['updatePositionArray', 'coloredWeightedDots'], positionData); result = []; inStep = []; for (let j = 0; j < positionData.numColorSteps; j++) { result[j] = 0; inStep[j] = 0; } size = ((_k = positionData.positions) !== null && _k !== void 0 ? _k : []).length; for (let i = 0; i < size; i++) { const p = positionData.positions[i]; const radius = (parseInt(p[2], 10) - ((_l = positionData.minValue) !== null && _l !== void 0 ? _l : 0)) * 50 / ((_m = positionData.maxValue) !== null && _m !== void 0 ? _m : 50); (_o = this.LOG) === null || _o === void 0 ? void 0 : _o.debug(['updatePositionArray', 'coloredWeightedDots', 'radius'], positionData.baseRadius * p[4]); const marker = Leaflet.circleMarker({ lat: p[0], lng: p[1] }, { radius, color: (_p = positionData.borderColor) !== null && _p !== void 0 ? _p : positionData.color, fillColor: ColorLib.rgb2hex(positionData.colorGradient[p[5]].r, positionData.colorGradient[p[5]].g, positionData.colorGradient[p[5]].b), riseOnHover: true, fillOpacity: 0.3, }); this.addPopup(positionData, p[2], undefined, marker, 0); group.addLayer(marker); } break; case 'weightedDots': size = ((_q = positionData.positions) !== null && _q !== void 0 ? _q : []).length; for (let i = 0; i < size; i++) { const p = positionData.positions[i]; const radius = (parseInt(p[2], 10) - ((_r = positionData.minValue) !== null && _r !== void 0 ? _r : 0)) * 50 / ((_s = positionData.maxValue) !== null && _s !== void 0 ? _s : 50); const marker = Leaflet.circleMarker({ lat: p[0], lng: p[1] }, { radius, color: (_t = positionData.borderColor) !== null && _t !== void 0 ? _t : positionData.color, fillColor: positionData.color, weight: 2, riseOnHover: true, fillOpacity: 0.3, }); this.addPopup(positionData, p[2], undefined, marker, 0); group.addLayer(marker); } break; case 'dots': default: size = ((_u = positionData.positions) !== null && _u !== void 0 ? _u : []).length; for (let i = 0; i < size; i++) { const p = positionData.positions[i]; const marker = Leaflet.circleMarker({ lat: p[0], lng: p[1] }, { radius: (_v = positionData.baseRadius) !== null && _v !== void 0 ? _v : MapLib.BASE_RADIUS, color: (_w = positionData.borderColor) !== null && _w !== void 0 ? _w : positionData.color, fillColor: positionData.color, weight: 2, riseOnHover: true, fillOpacity: 0.7, }); this.addPopup(positionData, p[2] === 0 ? 0 : (_x = p[2]) !== null && _x !== void 0 ? _x : 'na', undefined, marker, 0); group.addLayer(marker); } break; } this.positionDataLayer.addLayer(group); } render() { return h("div", { key: '482e7ef350484a24917ddeca6972d547fe959207', class: "map-container" }, h("div", { key: '161063f2ac095f763c54d26c0eb3835ae948d18f', ref: (el) => this.mapElement = el })); } static get is() { return "discovery-map"; } static get encapsulation() { return "shadow"; } static get originalStyleUrls() { return { "$": ["discovery-map.scss"] }; } static get styleUrls() { return { "$": ["discovery-map.css"] }; } static get properties() { return { "result": { "type": "string", "mutable": true, "complexType": { "original": "DataModel | string", "resolved": "DataModel | string", "references": { "DataModel": { "location": "import", "path": "../../model/types", "id": "src/model/types.ts::DataModel" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "getter": false, "setter": false, "attribute": "result", "reflect": false }, "type": { "type": "string", "mutable": false, "complexType": { "original": "ChartType", "resolved": "string", "references": { "ChartType": { "location": "import", "path": "../../model/types", "id": "src/model/types.ts::ChartType" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "getter": false, "setter": false, "attribute": "type", "reflect": false }, "options": { "type": "string", "mutable": false, "complexType": { "original": "Param | string", "resolved": "Param | string", "references": { "Param": { "location": "import", "path": "../../model/param", "id": "src/model/param.ts::Param" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "getter": false, "setter": false, "attribute": "options", "reflect": false, "defaultValue": "new Param()" }, "width": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "getter": false, "setter": false, "attribute": "width", "reflect": false }, "height": { "type": "number", "mutable": true, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "getter": false, "setter": false, "attribute": "height", "reflect": false }, "debug": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "getter": false, "setter": false, "attribute": "debug", "reflect": false, "defaultValue": "false" } }; } static get states() { return { "width": {}, "height": {}, "parsing": {}, "toDisplay": {}, "innerOptions": {} }; } static get events() { return [{ "method": "draw", "name": "draw", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [],