cleanup of obsolote leaflet components

This commit is contained in:
Christian Beutel
2024-11-30 01:13:57 +01:00
parent 8c42e9e695
commit 8f8d28ef7a
56 changed files with 118 additions and 9198 deletions

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 8.5 8.5"><defs><filter id="shadow"><feDropShadow dx="0" dy="0" stdDeviation="0.3" flood-color="#000000"/></filter></defs><circle cx="4.2" cy="4.2" r="2.2" fill="#ffffff" fill-opacity="1" filter="url(#shadow)"/><circle cx="4.2" cy="4.2" r="1.85" fill="none" stroke="#333333" stroke-linejoin="round" stroke-width="0.45"/><circle cx="4.2" cy="4.2" r="1.25" fill="none" stroke="#333333" stroke-linejoin="round" stroke-width="0.25"/><circle cx="4.2" cy="4.2" r="0.55" fill="#333333"/></svg>

Before

Width:  |  Height:  |  Size: 563 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -1,405 +0,0 @@
/*
* https://github.com/adoroszlai/joebed/tree/gh-pages
*
* The MIT License (MIT)
*
* Copyright (c) 2014- Doroszlai Attila, 2019- Raruto
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
L.Mixin.Selectable = {
includes: L.Mixin.Events,
setSelected: function (s) {
var selected = !!s;
if (this._selected !== selected) {
this._selected = selected;
this.fire('selected');
}
},
isSelected: function () {
return !!this._selected;
},
};
L.Mixin.Selection = {
includes: L.Mixin.Events,
getSelection: function () {
return this._selected;
},
setSelection: function (item) {
if (this._selected === item) {
if (item !== null) {
item.setSelected(!item.isSelected());
if (!item.isSelected()) {
this._selected = null;
}
}
} else {
if (this._selected) {
this._selected.setSelected(false);
}
this._selected = item;
if (this._selected) {
this._selected.setSelected(true);
}
}
this.fire('selection_changed', { polyline: item });
},
};
L.GeoJSON.include(L.Mixin.Selectable);
export const GpxGroup = L.GpxGroup = L.Class.extend({
options: {
highlight: {
opacity: 1,
weight: 6,
},
points: [],
points_options: {
icon: {
iconUrl: '../images/elevation-poi.png',
iconSize: [12, 12],
}
},
flyToBounds: true,
elevation: true,
elevation_options: {
theme: 'lightblue-theme',
detached: true,
elevationDiv: '#elevation',
},
distanceMarkers: true,
distanceMarkers_options: {
lazy: true,
distance: false,
direction: true,
offset: 1000,
},
},
initialize: function (tracks, options) {
L.Util.setOptions(this, options);
this._count = 0;
this._loadedCount = 0;
this._tracks = tracks;
this._layers = L.featureGroup();
this._markers = L.featureGroup();
this._hotline = L.featureGroup();
this._elevation = L.control.elevation(this.options.elevation_options);
this._routes = [];
this.options.points.forEach((poi) =>
L
.marker(poi.latlng, { icon: L.icon(this.options.points_options.icon) })
.bindTooltip(poi.name, { direction: 'auto' }).addTo(this._markers)
);
},
getBounds: function () {
return this._layers.getBounds();
},
addTo: function (map) {
this._hotline.addTo(map);
this._layers.addTo(map);
this._markers.addTo(map);
this._map = map;
this.on('selection_changed', this._onSelectionChanged, this);
this.addTracks();
},
addTracks() {
this._tracks.forEach(this._addTrack, this);
},
highlightTrack(id) {
const route = this._routes.find(r => r.options.id == id)
if (!route) {
return;
}
route.eachLayer((l) => {
this.highlight(route, l)
})
},
unHighlightTrack(id) {
const route = this._routes.find(r => r.options.id == id)
if (!route) {
return;
}
route.eachLayer((l) => {
this.unhighlight(route, l)
})
},
select(id) {
const route = this._routes.find(r => r.options.id == id)
if (!route) {
return;
}
this.setSelection(route)
},
resetSelection() {
this.setSelection(this._selected)
if (this.options.flyToBounds) {
this._map.flyToBounds(this.getBounds(), { duration: 0.25, easeLinearity: 0.25, noMoveStart: true });
}
},
openPopup(id) {
const route = this._routes.find(r => r.options.id == id)
if (!route) {
return;
}
route.openPopup();
},
closePopup(id) {
const route = this._routes.find(r => r.options.id == id)
if (!route) {
return;
}
route.closePopup();
},
_addTrack: function (track) {
this._elevation._parseFromString(track.gpx)
.then(geojson => this._loadGeoJSON(geojson, track.id, track.gpx.split('/').pop().split('#')[0].split('?')[0]))
},
clear: function () {
this._elevation.clear()
this._elevation.remove();
this._clearLayers();
this._clearLayers(this._markers);
this._clearLayers(this._hotline)
this._count = 0;
this._loadedCount = 0;
this._tracks = []
this._routes = []
this.fire('clear')
},
_clearLayers(l) {
l = l || this._layers;
if (l && l.eachLayer) {
l.eachLayer(f => f.remove())
l.clearLayers();
}
},
_loadGeoJSON: function (geojson, id, fallbackName) {
if (geojson) {
geojson.id = id
geojson.name = geojson.name || (geojson[0] && geojson[0].properties.name) || fallbackName;
this._loadRoute(geojson);
}
},
_loadRoute: function (data) {
if (!data) return;
var line_style = {
color: this._stringToColor(data.id),
opacity: 0.75,
weight: 5,
distanceMarkers: this.options.distanceMarkers_options,
};
var route = L.geoJson(data, {
name: data.name || '',
style: (feature) => line_style,
distanceMarkers: line_style.distanceMarkers,
originalStyle: line_style,
isGroupLayer: true,
id: data.id,
filter: feature => feature.geometry.type != "Point",
});
this._elevation.import([this._elevation.__LGEOMUTIL, this._elevation.__LDISTANCEM]).then(() => {
route.addTo(this._layers);
route.eachLayer((layer) => this._onEachRouteLayer(route, layer));
this._onEachRouteLoaded(route);
});
},
_onEachRouteLayer: function (route, layer) {
var polyline = layer;
this._routes.push(route)
route.on('selected', L.bind(this._onRouteSelected, this, route, polyline));
polyline.on('mouseover', L.bind(this._onRouteMouseOver, this, route, polyline));
polyline.on('mouseout', L.bind(this._onRouteMouseOut, this, route, polyline));
polyline.on('click', L.bind(this._onRouteClick, this, route, polyline));
const startIcon = L.divIcon({
html: '<i class="p-2 text-white bg-gray-500 rounded-full fa fa-bullseye -translate-x-1/2"></i>',
className: 'start-icon'
});
const endIcon = L.divIcon({
html: '<i class="p-2 text-white bg-gray-500 rounded-full fa fa-flag-checkered -translate-x-1/2"></i>',
className: 'end-icon'
});
const latlngs = polyline.getLatLngs().flat(1);
polyline.setLatLngs(latlngs);
if (this._loadedCount == 0 || !this.options.itinerary) {
L.marker(latlngs[0], { icon: startIcon }).addTo(this._markers)
}
L.marker(latlngs[latlngs.length - 1], { icon: endIcon }).addTo(this._markers)
},
_onEachRouteLoaded: function (route) {
this.fire('route_loaded', { route: route });
if (++this._loadedCount === this._tracks.length) {
this.fire('loaded');
if (this.options.flyToBounds) {
this._map.flyToBounds(this.getBounds(), { duration: 0.25, easeLinearity: 0.25, noMoveStart: true });
}
}
},
highlight: function (route, polyline) {
polyline.setStyle(this.options.highlight);
polyline.options.highlighted = true
if (this.options.distanceMarkers) {
polyline.addDistanceMarkers();
}
},
unhighlight: function (route, polyline) {
polyline.setStyle(route.options.originalStyle);
polyline.options.highlighted = false
if (this.options.distanceMarkers) {
polyline.removeDistanceMarkers();
}
},
_onRouteMouseOver: function (route, polyline) {
if (!route.isSelected()) {
this.highlight(route, polyline);
}
this.fire('route_mouseover', { route: route, polyline: polyline });
},
_onRouteMouseOut: function (route, polyline) {
if (!route.isSelected()) {
this.unhighlight(route, polyline);
}
this.fire('route_mouseout', { route: route, polyline: polyline });
},
_onRouteClick: function (route, polyline) {
this.highlight(route, polyline)
this.setSelection(route);
},
_onRouteSelected: function (route, polyline) {
if (!route.isSelected()) {
this.unhighlight(route, polyline);
}
},
_onSelectionChanged: async function (e) {
var elevation = this._elevation;
var eleDiv = elevation.getContainer();
var route = this.getSelection();
var hotline = this._hotline;
hotline.clearLayers();
if (route && route.isSelected()) {
elevation.clear();
if (!eleDiv) {
elevation.addTo(this._map);
this._map.invalidateSize()
}
for (const layer of route.getLayers()) {
if (layer instanceof L.Polyline) {
await elevation.addData(layer, false);
}
}
await elevation._initHotLine(route, this._hotline)
this._map.flyToBounds(route.getBounds(), { duration: 0.25, easeLinearity: 0.25, noMoveStart: true });
} else {
if (eleDiv) {
elevation.remove();
this._map.invalidateSize()
}
}
},
_stringToColor(input) {
// Define the maximum brightness to ensure the color is not too light
const maxBrightness = 200;
// Divide the string into 3 parts (5 characters each)
const redPart = input.slice(0, 5);
const greenPart = input.slice(5, 10);
const bluePart = input.slice(10, 15);
// Calculate the red, green, and blue values by summing the char codes of the parts
const red = Math.floor((redPart.split('').reduce((sum, char) => sum + char.charCodeAt(0), 0) % 256) * (maxBrightness / 255));
const greenRaw = greenPart.split('').reduce((sum, char) => sum + char.charCodeAt(0), 0) % 256;
const green = Math.floor((greenRaw * 0.5) * (maxBrightness / 255)); // Reduce green to avoid greenish colors
const blue = Math.floor((bluePart.split('').reduce((sum, char) => sum + char.charCodeAt(0), 0) % 256) * (maxBrightness / 255));
// Format as HEX color
return `#${(1 << 24 | red << 16 | green << 8 | blue).toString(16).slice(1).toUpperCase()}`;
},
removeFrom: function (map) {
this._layers.removeFrom(map);
},
});
L.GpxGroup.include(L.Mixin.Events);
L.GpxGroup.include(L.Mixin.Selection);
L.gpxGroup = (tracks, options) => new L.GpxGroup(tracks, options);

File diff suppressed because it is too large Load Diff

View File

@@ -1,350 +0,0 @@
.leaflet-hidden {
visibility: hidden;
}
.legend {
cursor: pointer;
}
.leaflet-container {
z-index: 0;
/* prevent overlapping the .elevation-detached chart */
}
.elevation-control .background {
background-color: var(--ele-bg, rgba(70, 130, 180, 0.2));
border-radius: 5px;
overflow: visible;
display: block;
touch-action: none;
user-select: none;
max-width: 100%;
}
.elevation-control .grid,
.elevation-control .area>foreignObject,
.elevation-control .axis,
.elevation-control .tooltip,
.height-focus.line {
pointer-events: none;
}
.elevation-control .axis line,
.elevation-control .axis path {
stroke: var(--ele-axis, #2D1130);
stroke-width: 1;
fill: none;
}
.elevation-control .grid .tick line {
stroke: var(--ele-grid, #EEE);
stroke-width: 1px;
shape-rendering: crispEdges;
}
.elevation-control .grid path {
stroke-width: 0;
}
.elevation-control .axis text,
.elevation-control .legend text,
.elevation-control .point text {
fill: #fff;
font-weight: 700;
paint-order: stroke fill;
stroke: #000;
stroke-width: 2px
}
.elevation-control .legend .legend-switcher-symbol {
fill: rgb(135, 135, 135);
}
.elevation-control .y.axis text {
text-anchor: end;
}
.elevation-control .area {
fill: var(--ele-area, #4682B4);
stroke: var(--ele-stroke, #000);
stroke-width: 1.2;
paint-order: stroke fill;
}
.elevation-control .horizontal-drag-line {
cursor: row-resize;
stroke: transparent;
stroke-dasharray: 5;
stroke-width: 1.1;
}
.elevation-control .active .horizontal-drag-line {
stroke: #000;
}
.elevation-control .horizontal-drag-label {
fill: #000;
font-weight: 700;
paint-order: stroke;
stroke: #FFF;
stroke-width: 2px;
}
.elevation-control .ruler {
color: #000;
cursor: row-resize;
}
.elevation-control .mouse-focus-line {
stroke: #000;
stroke-width: 1;
}
.elevation-control .mouse-focus-label-rect {
fill: #000;
fill-opacity: 0.75;
stroke-width: 1;
stroke: #444;
}
.elevation-control .mouse-focus-label-text {
fill: #FFF;
font-size: 10px;
}
.elevation-control .brush .overlay {
cursor: unset;
}
.elevation-control .brush .selection {
fill: var(--ele-brush, rgba(23, 74, 117, 0.4));
stroke: none;
fill-opacity: unset;
}
.elevation-summary {
font-family: "Lucida Grande", "Lucida Sans Unicode", Verdana, Arial, Helvetica, sans-serif;
font-size: 12px;
margin: var(--ele-sum-margin, 0 auto);
text-shadow: var(--ele-sum-shadow, 1px 0 0 #FFF, -1px 0 0 #FFF, 0 1px 0 #FFF, 0 -1px 0 #FFF, 1px 1px #FFF, -1px -1px 0 #FFF, 1px -1px 0 #FFF, -1px 1px 0 #FFF);
}
.elevation-summary>span:not(:last-child):after {
content: var(--ele-sum-sep, '');
}
.multiline-summary>span {
display: block;
}
.multiline-summary .download {
float: right;
margin-top: -3em;
margin-right: 2em;
font-weight: bold;
font-size: 1.2em;
}
.elevation-summary .summaryvalue {
font-weight: bold;
}
.elevation-toggle-icon {
background-color: #fff;
right: 5px;
top: 5px;
height: var(--ele-toggle-size, 36px);
width: var(--ele-toggle-size, 36px);
cursor: pointer;
box-shadow: 0 1px 7px rgba(0, 0, 0, 0.4);
border-radius: 5px;
display: inline-block;
position: var(--ele-toggle-pos, relative);
}
.elevation-toggle-icon:before {
content: '\2716';
display: var(--ele-close-btn, none);
color: #000;
width: 100%;
line-height: 20px;
text-align: center;
font-weight: bold;
font-size: 15px;
}
.leaflet-elevation-pane .height-focus,
.leaflet-overlay-pane .height-focus {
stroke: #000;
fill: var(--ele-circle, var(--ele-area, #FFF));
}
.leaflet-elevation-pane .height-focus.line,
.leaflet-overlay-pane .height-focus.line {
stroke-width: 2;
}
.leaflet-elevation-pane .height-focus-label,
.leaflet-overlay-pane .height-focus-label {
font-size: 12px;
font-weight: 600;
fill: #000;
paint-order: stroke;
stroke: #FFF;
stroke-width: 2px;
}
.elevation-waypoint-icon:before,
.elevation-position-icon:before {
content: "";
width: 100%;
height: 100%;
display: inline-block;
background: var(--ele-marker) no-repeat center center / contain;
}
.elevation-polyline {
stroke: var(--ele-poly, var(--ele-area, #000));
filter: drop-shadow(1px 1px 0 #FFF) drop-shadow(-1px -1px 0 #FFF) drop-shadow(1px -1px 0 #FFF) drop-shadow(-1px 1px 0 #FFF);
}
/* CHART STATES /////////////////////////////////////////////////// */
.elevation-detached {
font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
height: auto;
width: 100%;
position: relative;
z-index: 0;
}
.elevation-detached .area {
fill-opacity: var(--ele-alpha, 0.8);
}
.elevation-detached.elevation-collapsed .elevation-summary {
display: block;
}
.elevation-detached.elevation-collapsed .elevation-toggle-icon {
top: 5px;
right: 9px;
bottom: 5px;
margin: auto;
}
.elevation-control.elevation-collapsed>* {
display: none;
}
.elevation-control.elevation-collapsed>.elevation-toggle-icon {
display: inline-block;
}
.elevation-detached {
--ele-sum-margin: 12px 35px;
--ele-sum-shadow: none;
--ele-toggle-pos: absolute;
}
.elevation-expanded {
--ele-close-btn: inline-block;
--ele-toggle-bg: none;
--ele-toggle-pos: absolute;
--ele-toggle-size: 20px;
}
.inline-summary {
--ele-sum-sep: "\0020\2014\0020";
}
.elevation-waypoint-icon {
--ele-marker: url(../images/elevation-pushpin.svg);
}
.elevation-position-icon {
--ele-marker: url(../images/elevation-position.svg);
}
/* LIME THEME ///////////////////////////////////////////////////// */
.lime-theme {
--ele-bg: rgba(156, 194, 34, 0.2);
--ele-axis: #566B13;
--ele-area: #9CC222;
--ele-grid: #CCC;
--ele-brush: rgba(99, 126, 11, 0.4);
--ele-poly: #566B13;
--ele-line: #70ab00;
}
/* STEELBLUE THEME //////////////////////////////////////////////// */
.steelblue-theme {
--ele-axis: #0D1821;
--ele-area: #4682B4;
--ele-brush: rgba(23, 74, 117, 0.4);
--ele-line: #174A75;
}
/* PURPLE THEME /////////////////////////////////////////////////// */
.purple-theme {
--ele-bg: rgba(115, 44, 123, 0.2);
--ele-area: #732C7B;
--ele-brush: rgba(74, 14, 80, 0.4);
--ele-line: #732c7b;
}
/* YELLOW THEME /////////////////////////////////////////////////// */
.yellow-theme {
--ele-area: #FF0;
}
/* RED THEME ////////////////////////////////////////////////////// */
.red-theme {
--ele-area: #F00;
}
/* MAGENTA THEME ////////////////////////////////////////////////// */
.magenta-theme {
--ele-bg: rgba(255, 255, 255, 0.47);
--ele-area: #FF005E;
}
/* LIGHTBLUE THEME //////////////////////////////////////////////// */
.lightblue-theme {
--ele-area: #3366CC;
--ele-alpha: 0.45;
--ele-stroke: #4682B4;
--ele-circle: #fff;
--ele-line: #000;
--ele-grid: rgba(var(--input-border));
}
/* GRAY THEME //////////////////////////////////////////////// */
.gray-theme {
--ele-bg: #ffffff;
--ele-area: #242734;
--ele-alpha: 0.45;
--ele-stroke: #7b7b7b;
--ele-circle: #fff;
--ele-line: #000;
--ele-grid: #d1d5db;
}
.elevation-detached.lightblue-theme .area {
stroke: #3366CC;
}
/* leaflet-distance-markers */
.dist-marker {
font-size: 0.5rem;
border: 1px solid #777;
border-radius: 10px;
text-align: center;
color: #000;
background: #fff;
}
.leaflet-popup-content {
width: max-content !important;
max-width: 100%;
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright (c) 2019, GPL-3.0+ Project, Raruto
*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright (c) 2013-2016, MIT License, Felix “MrMufflon” Bache
*
* Permission to use, copy, modify, and/or distribute this software
* for any purpose with or without fee is hereby granted, provided
* that the above copyright notice and this permission notice appear
* in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
import * as _ from './utils';
import { Elevation } from './control';
Elevation.Utils = _;
L.control.elevation = (options) => new Elevation(options);

View File

@@ -1,90 +0,0 @@
import * as _ from './utils';
export var Options = {
autofitBounds: true,
autohide: false,
autohideMarker: true,
almostover: true,
altitude: true,
closeBtn: true,
collapsed: false,
detached: true,
distance: true,
distanceMarkers: { lazy: true, distance: true, direction: true },
dragging: !L.Browser.mobile,
downloadLink: 'link',
elevationDiv: "#elevation-div",
edgeScale: { bar: true, icon: false, coords: false },
followMarker: true,
imperial: false,
legend: true,
handlers: ["Distance", "Time", "Altitude", "Slope", "Speed", "Acceleration"],
hotline: 'elevation',
marker: 'elevation-line',
markerIcon: L.divIcon({
className: 'elevation-position-marker',
html: '<i class="elevation-position-icon"></i>',
iconSize: [32, 32],
iconAnchor: [16, 16],
}),
position: "topright",
polyline: {
className: 'elevation-polyline',
color: '#000',
opacity: 0.75,
weight: 5,
lineCap: 'round'
},
polylineSegments: {
className: 'elevation-polyline-segments',
color: '#F00',
interactive: false,
},
preferCanvas: false,
reverseCoords: false,
ruler: true,
theme: "lightblue-theme",
summary: 'inline',
slope: false,
speed: false,
time: true,
timeFactor: 3600,
timestamps: false,
showStartEnd: true,
mapTooltip: true,
trkStart: { className: 'start-marker', radius: 6, weight: 2, color: '#fff', fillColor: '#00d800', fillOpacity: 1, interactive: false },
trkEnd: { className: 'end-marker', radius: 6, weight: 2, color: '#fff', fillColor: '#ff0606', fillOpacity: 1, interactive: false },
waypoints: true,
wptIcons: {
'': L.divIcon({
className: 'elevation-waypoint-marker',
html: '<i class="elevation-waypoint-icon default"></i>',
iconSize: [30, 30],
iconAnchor: [8, 30],
}),
},
wptLabels: true,
xAttr: "dist",
xLabel: "km",
yAttr: "z",
yLabel: "m",
zFollow: false,
zooming: !L.Browser.Mobile,
// Quite uncommon and undocumented options
margins: { top: 30, right: 30, bottom: 30, left: 40 },
height: (screen.height * 0.3) || 200,
width: (screen.width * 0.6) || 600,
xTicks: undefined,
yTicks: undefined,
decimalsX: 2,
decimalsY: 0,
forceAxisBounds: false,
interpolation: "curveLinear",
yAxisMax: undefined,
yAxisMin: undefined,
// Prevent CORS issues for relative locations (dynamic import)
srcFolder: ((document.currentScript && document.currentScript.src) || (import.meta && import.meta.url)).split("/").slice(0,-1).join("/") + '/',
};

View File

@@ -1,214 +0,0 @@
/**
* TODO: exget computed styles of theese values from actual "CSS vars"
**/
export const Colors = {
'lightblue': { area: '#3366CC', alpha: 0.45, stroke: '#3366CC' },
'magenta': { area: '#FF005E' },
'yellow': { area: '#FF0' },
'purple': { area: '#732C7B' },
'steelblue': { area: '#4682B4' },
'red': { area: '#F00' },
'lime': { area: '#9CC222', line: '#566B13' },
'gray': { area: '#000000', line: '#3366CC', alpha: 0.00001, stroke: '#000000' }
};
export const LineColors = [
'#0058ca',
'#E36414',
'5f0f40' ,
'#9A031E',
'#fb8b24',
];
const SEC = 1000;
const MIN = SEC * 60;
const HOUR = MIN * 60;
const DAY = HOUR * 24;
export function resolveURL(src, baseUrl) {
console.log(baseUrl, src);
return (new URL(src, (src.startsWith('../') || src.startsWith('./')) ? baseUrl : undefined)).toString()
};
/**
* Convert a time (millis) to a human readable duration string (%Dd %H:%M'%S")
*/
export function formatTime(t) {
let d = Math.floor(t / DAY);
let h = Math.floor((t - d * DAY) / HOUR);
let m = Math.floor((t - d * DAY - h * HOUR) / MIN);
let s = Math.round((t - d * DAY - h * HOUR - m * MIN) / SEC);
if (s === 60) { m++; s = 0; }
if (m === 60) { h++; m = 0; }
if (h === 24) { d++; h = 0; }
return (d ? d + "d " : '') + h.toString().padStart(2, 0) + ':' + m.toString().padStart(2, 0) + "'" + s.toString().padStart(2, 0) + '"';
}
/**
* Convert a time (millis) to human readable date string (dd-mm-yyyy hh:mm:ss)
*/
export function formatDate(format) {
if (!format) {
return (time) => (new Date(time)).toLocaleString().replaceAll('/', '-').replaceAll(',', ' ');
} else if (format == 'time') {
return (time) => (new Date(time)).toLocaleTimeString();
} else if (format == 'date') {
return (time) => (new Date(time)).toLocaleDateString();
}
return (time) => format(time);
}
/**
* Generate download data event.
*/
export function saveFile(dataURI, fileName) {
let a = create('a', '', { href: dataURI, target: '_new', download: fileName || "", style: "display:none;" });
let b = document.body;
b.appendChild(a);
a.click();
b.removeChild(a);
}
/**
* Convert SVG Path into Path2D and then update canvas
*/
export function drawCanvas(ctx, path) {
path.classed('canvas-path', true);
ctx.beginPath();
ctx.moveTo(0, 0);
let p = new Path2D(path.attr('d'));
ctx.strokeStyle = path.__strokeStyle || path.attr('stroke');
ctx.fillStyle = path.__fillStyle || path.attr('fill');
ctx.lineWidth = 1.25;
ctx.globalCompositeOperation = 'source-over';
// stroke opacity
ctx.globalAlpha = path.attr('stroke-opacity') || 0.3;
ctx.stroke(p);
// fill opacity
ctx.globalAlpha = path.attr('fill-opacity') || 0.45;
ctx.fill(p);
ctx.globalAlpha = 1;
ctx.closePath();
}
/**
* Loop and extract GPX Extensions handled by "@tmcw/toGeoJSON" (eg. "coordinateProperties" > "times")
*/
export function coordPropsToMeta(coordProps, name, parser) {
return coordProps && (({ props, point, id, isMulti }) => {
if (props) {
for (const key of coordProps) {
if (key in props) {
point.meta[name] = (parser || parseNumeric).call(this, (isMulti ? props[key][isMulti] : props[key]), id);
break;
}
}
}
});
}
/**
* Extract numeric property (id) from GeoJSON object
*/
export const parseNumeric = (property, id) => parseInt((typeof property === 'object' ? property[id] : property));
/**
* Extract datetime property (id) from GeoJSON object
*/
export const parseDate = (property, id) => new Date(Date.parse((typeof property === 'object' ? property[id] : property)));
/**
* A little bit shorter than L.DomUtil
*/
export const addClass = (n, str) => n && str.split(" ").every(s => s && L.DomUtil.addClass(n, s));
export const removeClass = (n, str) => n && str.split(" ").every(s => s && L.DomUtil.removeClass(n, s));
export const toggleClass = (n, str, cond) => (cond ? addClass : removeClass)(n, str);
export const replaceClass = (n, rem, add) => (rem && removeClass(n, rem)) || (add && addClass(n, add));
export const style = (n, k, v) => (typeof v === "undefined" && L.DomUtil.getStyle(n, k)) || n.style.setProperty(k, v);
export const toggleStyle = (n, k, v, cond) => style(n, k, cond ? v : '');
export const setAttributes = (n, attrs) => { for (let k in attrs) { n.setAttribute(k, attrs[k]); } };
export const toggleEvent = (el, e, fn, cond) => el[cond ? 'on' : 'off'](e, fn);
export const create = (tag, str, attrs, n) => { let elem = L.DomUtil.create(tag, str || ""); if (attrs) setAttributes(elem, attrs); if (n) append(n, elem); return elem; };
export const append = (n, c) => n.appendChild(c);
export const insert = (n, c, pos) => n.insertAdjacentElement(pos, c);
export const select = (str, n) => (n || document).querySelector(str);
export const each = (obj, fn) => { for (let i in obj) fn(obj[i], i); };
export const randomId = () => Math.random().toString(36).substr(2, 9);
/**
* TODO: use generators instead? (ie. "yield")
*/
export const iMax = (iVal, max = -Infinity) => (iVal > max ? iVal : max);
export const iMin = (iVal, min = +Infinity) => (iVal < min ? iVal : min);
export const iAvg = (iVal, avg = 0, idx = 1) => (iVal + avg * (idx - 1)) / idx;
export const iSum = (iVal, sum = 0) => iVal + sum;
/**
* Alias for some leaflet core functions
*/
export const { on, off } = L.DomEvent;
export const { throttle, wrapNum } = L.Util;
export const { hasClass } = L.DomUtil;
/**
* Limit floating point precision
*/
export const round = L.Util.formatNum;
/**
* Limit a number between min / max values
*/
export const clamp = (val, range) => range ? (val < range[0] ? range[0] : val > range[1] ? range[1] : val) : val;
/**
* Limit a delta difference between two values
*/
export const wrapDelta = (curr, prev, deltaMax) => Math.abs(curr - prev) > deltaMax ? prev + deltaMax * Math.sign(curr - prev) : curr;
/**
* A deep copy implementation that takes care of correct prototype chain and cycles, references
*
* @see https://web.dev/structured-clone/#features-and-limitations
*/
export function cloneDeep(o, skipProps = [], cache = []) {
switch (!o || typeof o) {
case 'object':
const hit = cache.filter(c => o === c.original)[0];
if (hit) return hit.copy; // handle circular structures
const copy = Array.isArray(o) ? [] : Object.create(Object.getPrototypeOf(o));
cache.push({ original: o, copy });
Object
.getOwnPropertyNames(o)
.forEach(function (prop) {
const propdesc = Object.getOwnPropertyDescriptor(o, prop);
Object.defineProperty(
copy,
prop,
propdesc.get || propdesc.set
? propdesc // just copy accessor properties
: { // deep copy data properties
writable: propdesc.writable,
configurable: propdesc.configurable,
enumerable: propdesc.enumerable,
value: skipProps.includes(prop) ? propdesc.value : cloneDeep(propdesc.value, skipProps, cache),
}
);
});
return copy;
case 'function':
case 'symbol':
console.warn('cloneDeep: ' + typeof o + 's not fully supported:', o);
case true:
// null, undefined or falsy primitive
default:
return o;
}
}

View File

@@ -1,11 +0,0 @@
.leaflet-grid-label .gridlabel-vert {
margin-left: 8px;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
}
.leaflet-grid-label .gridlabel-vert,
.leaflet-grid-label .gridlabel-horiz {
padding-left:2px;
text-shadow: -2px 0 #FFFFFF, 0 2px #FFFFFF, 2px 0 #FFFFFF, 0 -2px #FFFFFF;
}

View File

@@ -1,233 +0,0 @@
import { LatLngBounds, type LatLngExpression, type LayerOptions, type LeafletEventHandlerFnMap, type PolylineOptions, Map, LayerGroup, Util, Polyline, LatLng, marker, divIcon, latLngBounds } from 'leaflet';
import './leaflet-auto-graticule.css';
export interface AutoGraticuleOptions extends LayerOptions {
redraw: keyof LeafletEventHandlerFnMap,
/** Minimum distance between two lines in pixels */
minDistance: number
}
export default class AutoGraticule extends LayerGroup {
options: AutoGraticuleOptions = {
redraw: 'moveend',
minDistance: 100 // Minimum distance between two lines in pixels
};
lineStyle: PolylineOptions = {
stroke: true,
color: '#333',
opacity: 0.6,
weight: 1,
interactive: false
};
_bounds!: LatLngBounds;
constructor(options?: Partial<AutoGraticuleOptions>) {
super();
Util.setOptions(this, options);
}
onAdd(map: Map) {
this._map = map;
this.redraw();
this._map.on('viewreset ' + this.options.redraw, this.redraw, this);
this.eachLayer(map.addLayer, map);
return this;
}
onRemove(map: Map) {
map.off('viewreset ' + this.options.redraw, this.redraw, this);
this.eachLayer(this.removeLayer, this);
return this;
}
redraw() {
this._bounds = this._map.getBounds().pad(0.5);
this.clearLayers();
this.constructLines();
return this;
}
constructLines() {
const bounds = this._map.getBounds();
const zoom = this._map.getZoom();
// Fix drawing of lines outside of bounds
this._bounds = AutoGraticule.bboxIntersect(bounds, [[-85, -180], [85, 180]]);
// Fix drawing of labels outside of bounds
const getBoundsBkp = this._map.getBounds;
try {
this._map.getBounds = function () {
return AutoGraticule.bboxIntersect(getBoundsBkp.apply(this), [[-85, -180], [85, 180]])
};
// Longitude: Draw vartical lines with a fixed distance between each other
const center = this._map.project(bounds.getCenter(), zoom);
const divisor = AutoGraticule.getGridDivisor(this._map.unproject(center.add([this.options.minDistance / 2, 0]), zoom).lng - this._map.unproject(center.subtract([this.options.minDistance / 2, 0]), zoom).lng, false);
const west = Math.max(bounds.getWest(), -180);
const east = Math.min(bounds.getEast(), 180);
for (let lng = AutoGraticule.fixFloatingPoint(Math.ceil(west / divisor) * divisor); lng <= east; lng += divisor) {
this.addLayer(this.buildXLine(lng));
this.addLayer(this.buildLabel('gridlabel-horiz', AutoGraticule.fixFloatingPoint(lng)));
}
// Latitude: Draw horizontal lines with a variable distance between each other (as in Mercator projection, the distance
// between latitudes gets bigger towards the poles). Calculate a divisor that all latitude line coordinates must be
// dividable by, but then only draw those coordinates that keep the minimum distance to their neighbour lines.
// Draw lines north of the equator separately from lines south of the equator (to keep the grid symmetical in
// relation to the equator).
if (bounds.getNorth() > 0) {
let lat = Math.max(0, bounds.getSouth());
let first = true;
while (lat < bounds.getNorth() && lat < 85) {
const point = this._map.project([lat, bounds.getCenter().lng], zoom);
const point2LatLng = this._map.unproject(point.subtract([0, this.options.minDistance]), zoom);
const divisor = AutoGraticule.getGridDivisor(point2LatLng.lat - lat, true);
lat = AutoGraticule.fixFloatingPoint(first ? Math.ceil(lat / divisor) * divisor : Math.ceil(point2LatLng.lat / divisor) * divisor);
first = false;
this.addLayer(this.buildYLine(lat));
this.addLayer(this.buildLabel('gridlabel-vert', lat));
}
}
if (bounds.getSouth() < 0) {
let lat = Math.min(0, bounds.getNorth());
let first = true;
while (lat > bounds.getSouth() && lat > -85) {
const point = this._map.project([lat, bounds.getCenter().lng], zoom);
const point2LatLng = this._map.unproject(point.add([0, this.options.minDistance]), zoom);
const divisor = AutoGraticule.getGridDivisor(AutoGraticule.fixFloatingPoint(lat - point2LatLng.lat), true);
lat = AutoGraticule.fixFloatingPoint(first ? Math.floor(lat / divisor) * divisor : Math.floor(point2LatLng.lat / divisor) * divisor);
first = false;
this.addLayer(this.buildYLine(lat));
this.addLayer(this.buildLabel('gridlabel-vert', lat));
}
}
} finally {
this._map.getBounds = getBoundsBkp;
}
}
buildXLine(x: number): Polyline {
const bottomLL = new LatLng(this._bounds.getSouth(), x);
const topLL = new LatLng(this._bounds.getNorth(), x);
return new Polyline([bottomLL, topLL], this.lineStyle);
}
buildYLine(y: number): L.Polyline {
const leftLL = new LatLng(y, this._bounds.getWest());
const rightLL = new LatLng(y, this._bounds.getEast());
return new Polyline([leftLL, rightLL], this.lineStyle);
}
buildLabel(axis: 'gridlabel-horiz' | 'gridlabel-vert', val: number) {
const bounds = this._map.getBounds().pad(-0.003);
let latLng: LatLng;
if (axis == 'gridlabel-horiz') {
latLng = new LatLng(bounds.getNorth(), val);
} else {
latLng = new LatLng(val, bounds.getWest());
}
return marker(latLng, {
interactive: false,
icon: divIcon({
iconSize: [0, 0],
className: 'leaflet-grid-label',
html: '<div class="' + axis + '">' + val + '&#8239;°</div>'
})
});
}
/**
* Rounds the given number to a fixed number of decimals in order to avoid floating point inaccuracies
* (for example to make 0.1 + 0.2 = 0.3 instead of 0.30000000000000004).
*/
static fixFloatingPoint(number: number): number {
return AutoGraticule.round(number, 12);
}
/**
* Rounds the given number to the given number of decimals.
*/
static round(number: number, digits: number) {
const fac = Math.pow(10, digits);
return Math.round(number * fac) / fac;
}
/**
* Given the distance between two coordinates, floors this distance to 90, 60, 45, 30 or
* 10, 5, 2, 1, 0.5, 0.2, 0.1, 0.05, 0.02, 0.01, ...
* This will define the distance between two grid lines.
* @param variableDistance This should be true when the distance between the grid lines will be variable, that is for the latitude
* lines (because in Meractor projection the distance between two latitutes gets larger towards the poles, but the distance
* between two longitudes is constant throughout the globe).
* For constant distance lines (longitude), a line should be shown for every coordinate dividable by the result of this
* function. For example, if the result is 45, a line should be shown for longitudes -180, -135, -90, -45, 0, 45, 90, 135, 180.
* For variable distance lines (latitude), a line should be shown for coordinates dividable by a result of this function, but
* not for every single coordinate but only those that have a minimum distance towards their neighbour coordinate line. For
* variable distance lines, the maximum number returned by this function is 5, meaning at low zoom levels, all latitude lines
* are dividable by 5 (but not every latitude dividable by 5 will get a line).
*/
static getGridDivisor(number: number, variableDistance: boolean) {
if (number <= 0 || !isFinite(number))
throw new Error("Invalid number " + number);
else {
if (variableDistance && number >= 5)
return 5;
if (number <= 10) {
let fac = 1;
while (number > 1) { fac *= 10; number /= 10; }
while (number <= 0.1) { fac /= 10; number *= 10; }
// Dist is now some number between 0.1 and 1, so we can round it conveniently and then multiply it again by fac to get back to the original dist
if (number == 0.1)
return AutoGraticule.fixFloatingPoint(0.1 * fac);
else if (number <= 0.2)
return AutoGraticule.fixFloatingPoint(0.2 * fac);
else if (number <= 0.5)
return AutoGraticule.fixFloatingPoint(0.5 * fac);
else
return fac;
} else if (number <= 30)
return 30;
else if (number <= 45)
return 45;
else if (number <= 60)
return 60;
else
return 90;
}
}
// Backwards compatibility
static niceRound = AutoGraticule.getGridDivisor;
static bboxIntersect(bbox1: LatLngBounds | LatLngExpression[], bbox2: LatLngBounds | LatLngExpression[]) {
const bounds1 = bbox1 instanceof LatLngBounds ? bbox1 : latLngBounds(bbox1);
const bounds2 = bbox2 instanceof LatLngBounds ? bbox2 : latLngBounds(bbox2);
return latLngBounds([
[Math.max(bounds1.getSouth(), bounds2.getSouth()), Math.max(bounds1.getWest(), bounds2.getWest())],
[Math.min(bounds1.getNorth(), bounds2.getNorth()), Math.min(bounds1.getEast(), bounds2.getEast())]
]);
}
}

View File

@@ -1,280 +0,0 @@
import queue from "./queue";
var cacheBusterDate = +new Date();
// leaflet-image
export default function leafletImage(map, callback) {
var dimensions = map.getSize(),
layerQueue = new queue(1);
var canvas = document.createElement('canvas');
canvas.width = dimensions.x;
canvas.height = dimensions.y;
var ctx = canvas.getContext('2d');
// dummy canvas image when loadTile get 404 error
// and layer don't have errorTileUrl
var dummycanvas = document.createElement('canvas');
dummycanvas.width = 1;
dummycanvas.height = 1;
var dummyctx = dummycanvas.getContext('2d');
dummyctx.fillStyle = 'rgba(0,0,0,0)';
dummyctx.fillRect(0, 0, 1, 1);
// layers are drawn in the same order as they are composed in the DOM:
// tiles, paths, and then markers
map.eachLayer(drawTileLayer);
map.eachLayer(drawEsriDynamicLayer);
if (map._pathRoot) {
layerQueue.defer(handlePathRoot, map._pathRoot);
} else if (map._panes) {
var firstCanvas = map._panes.overlayPane.getElementsByTagName('canvas').item(0);
if (firstCanvas) {
layerQueue.defer(handlePathRoot, firstCanvas);
}
}
map.eachLayer(drawMarkerLayer);
layerQueue.awaitAll(layersDone);
function drawTileLayer(l) {
if (l instanceof L.TileLayer) layerQueue.defer(handleTileLayer, l);
else if (l._heat) layerQueue.defer(handlePathRoot, l._canvas);
}
function drawMarkerLayer(l) {
if (l instanceof L.Marker && l.options.icon instanceof L.Icon) {
layerQueue.defer(handleMarkerLayer, l);
}
}
function drawEsriDynamicLayer(l) {
if (!L.esri) return;
if (l instanceof L.esri.DynamicMapLayer) {
layerQueue.defer(handleEsriDymamicLayer, l);
}
}
function done() {
callback(null, canvas);
}
function layersDone(err, layers) {
if (err) throw err;
layers.forEach(function (layer) {
if (layer && layer.canvas) {
ctx.drawImage(layer.canvas, 0, 0);
}
});
done();
}
function handleTileLayer(layer, callback) {
// `L.TileLayer.Canvas` was removed in leaflet 1.0
var isCanvasLayer = (L.TileLayer.Canvas && layer instanceof L.TileLayer.Canvas),
canvas = document.createElement('canvas');
canvas.width = dimensions.x;
canvas.height = dimensions.y;
var ctx = canvas.getContext('2d'),
bounds = map.getPixelBounds(),
zoom = map.getZoom(),
tileSize = layer.options.tileSize;
if (zoom > layer.options.maxZoom ||
zoom < layer.options.minZoom
) {
return callback();
}
var tileBounds = L.bounds(
bounds.min.divideBy(tileSize)._floor(),
bounds.max.divideBy(tileSize)._floor()),
tiles = [],
j, i,
tileQueue = new queue(1);
for (j = tileBounds.min.y; j <= tileBounds.max.y; j++) {
for (i = tileBounds.min.x; i <= tileBounds.max.x; i++) {
tiles.push(new L.Point(i, j));
}
}
tiles.forEach(function (tilePoint) {
var originalTilePoint = tilePoint.clone();
if (layer._adjustTilePoint) {
layer._adjustTilePoint(tilePoint);
}
var tilePos = originalTilePoint
.scaleBy(new L.Point(tileSize, tileSize))
.subtract(bounds.min);
if (tilePoint.y >= 0) {
if (isCanvasLayer) {
var tile = layer._tiles[tilePoint.x + ':' + tilePoint.y];
tileQueue.defer(canvasTile, tile, tilePos, tileSize);
} else {
var url = addCacheString(layer.getTileUrl(tilePoint));
tileQueue.defer(loadTile, url, tilePos, tileSize);
}
}
});
tileQueue.awaitAll(tileQueueFinish);
function canvasTile(tile, tilePos, tileSize, callback) {
callback(null, {
img: tile,
pos: tilePos,
size: tileSize
});
}
function loadTile(url, tilePos, tileSize, callback) {
var im = new Image();
im.crossOrigin = '';
im.onload = function () {
callback(null, {
img: this,
pos: tilePos,
size: tileSize
});
};
im.onerror = function (e) {
// use canvas instead of errorTileUrl if errorTileUrl get 404
if (layer.options.errorTileUrl != '' && e.target.errorCheck === undefined) {
e.target.errorCheck = true;
e.target.src = layer.options.errorTileUrl;
} else {
callback(null, {
img: dummycanvas,
pos: tilePos,
size: tileSize
});
}
};
im.src = url;
}
function tileQueueFinish(err, data) {
data.forEach(drawTile);
callback(null, { canvas: canvas });
}
function drawTile(d) {
ctx.drawImage(d.img, Math.floor(d.pos.x), Math.floor(d.pos.y),
d.size, d.size);
}
}
function handlePathRoot(root, callback) {
var bounds = map.getPixelBounds(),
origin = map.getPixelOrigin(),
canvas = document.createElement('canvas');
canvas.width = dimensions.x;
canvas.height = dimensions.y;
var ctx = canvas.getContext('2d');
var pos = L.DomUtil.getPosition(root).subtract(bounds.min).add(origin);
try {
ctx.drawImage(root, pos.x, pos.y, canvas.width - (pos.x * 2), canvas.height - (pos.y * 2));
callback(null, {
canvas: canvas
});
} catch (e) {
console.error('Element could not be drawn on canvas', root); // eslint-disable-line no-console
}
}
function handleMarkerLayer(marker, callback) {
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d'),
pixelBounds = map.getPixelBounds(),
minPoint = new L.Point(pixelBounds.min.x, pixelBounds.min.y),
pixelPoint = map.project(marker.getLatLng()),
url = "/vendor/leaflet-image/marker.png",
im = new Image(),
options = marker.options.icon.options,
size = options.iconSize,
pos = pixelPoint.subtract(minPoint),
anchor = L.point(options.iconAnchor || size && { x: size[0], y: size[1] });
if (size instanceof L.Point) size = [size.x, size.y];
var x = Math.round(pos.x - size[0] + anchor.x),
y = Math.round(pos.y - anchor.y);
canvas.width = dimensions.x;
canvas.height = dimensions.y;
im.crossOrigin = '';
im.onload = function () {
if (marker._icon.classList.contains("leaflet-grid-label")) {
const label = marker._icon.children[0].textContent;
ctx.font = '600 10px "IBMPlexSans"';
ctx.fillStyle = "#000";
ctx.fillText(label, x + 4, y + 12);
} else {
const waypointName = marker.options.meta?.waypointName;
const icon = getComputedStyle(marker._icon.children[0], ':before').getPropertyValue('content').substring(1, 2) ?? "\uf111";
ctx.drawImage(this, x, y, size[0], size[1]);
ctx.font = '600 14px "Font Awesome 6 Free"';
ctx.fillStyle = "#ffffff";
const iconWidth = ctx.measureText(icon).width
ctx.fillText(icon, x + size[0] / 2 - iconWidth / 2, y + 24);
if (waypointName) {
ctx.fillStyle = "rgba(49, 49, 49, 0.5)"
ctx.font = '600 12px "IBMPlexSans"';
const textWidth = ctx.measureText(waypointName).width
ctx.roundRect(size[0] / 2 + x - (textWidth + 16) / 2, y - 18, textWidth + 16, 20, 5)
ctx.fill();
ctx.fillStyle = "#ffffff";
ctx.fillText(waypointName, size[0] / 2 + x - (textWidth + 16) / 2 + 8, y - 4);
}
}
callback(null, {
canvas: canvas
});
};
im.src = url;
}
function handleEsriDymamicLayer(dynamicLayer, callback) {
var canvas = document.createElement('canvas');
canvas.width = dimensions.x;
canvas.height = dimensions.y;
var ctx = canvas.getContext('2d');
var im = new Image();
im.crossOrigin = '';
im.src = addCacheString(dynamicLayer._currentImage._image.src);
im.onload = function () {
ctx.drawImage(im, 0, 0);
callback(null, {
canvas: canvas
});
};
}
function addCacheString(url) {
// If it's a data URL we don't want to touch this.
if (isDataURL(url)) {
return url;
}
return url + ((url.match(/\?/)) ? '&' : '?') + 'cache=' + cacheBusterDate;
}
function isDataURL(url) {
var dataURLRegex = /^\s*data:([a-z]+\/[a-z]+(;[a-z\-]+\=[a-z\-]+)?)?(;base64)?,[a-z0-9\!\$\&\'\,\(\)\*\+\,\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i;
return !!url.match(dataURLRegex);
}
};

View File

@@ -1,120 +0,0 @@
var noabort = {};
const slice = [].slice;
function Queue(size) {
this._size = size;
this._call =
this._error = null;
this._tasks = [];
this._data = [];
this._waiting =
this._active =
this._ended =
this._start = 0; // inside a synchronous task callback?
}
Queue.prototype = queue.prototype = {
constructor: Queue,
defer: function(callback) {
if (typeof callback !== "function") throw new Error("invalid callback");
if (this._call) throw new Error("defer after await");
if (this._error != null) return this;
var t = slice.call(arguments, 1);
t.push(callback);
++this._waiting, this._tasks.push(t);
poke(this);
return this;
},
abort: function() {
if (this._error == null) abort(this, new Error("abort"));
return this;
},
await: function(callback) {
if (typeof callback !== "function") throw new Error("invalid callback");
if (this._call) throw new Error("multiple await");
this._call = function(error, results) { callback.apply(null, [error].concat(results)); };
maybeNotify(this);
return this;
},
awaitAll: function(callback) {
if (typeof callback !== "function") throw new Error("invalid callback");
if (this._call) throw new Error("multiple await");
this._call = callback;
maybeNotify(this);
return this;
}
};
function poke(q) {
if (!q._start) {
try { start(q); } // let the current task complete
catch (e) {
if (q._tasks[q._ended + q._active - 1]) abort(q, e); // task errored synchronously
else if (!q._data) throw e; // await callback errored synchronously
}
}
}
function start(q) {
while (q._start = q._waiting && q._active < q._size) {
var i = q._ended + q._active,
t = q._tasks[i],
j = t.length - 1,
c = t[j];
t[j] = end(q, i);
--q._waiting, ++q._active;
t = c.apply(null, t);
if (!q._tasks[i]) continue; // task finished synchronously
q._tasks[i] = t || noabort;
}
}
function end(q, i) {
return function(e, r) {
if (!q._tasks[i]) return; // ignore multiple callbacks
--q._active, ++q._ended;
q._tasks[i] = null;
if (q._error != null) return; // ignore secondary errors
if (e != null) {
abort(q, e);
} else {
q._data[i] = r;
if (q._waiting) poke(q);
else maybeNotify(q);
}
};
}
function abort(q, e) {
var i = q._tasks.length, t;
q._error = e; // ignore active callbacks
q._data = undefined; // allow gc
q._waiting = NaN; // prevent starting
while (--i >= 0) {
if (t = q._tasks[i]) {
q._tasks[i] = null;
if (t.abort) {
try { t.abort(); }
catch (e) { /* ignore */ }
}
}
}
q._active = NaN; // allow notification
maybeNotify(q);
}
function maybeNotify(q) {
if (!q._active && q._call) {
var d = q._data;
q._data = undefined; // allow gc
q._call(q._error, d);
}
}
export default function queue(concurrency) {
if (concurrency == null) concurrency = Infinity;
else if (!((concurrency = +concurrency) >= 1)) throw new Error("invalid concurrency");
return new Queue(concurrency);
}

View File

@@ -0,0 +1,42 @@
import * as M from "maplibre-gl";
import { type ControlPosition, type IControl } from "maplibre-gl";
export class FullscreenControl implements IControl {
private buttonContainer?: HTMLDivElement;
private fullscreenButton?: HTMLButtonElement;
private iconSpan?: HTMLSpanElement;
private callback: (e: MouseEvent) => void;
constructor(callback: (e: MouseEvent) => void) {
this.callback = callback;
}
onAdd(map: M.Map): HTMLElement {
this.buttonContainer = document.createElement("div");
this.buttonContainer.classList.add(
"maplibregl-ctrl",
"maplibregl-ctrl-group"
);
this.fullscreenButton = document.createElement("button");
this.buttonContainer.appendChild(this.fullscreenButton);
this.iconSpan = document.createElement("i");
this.iconSpan.classList.add("fa", "fa-maximize", "text-black");
this.fullscreenButton.appendChild(this.iconSpan);
this.fullscreenButton.addEventListener("click", this.callback);
return this.buttonContainer;
}
onRemove(): void {
// remove button
if (this.buttonContainer?.parentNode) {
this.buttonContainer.parentNode.removeChild(this.buttonContainer);
}
this.buttonContainer = undefined;
this.fullscreenButton = undefined;
}
}