adds list editor
This commit is contained in:
330
web/src/lib/vendor/leaflet-elevation/libs/leaflet-gpxgroup.js
vendored
Normal file
330
web/src/lib/vendor/leaflet-elevation/libs/leaflet-gpxgroup.js
vendored
Normal file
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* 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.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._layers.addTo(map);
|
||||
this._markers.addTo(map);
|
||||
this._hotline.addTo(map);
|
||||
|
||||
this._map = map;
|
||||
|
||||
this.on('selection_changed', this._onSelectionChanged, this);
|
||||
this.addTracks();
|
||||
},
|
||||
|
||||
addTracks() {
|
||||
this._tracks.forEach(this._addTrack, this);
|
||||
|
||||
},
|
||||
_addTrack: function (track) {
|
||||
if (track instanceof Object) {
|
||||
this._loadGeoJSON(track);
|
||||
} else {
|
||||
this._elevation._parseFromString(track)
|
||||
.then(geojson => this._loadGeoJSON(geojson, track.split('/').pop().split('#')[0].split('?')[0]))
|
||||
}
|
||||
},
|
||||
|
||||
clear: function () {
|
||||
this._elevation.clear()
|
||||
this._clearLayers();
|
||||
this._clearLayers(this._markers);
|
||||
this._clearLayers(this._hotline)
|
||||
this._count = 0;
|
||||
this._loadedCount = 0;
|
||||
this._tracks = []
|
||||
},
|
||||
|
||||
_clearLayers(l) {
|
||||
l = l || this._layers;
|
||||
if (l && l.eachLayer) {
|
||||
l.eachLayer(f => f.remove())
|
||||
l.clearLayers();
|
||||
}
|
||||
},
|
||||
|
||||
_loadGeoJSON: function (geojson, fallbackName) {
|
||||
if (geojson) {
|
||||
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._uniqueColors(this._tracks.length)[this._count++],
|
||||
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,
|
||||
index: this._count - 1,
|
||||
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;
|
||||
|
||||
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="px-2 py-2 text-white bg-gray-500 rounded-lg fa fa-bullseye"></i>',
|
||||
className: 'start-icon'
|
||||
});
|
||||
const endIcon = L.divIcon({
|
||||
html: '<i class="px-2 py-2 text-white bg-gray-500 rounded-lg fa fa-flag-checkered"></i>',
|
||||
className: 'end-icon'
|
||||
});
|
||||
const latlngs = polyline.getLatLngs();
|
||||
|
||||
|
||||
if (this._loadedCount == 0) {
|
||||
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: function (e) {
|
||||
var elevation = this._elevation;
|
||||
var eleDiv = elevation.getContainer();
|
||||
var route = this.getSelection();
|
||||
var hotline = this._hotline;
|
||||
|
||||
elevation.clear();
|
||||
|
||||
if (route && route.isSelected()) {
|
||||
if (!eleDiv) {
|
||||
elevation.addTo(this._map);
|
||||
}
|
||||
route.getLayers().forEach(function (layer) {
|
||||
if (layer instanceof L.Polyline) {
|
||||
elevation.addData(layer, false);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (eleDiv) {
|
||||
elevation.remove();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_uniqueColors: function (count) {
|
||||
return count === 1 ? ['#0058ca'] : new Array(count).fill(null).map((_, i) => this._hsvToHex(i * (1 / count), 1, 0.7));
|
||||
},
|
||||
|
||||
_hsvToHex: function (h, s, v) {
|
||||
var i = Math.floor(h * 6);
|
||||
var f = h * 6 - i;
|
||||
var p = v * (1 - s);
|
||||
var q = v * (1 - f * s);
|
||||
var t = v * (1 - (1 - f) * s);
|
||||
var rgb = { 0: [v, t, p], 1: [q, v, p], 2: [p, v, t], 3: [p, q, v], 4: [t, p, v], 5: [v, p, q] }[i % 6];
|
||||
return rgb.map(d => d * 255).reduce((hex, byte) => hex + ((byte >> 4) & 0x0F).toString(16) + (byte & 0x0F).toString(16), "#");
|
||||
},
|
||||
|
||||
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);
|
||||
@@ -446,7 +446,7 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
|
||||
}) : Promise.resolve();
|
||||
},
|
||||
|
||||
_initHotLine(layer) {
|
||||
_initHotLine(layer, target = this._hotline) {
|
||||
let prop = typeof this.options.hotline == 'string' ? this.options.hotline : 'elevation';
|
||||
return this.options.hotline ? this.import(/* @vite-ignore */this.__LHOTLINE)
|
||||
.then(() => {
|
||||
@@ -464,7 +464,9 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
|
||||
weight: 5,
|
||||
outlineColor: '#000000',
|
||||
outlineWidth: 1
|
||||
}).addTo(this._hotline);
|
||||
}).addTo(target);
|
||||
console.log(this._data);
|
||||
|
||||
let alpha = trkseg.options.style && trkseg.options.style.opacity || 1;
|
||||
trkseg.on('add remove', ({ type }) => {
|
||||
trkseg.setStyle({ opacity: (type == 'add' ? 0 : alpha) });
|
||||
@@ -536,16 +538,20 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
|
||||
|
||||
L.Canvas.include({
|
||||
_fillStroke(ctx, layer) {
|
||||
if (control._layers.hasLayer(layer)) {
|
||||
let options = layer.options;
|
||||
|
||||
let options = layer.options;
|
||||
|
||||
options.color = color.line || color.area || theme;
|
||||
if (control._layers.hasLayer(layer) || options.isGroupLayer) {
|
||||
|
||||
|
||||
if (!options.isGroupLayer) {
|
||||
options.color = color.line || color.area || theme;
|
||||
}
|
||||
options.stroke = !!options.color;
|
||||
|
||||
oldProto.call(this, ctx, layer);
|
||||
|
||||
if (options.stroke && options.weight !== 0) {
|
||||
if (!options.highlighted && options.stroke && options.weight !== 0) {
|
||||
let oldVal = ctx.globalCompositeOperation || 'source-over';
|
||||
ctx.globalCompositeOperation = 'destination-over'
|
||||
ctx.strokeStyle = color.outline || '#FFF';
|
||||
|
||||
101
web/src/lib/vendor/leaflet-elevation/src/utils.js
vendored
101
web/src/lib/vendor/leaflet-elevation/src/utils.js
vendored
@@ -3,19 +3,28 @@
|
||||
**/
|
||||
export const Colors = {
|
||||
'lightblue': { area: '#3366CC', alpha: 0.45, stroke: '#3366CC' },
|
||||
'magenta' : { area: '#FF005E' },
|
||||
'yellow' : { area: '#FF0' },
|
||||
'purple' : { area: '#732C7B' },
|
||||
'magenta': { area: '#FF005E' },
|
||||
'yellow': { area: '#FF0' },
|
||||
'purple': { area: '#732C7B' },
|
||||
'steelblue': { area: '#4682B4' },
|
||||
'red' : { area: '#F00' },
|
||||
'lime' : { area: '#9CC222', line: '#566B13' },
|
||||
'red': { area: '#F00' },
|
||||
'lime': { area: '#9CC222', line: '#566B13' },
|
||||
'gray': { area: '#000000', line: '#3366CC', alpha: 0.00001, stroke: '#000000' }
|
||||
};
|
||||
|
||||
const SEC = 1000;
|
||||
const MIN = SEC * 60;
|
||||
export const LineColors = [
|
||||
'#0058ca',
|
||||
'#E36414',
|
||||
'5f0f40' ,
|
||||
'#9A031E',
|
||||
'#fb8b24',
|
||||
];
|
||||
|
||||
|
||||
const SEC = 1000;
|
||||
const MIN = SEC * 60;
|
||||
const HOUR = MIN * 60;
|
||||
const DAY = HOUR * 24;
|
||||
const DAY = HOUR * 24;
|
||||
|
||||
export function resolveURL(src, baseUrl) {
|
||||
console.log(baseUrl, src);
|
||||
@@ -27,19 +36,19 @@ export function resolveURL(src, baseUrl) {
|
||||
*/
|
||||
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; }
|
||||
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) {
|
||||
export function formatDate(format) {
|
||||
if (!format) {
|
||||
return (time) => (new Date(time)).toLocaleString().replaceAll('/', '-').replaceAll(',', ' ');
|
||||
} else if (format == 'time') {
|
||||
@@ -53,7 +62,7 @@ export function formatTime(t) {
|
||||
/**
|
||||
* Generate download data event.
|
||||
*/
|
||||
export function saveFile(dataURI, fileName) {
|
||||
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);
|
||||
@@ -65,7 +74,7 @@ export function formatTime(t) {
|
||||
/**
|
||||
* Convert SVG Path into Path2D and then update canvas
|
||||
*/
|
||||
export function drawCanvas(ctx, path) {
|
||||
export function drawCanvas(ctx, path) {
|
||||
path.classed('canvas-path', true);
|
||||
|
||||
ctx.beginPath();
|
||||
@@ -73,8 +82,8 @@ export function formatTime(t) {
|
||||
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.fillStyle = path.__fillStyle || path.attr('fill');
|
||||
ctx.lineWidth = 1.25;
|
||||
ctx.globalCompositeOperation = 'source-over';
|
||||
|
||||
// stroke opacity
|
||||
@@ -82,7 +91,7 @@ export function formatTime(t) {
|
||||
ctx.stroke(p);
|
||||
|
||||
// fill opacity
|
||||
ctx.globalAlpha = path.attr('fill-opacity') || 0.45;
|
||||
ctx.globalAlpha = path.attr('fill-opacity') || 0.45;
|
||||
ctx.fill(p);
|
||||
|
||||
ctx.globalAlpha = 1;
|
||||
@@ -94,7 +103,7 @@ export function formatTime(t) {
|
||||
* Loop and extract GPX Extensions handled by "@tmcw/toGeoJSON" (eg. "coordinateProperties" > "times")
|
||||
*/
|
||||
export function coordPropsToMeta(coordProps, name, parser) {
|
||||
return coordProps && (({props, point, id, isMulti }) => {
|
||||
return coordProps && (({ props, point, id, isMulti }) => {
|
||||
if (props) {
|
||||
for (const key of coordProps) {
|
||||
if (key in props) {
|
||||
@@ -109,7 +118,7 @@ export function coordPropsToMeta(coordProps, name, parser) {
|
||||
/**
|
||||
* Extract numeric property (id) from GeoJSON object
|
||||
*/
|
||||
export const parseNumeric = (property, id) => parseInt((typeof property === 'object' ? property[id] : property));
|
||||
export const parseNumeric = (property, id) => parseInt((typeof property === 'object' ? property[id] : property));
|
||||
|
||||
/**
|
||||
* Extract datetime property (id) from GeoJSON object
|
||||
@@ -119,25 +128,25 @@ export const parseDate = (property, id) => new Date(Date.parse((typeof 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);
|
||||
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 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;
|
||||
@@ -145,19 +154,19 @@ export const iSum = (iVal, sum = 0) => iVal + sum;
|
||||
/**
|
||||
* Alias for some leaflet core functions
|
||||
*/
|
||||
export const { on, off } = L.DomEvent;
|
||||
export const { on, off } = L.DomEvent;
|
||||
export const { throttle, wrapNum } = L.Util;
|
||||
export const { hasClass } = L.DomUtil;
|
||||
export const { hasClass } = L.DomUtil;
|
||||
|
||||
/**
|
||||
* Limit floating point precision
|
||||
*/
|
||||
export const round = L.Util.formatNum;
|
||||
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;
|
||||
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
|
||||
@@ -170,7 +179,7 @@ export const wrapDelta = (curr, prev, deltaMax) => Math.abs(curr - prev) > delta
|
||||
* @see https://web.dev/structured-clone/#features-and-limitations
|
||||
*/
|
||||
export function cloneDeep(o, skipProps = [], cache = []) {
|
||||
switch(!o || typeof o) {
|
||||
switch (!o || typeof o) {
|
||||
case 'object':
|
||||
const hit = cache.filter(c => o === c.original)[0];
|
||||
if (hit) return hit.copy; // handle circular structures
|
||||
@@ -186,10 +195,10 @@ export function cloneDeep(o, skipProps = [], cache = []) {
|
||||
propdesc.get || propdesc.set
|
||||
? propdesc // just copy accessor properties
|
||||
: { // deep copy data properties
|
||||
writable: propdesc.writable,
|
||||
writable: propdesc.writable,
|
||||
configurable: propdesc.configurable,
|
||||
enumerable: propdesc.enumerable,
|
||||
value: skipProps.includes(prop) ? propdesc.value : cloneDeep(propdesc.value, skipProps, cache),
|
||||
enumerable: propdesc.enumerable,
|
||||
value: skipProps.includes(prop) ? propdesc.value : cloneDeep(propdesc.value, skipProps, cache),
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -198,7 +207,7 @@ export function cloneDeep(o, skipProps = [], cache = []) {
|
||||
case 'symbol':
|
||||
console.warn('cloneDeep: ' + typeof o + 's not fully supported:', o);
|
||||
case true:
|
||||
// null, undefined or falsy primitive
|
||||
// null, undefined or falsy primitive
|
||||
default:
|
||||
return o;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user