`).join('');
}
function renderPopup(features) {
return `
${renderFeatures(features)}
`;
}
var randomColor$1 = {exports: {}};
(function (module, exports) {
(function(root, factory) {
// Support CommonJS
{
var randomColor = factory();
// Support NodeJS & Component, which allow module.exports to be a function
if (module && module.exports) {
exports = module.exports = randomColor;
}
// Support CommonJS 1.1.1 spec
exports.randomColor = randomColor;
// Support AMD
}
}(commonjsGlobal, function() {
// Seed to get repeatable colors
var seed = null;
// Shared color dictionary
var colorDictionary = {};
// Populate the color dictionary
loadColorBounds();
// check if a range is taken
var colorRanges = [];
var randomColor = function (options) {
options = options || {};
// Check if there is a seed and ensure it's an
// integer. Otherwise, reset the seed value.
if (options.seed !== undefined && options.seed !== null && options.seed === parseInt(options.seed, 10)) {
seed = options.seed;
// A string was passed as a seed
} else if (typeof options.seed === 'string') {
seed = stringToInteger(options.seed);
// Something was passed as a seed but it wasn't an integer or string
} else if (options.seed !== undefined && options.seed !== null) {
throw new TypeError('The seed value must be an integer or string');
// No seed, reset the value outside.
} else {
seed = null;
}
var H,S,B;
// Check if we need to generate multiple colors
if (options.count !== null && options.count !== undefined) {
var totalColors = options.count,
colors = [];
// Value false at index i means the range i is not taken yet.
for (var i = 0; i < options.count; i++) {
colorRanges.push(false);
}
options.count = null;
while (totalColors > colors.length) {
var color = randomColor(options);
if (seed !== null) {
options.seed = seed;
}
colors.push(color);
}
options.count = totalColors;
return colors;
}
// First we pick a hue (H)
H = pickHue(options);
// Then use H to determine saturation (S)
S = pickSaturation(H, options);
// Then use S and H to determine brightness (B).
B = pickBrightness(H, S, options);
// Then we return the HSB color in the desired format
return setFormat([H,S,B], options);
};
function pickHue(options) {
if (colorRanges.length > 0) {
var hueRange = getRealHueRange(options.hue);
var hue = randomWithin(hueRange);
//Each of colorRanges.length ranges has a length equal approximatelly one step
var step = (hueRange[1] - hueRange[0]) / colorRanges.length;
var j = parseInt((hue - hueRange[0]) / step);
//Check if the range j is taken
if (colorRanges[j] === true) {
j = (j + 2) % colorRanges.length;
}
else {
colorRanges[j] = true;
}
var min = (hueRange[0] + j * step) % 359,
max = (hueRange[0] + (j + 1) * step) % 359;
hueRange = [min, max];
hue = randomWithin(hueRange);
if (hue < 0) {hue = 360 + hue;}
return hue
}
else {
var hueRange = getHueRange(options.hue);
hue = randomWithin(hueRange);
// Instead of storing red as two seperate ranges,
// we group them, using negative numbers
if (hue < 0) {
hue = 360 + hue;
}
return hue;
}
}
function pickSaturation (hue, options) {
if (options.hue === 'monochrome') {
return 0;
}
if (options.luminosity === 'random') {
return randomWithin([0,100]);
}
var saturationRange = getSaturationRange(hue);
var sMin = saturationRange[0],
sMax = saturationRange[1];
switch (options.luminosity) {
case 'bright':
sMin = 55;
break;
case 'dark':
sMin = sMax - 10;
break;
case 'light':
sMax = 55;
break;
}
return randomWithin([sMin, sMax]);
}
function pickBrightness (H, S, options) {
var bMin = getMinimumBrightness(H, S),
bMax = 100;
switch (options.luminosity) {
case 'dark':
bMax = bMin + 20;
break;
case 'light':
bMin = (bMax + bMin)/2;
break;
case 'random':
bMin = 0;
bMax = 100;
break;
}
return randomWithin([bMin, bMax]);
}
function setFormat (hsv, options) {
switch (options.format) {
case 'hsvArray':
return hsv;
case 'hslArray':
return HSVtoHSL(hsv);
case 'hsl':
var hsl = HSVtoHSL(hsv);
return 'hsl('+hsl[0]+', '+hsl[1]+'%, '+hsl[2]+'%)';
case 'hsla':
var hslColor = HSVtoHSL(hsv);
var alpha = options.alpha || Math.random();
return 'hsla('+hslColor[0]+', '+hslColor[1]+'%, '+hslColor[2]+'%, ' + alpha + ')';
case 'rgbArray':
return HSVtoRGB(hsv);
case 'rgb':
var rgb = HSVtoRGB(hsv);
return 'rgb(' + rgb.join(', ') + ')';
case 'rgba':
var rgbColor = HSVtoRGB(hsv);
var alpha = options.alpha || Math.random();
return 'rgba(' + rgbColor.join(', ') + ', ' + alpha + ')';
default:
return HSVtoHex(hsv);
}
}
function getMinimumBrightness(H, S) {
var lowerBounds = getColorInfo(H).lowerBounds;
for (var i = 0; i < lowerBounds.length - 1; i++) {
var s1 = lowerBounds[i][0],
v1 = lowerBounds[i][1];
var s2 = lowerBounds[i+1][0],
v2 = lowerBounds[i+1][1];
if (S >= s1 && S <= s2) {
var m = (v2 - v1)/(s2 - s1),
b = v1 - m*s1;
return m*S + b;
}
}
return 0;
}
function getHueRange (colorInput) {
if (typeof parseInt(colorInput) === 'number') {
var number = parseInt(colorInput);
if (number < 360 && number > 0) {
return [number, number];
}
}
if (typeof colorInput === 'string') {
if (colorDictionary[colorInput]) {
var color = colorDictionary[colorInput];
if (color.hueRange) {return color.hueRange;}
} else if (colorInput.match(/^#?([0-9A-F]{3}|[0-9A-F]{6})$/i)) {
var hue = HexToHSB(colorInput)[0];
return [ hue, hue ];
}
}
return [0,360];
}
function getSaturationRange (hue) {
return getColorInfo(hue).saturationRange;
}
function getColorInfo (hue) {
// Maps red colors to make picking hue easier
if (hue >= 334 && hue <= 360) {
hue-= 360;
}
for (var colorName in colorDictionary) {
var color = colorDictionary[colorName];
if (color.hueRange &&
hue >= color.hueRange[0] &&
hue <= color.hueRange[1]) {
return colorDictionary[colorName];
}
} return 'Color not found';
}
function randomWithin (range) {
if (seed === null) {
//generate random evenly destinct number from : https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
var golden_ratio = 0.618033988749895;
var r=Math.random();
r += golden_ratio;
r %= 1;
return Math.floor(range[0] + r*(range[1] + 1 - range[0]));
} else {
//Seeded random algorithm from http://indiegamr.com/generate-repeatable-random-numbers-in-js/
var max = range[1] || 1;
var min = range[0] || 0;
seed = (seed * 9301 + 49297) % 233280;
var rnd = seed / 233280.0;
return Math.floor(min + rnd * (max - min));
}
}
function HSVtoHex (hsv){
var rgb = HSVtoRGB(hsv);
function componentToHex(c) {
var hex = c.toString(16);
return hex.length == 1 ? '0' + hex : hex;
}
var hex = '#' + componentToHex(rgb[0]) + componentToHex(rgb[1]) + componentToHex(rgb[2]);
return hex;
}
function defineColor (name, hueRange, lowerBounds) {
var sMin = lowerBounds[0][0],
sMax = lowerBounds[lowerBounds.length - 1][0],
bMin = lowerBounds[lowerBounds.length - 1][1],
bMax = lowerBounds[0][1];
colorDictionary[name] = {
hueRange: hueRange,
lowerBounds: lowerBounds,
saturationRange: [sMin, sMax],
brightnessRange: [bMin, bMax]
};
}
function loadColorBounds () {
defineColor(
'monochrome',
null,
[[0,0],[100,0]]
);
defineColor(
'red',
[-26,18],
[[20,100],[30,92],[40,89],[50,85],[60,78],[70,70],[80,60],[90,55],[100,50]]
);
defineColor(
'orange',
[18,46],
[[20,100],[30,93],[40,88],[50,86],[60,85],[70,70],[100,70]]
);
defineColor(
'yellow',
[46,62],
[[25,100],[40,94],[50,89],[60,86],[70,84],[80,82],[90,80],[100,75]]
);
defineColor(
'green',
[62,178],
[[30,100],[40,90],[50,85],[60,81],[70,74],[80,64],[90,50],[100,40]]
);
defineColor(
'blue',
[178, 257],
[[20,100],[30,86],[40,80],[50,74],[60,60],[70,52],[80,44],[90,39],[100,35]]
);
defineColor(
'purple',
[257, 282],
[[20,100],[30,87],[40,79],[50,70],[60,65],[70,59],[80,52],[90,45],[100,42]]
);
defineColor(
'pink',
[282, 334],
[[20,100],[30,90],[40,86],[60,84],[80,80],[90,75],[100,73]]
);
}
function HSVtoRGB (hsv) {
// this doesn't work for the values of 0 and 360
// here's the hacky fix
var h = hsv[0];
if (h === 0) {h = 1;}
if (h === 360) {h = 359;}
// Rebase the h,s,v values
h = h/360;
var s = hsv[1]/100,
v = hsv[2]/100;
var h_i = Math.floor(h*6),
f = h * 6 - h_i,
p = v * (1 - s),
q = v * (1 - f*s),
t = v * (1 - (1 - f)*s),
r = 256,
g = 256,
b = 256;
switch(h_i) {
case 0: r = v; g = t; b = p; break;
case 1: r = q; g = v; b = p; break;
case 2: r = p; g = v; b = t; break;
case 3: r = p; g = q; b = v; break;
case 4: r = t; g = p; b = v; break;
case 5: r = v; g = p; b = q; break;
}
var result = [Math.floor(r*255), Math.floor(g*255), Math.floor(b*255)];
return result;
}
function HexToHSB (hex) {
hex = hex.replace(/^#/, '');
hex = hex.length === 3 ? hex.replace(/(.)/g, '$1$1') : hex;
var red = parseInt(hex.substr(0, 2), 16) / 255,
green = parseInt(hex.substr(2, 2), 16) / 255,
blue = parseInt(hex.substr(4, 2), 16) / 255;
var cMax = Math.max(red, green, blue),
delta = cMax - Math.min(red, green, blue),
saturation = cMax ? (delta / cMax) : 0;
switch (cMax) {
case red: return [ 60 * (((green - blue) / delta) % 6) || 0, saturation, cMax ];
case green: return [ 60 * (((blue - red) / delta) + 2) || 0, saturation, cMax ];
case blue: return [ 60 * (((red - green) / delta) + 4) || 0, saturation, cMax ];
}
}
function HSVtoHSL (hsv) {
var h = hsv[0],
s = hsv[1]/100,
v = hsv[2]/100,
k = (2-s)*v;
return [
h,
Math.round(s*v / (k<1 ? k : 2-k) * 10000) / 100,
k/2 * 100
];
}
function stringToInteger (string) {
var total = 0;
for (var i = 0; i !== string.length; i++) {
if (total >= Number.MAX_SAFE_INTEGER) break;
total += string.charCodeAt(i);
}
return total
}
// get The range of given hue when options.count!=0
function getRealHueRange(colorHue)
{ if (!isNaN(colorHue)) {
var number = parseInt(colorHue);
if (number < 360 && number > 0) {
return getColorInfo(colorHue).hueRange
}
}
else if (typeof colorHue === 'string') {
if (colorDictionary[colorHue]) {
var color = colorDictionary[colorHue];
if (color.hueRange) {
return color.hueRange
}
} else if (colorHue.match(/^#?([0-9A-F]{3}|[0-9A-F]{6})$/i)) {
var hue = HexToHSB(colorHue)[0];
return getColorInfo(hue).hueRange
}
}
return [0,360]
}
return randomColor;
}));
} (randomColor$1, randomColor$1.exports));
var randomColorExports = randomColor$1.exports;
var randomColor = /*@__PURE__*/getDefaultExportFromCjs(randomColorExports);
/**
* Assign a color to a unique layer ID and also considering
* common layer names such as water or wood.
* @param layerId - a layer ID
* @param alpha - alpha value for the color, default is 1
* @return a color in rgba string format
*/
function brightColor(layerId, alpha) {
let luminosity = 'bright';
let hue = undefined;
if (/water|ocean|lake|sea|river/.test(layerId)) {
hue = 'blue';
}
if (/state|country|place/.test(layerId)) {
hue = 'pink';
}
if (/road|highway|transport|streets/.test(layerId)) {
hue = 'orange';
}
if (/contour|building|earth/.test(layerId)) {
hue = 'monochrome';
}
if (/building/.test(layerId)) {
luminosity = 'dark';
}
if (/earth/.test(layerId)) {
luminosity = 'light';
}
if (/contour|landuse/.test(layerId)) {
hue = 'yellow';
}
if (/wood|forest|park|landcover|land|natural/.test(layerId)) {
hue = 'green';
}
const rgb = randomColor({
luminosity,
hue,
seed: layerId,
format: 'rgbArray'
});
return `rgba(${rgb.join(', ')}, ${alpha || "1"})`;
}
var colors = { brightColor };
function isInspectStyle(style) {
return style.metadata && style.metadata['maplibregl-inspect:inspect'];
}
function markInspectStyle(style) {
return Object.assign(style, {
metadata: Object.assign({}, style.metadata, {
'maplibregl-inspect:inspect': true
})
});
}
/**
* Maplibre Inspect Control
*/
class MaplibreInspect {
constructor(options) {
this._onSourceChange = (e) => {
if (e.sourceDataType === 'visibility' || !e.isSourceLoaded) {
return;
}
const previousSources = Object.assign({}, this.sources);
this._setSourcesFromMap();
if (!isEqual(previousSources, this.sources) && Object.keys(this.sources).length > 0) {
// If the sources have changed, we need to re-render the inspect style but not too fast
setTimeout(() => this.render(), 1000);
}
};
this._onStyleChange = () => {
const style = this._map.getStyle();
if (!isInspectStyle(style)) {
this._originalStyle = style;
}
};
this._onRightClick = () => {
if (!this.options.showMapPopupOnHover && !this.options.showInspectMapPopupOnHover && !this.options.blockHoverPopupOnClick) {
if (this._popup)
this._popup.remove();
}
};
this._onMousemove = (e) => {
if (this._showInspectMap) {
if (!this.options.showInspectMapPopup)
return;
if (e.type === 'mousemove' && !this.options.showInspectMapPopupOnHover)
return;
if (e.type === 'click' && this.options.showInspectMapPopupOnHover && this.options.blockHoverPopupOnClick) {
this._popupBlocked = !this._popupBlocked;
}
}
else {
if (!this.options.showMapPopup)
return;
if (e.type === 'mousemove' && !this.options.showMapPopupOnHover)
return;
if (e.type === 'click' && this.options.showMapPopupOnHover && this.options.blockHoverPopupOnClick) {
this._popupBlocked = !this._popupBlocked;
}
}
if (!this._popupBlocked && this._popup) {
let queryBox;
if (this.options.selectThreshold === 0) {
queryBox = e.point;
}
else {
// set a bbox around the pointer
queryBox = [
[
e.point.x - this.options.selectThreshold,
e.point.y + this.options.selectThreshold
], // bottom left (SW)
[
e.point.x + this.options.selectThreshold,
e.point.y - this.options.selectThreshold
] // top right (NE)
];
}
const features = this._map.queryRenderedFeatures(queryBox, this.options.queryParameters) || [];
this._map.getCanvas().style.cursor = (features.length) ? 'pointer' : '';
if (!features.length) {
this._popup.remove();
}
else {
this._popup.setLngLat(e.lngLat);
const renderedPopup = this.options.renderPopup(features);
if (typeof renderedPopup === 'string') {
this._popup.setHTML(renderedPopup);
}
else {
this._popup.setDOMContent(renderedPopup);
}
this._popup.addTo(this._map);
}
}
};
if (!(this instanceof MaplibreInspect)) {
throw new Error('MaplibreInspect needs to be called with the new keyword');
}
let popup = null;
if (window.maplibregl) {
popup = new window.maplibregl.Popup({
closeButton: false,
closeOnClick: false
});
}
else if (!options.popup) {
console.error('Maplibre GL JS can not be found. Make sure to include it or pass an initialized MaplibreGL Popup to MaplibreInspect if you are using moduleis.');
}
this.options = Object.assign({
showInspectMap: false,
showInspectButton: true,
showInspectMapPopup: true,
showMapPopup: false,
showMapPopupOnHover: true,
showInspectMapPopupOnHover: true,
blockHoverPopupOnClick: false,
backgroundColor: '#fff',
assignLayerColor: colors.brightColor,
buildInspectStyle: stylegen.generateInspectStyle,
renderPopup,
popup,
selectThreshold: 5,
useInspectStyle: true,
queryParameters: {},
sources: {},
toggleCallback() { },
manageStyleOutside: false
}, options);
this.sources = this.options.sources;
this.assignLayerColor = this.options.assignLayerColor;
this._popup = this.options.popup;
this._popupBlocked = false;
this._showInspectMap = this.options.showInspectMap;
this._toggle = new InspectButton({
show: this.options.showInspectButton,
onToggle: () => this.toggleInspector()
});
}
toggleInspector() {
this._showInspectMap = !this._showInspectMap;
this._popupBlocked = false;
this.options.toggleCallback(this._showInspectMap);
this.render();
}
_inspectStyle() {
const coloredLayers = stylegen.generateColoredLayers(this.sources, this.assignLayerColor);
return this.options.buildInspectStyle(this._map.getStyle(), coloredLayers, {
backgroundColor: this.options.backgroundColor
});
}
render() {
if (this._showInspectMap) {
if (this.options.useInspectStyle) {
this._map.setStyle(markInspectStyle(this._inspectStyle()));
}
this._toggle.setMapIcon();
}
else if (this._originalStyle) {
if (this._popup)
this._popup.remove();
if (this.options.useInspectStyle) {
this._map.setStyle(this._originalStyle);
}
this._toggle.setInspectIcon();
}
}
_setSourcesFromMap() {
//NOTE: This heavily depends on the internal API of Maplibre GL
//so this breaks between Maplibre GL JS releases
const mapStyleSourcesNames = Object.keys(this._map.getStyle().sources);
Object.keys(this._map.style.sourceCaches).forEach((sourceId) => {
const sourceCache = this._map.style.sourceCaches[sourceId] || { _source: {} };
const layerIds = sourceCache._source.vectorLayerIds;
if (layerIds) {
this.sources[sourceId] = layerIds;
}
else if (sourceCache._source.type === 'geojson') {
this.sources[sourceId] = [];
}
});
Object.keys(this.sources).forEach((sourceId) => {
if (mapStyleSourcesNames.indexOf(sourceId) === -1) {
delete this.sources[sourceId];
}
});
}
/**
* This will set the original style of the map
* It will also update the sources assuming the map has already been loaded
* @param style - The original style
*/
setOriginalStyle(style) {
this._originalStyle = style;
this._setSourcesFromMap();
}
onAdd(map) {
this._map = map;
// if sources have already been passed as options
// we do not need to figure out the sources ourselves
if (Object.keys(this.sources).length === 0) {
map.on('tiledata', this._onSourceChange);
map.on('sourcedata', this._onSourceChange);
}
map.on('styledata', this._onStyleChange);
map.on('load', this._onStyleChange);
map.on('mousemove', this._onMousemove);
map.on('click', this._onMousemove);
map.on('contextmenu', this._onRightClick);
return this._toggle.elem;
}
onRemove() {
this._map.off('styledata', this._onStyleChange);
this._map.off('load', this._onStyleChange);
this._map.off('tiledata', this._onSourceChange);
this._map.off('sourcedata', this._onSourceChange);
this._map.off('mousemove', this._onMousemove);
this._map.off('click', this._onMousemove);
this._map.off('contextmenu', this._onRightClick);
const elem = this._toggle.elem;
elem.parentNode.removeChild(elem);
this._map = undefined;
}
}
return MaplibreInspect;
}));
//# sourceMappingURL=maplibre-gl-inspect.js.map