leaflet
Version:
JavaScript library for mobile-friendly interactive maps
125 lines (107 loc) • 4.28 kB
JavaScript
/*
* @namespace Util
*
* Various utility functions, used by Leaflet internally.
*/
// @property lastId: Number
// Last unique ID used by [`stamp()`](#util-stamp)
export let lastId = 0;
// @function stamp(obj: Object): Number
// Returns the unique ID of an object, assigning it one if it doesn't have it.
export function stamp(obj) {
if (!('_leaflet_id' in obj)) {
obj['_leaflet_id'] = ++lastId;
}
return obj._leaflet_id;
}
// @function throttle(fn: Function, time: Number, context: Object): Function
// Returns a function which executes function `fn` with the given scope `context`
// (so that the `this` keyword refers to `context` inside `fn`'s code). The function
// `fn` will be called no more than one time per given amount of `time`. The arguments
// received by the bound function will be any arguments passed when binding the
// function, followed by any arguments passed when invoking the bound function.
export function throttle(fn, time, context) {
let lock, queuedArgs;
function later() {
// reset lock and call if queued
lock = false;
if (queuedArgs) {
wrapperFn.apply(context, queuedArgs);
queuedArgs = false;
}
}
function wrapperFn(...args) {
if (lock) {
// called too soon, queue to call later
queuedArgs = args;
} else {
// call and lock until later
fn.apply(context, args);
setTimeout(later, time);
lock = true;
}
}
return wrapperFn;
}
// @function wrapNum(num: Number, range: Number[], includeMax?: Boolean): Number
// Returns the number `num` modulo `range` in such a way so it lies within
// `range[0]` and `range[1]`. The returned value will be always smaller than
// `range[1]` unless `includeMax` is set to `true`.
export function wrapNum(x, range, includeMax) {
const max = range[1],
min = range[0],
d = max - min;
return x === max && includeMax ? x : ((x - min) % d + d) % d + min;
}
// @function falseFn(): Function
// Returns a function which always returns `false`.
export function falseFn() { return false; }
// @function formatNum(num: Number, precision?: Number|false): Number
// Returns the number `num` rounded with specified `precision`.
// The default `precision` value is 6 decimal places.
// `false` can be passed to skip any processing (can be useful to avoid round-off errors).
export function formatNum(num, precision) {
if (precision === false) { return num; }
const pow = 10 ** (precision === undefined ? 6 : precision);
return Math.round(num * pow) / pow;
}
// @function splitWords(str: String): String[]
// Trims and splits the string on whitespace and returns the array of parts.
export function splitWords(str) {
return str.trim().split(/\s+/);
}
// @function setOptions(obj: Object, options: Object): Object
// Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`.
export function setOptions(obj, options) {
if (!Object.hasOwn(obj, 'options')) {
obj.options = obj.options ? Object.create(obj.options) : {};
}
for (const i in options) {
if (Object.hasOwn(options, i)) {
obj.options[i] = options[i];
}
}
return obj.options;
}
const templateRe = /\{ *([\w_ -]+) *\}/g;
// @function template(str: String, data: Object): String
// Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'`
// and a data object like `{a: 'foo', b: 'bar'}`, returns evaluated string
// `('Hello foo, bar')`. You can also specify functions instead of strings for
// data values — they will be evaluated passing `data` as an argument.
export function template(str, data) {
return str.replace(templateRe, (str, key) => {
let value = data[key];
if (value === undefined) {
throw new Error(`No value provided for variable ${str}`);
} else if (typeof value === 'function') {
value = value(data);
}
return value;
});
}
// @property emptyImageUrl: String
// Data URI string containing a base64-encoded empty GIF image.
// Used as a hack to free memory from unused images on WebKit-powered
// mobile devices (by setting image `src` to this string).
export const emptyImageUrl = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';