Add custom GeoJSON layer functionality
This commit is contained in:
parent
35e92304c5
commit
13855a9a38
13
generic-pin.svg
Normal file
13
generic-pin.svg
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 384 512"
|
||||||
|
width="40px"
|
||||||
|
height="30px"
|
||||||
|
version="1.1"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<!--! Font Awesome Pro 6.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
|
||||||
|
<path
|
||||||
|
d="m 384,192 c 0,87.4 -117,243 -168.3,307.2 -12.3,15.3 -35.1,15.3 -47.4,0 C 116.1,435 0,279.4 0,192 0,85.96 85.96,0 192,0 245.96029,0 294.73775,22.275796 329.62577,58.136607 363.27205,92.721042 384,139.94065 384,192 Z"
|
||||||
|
style="fill:#fff;fill-opacity:1" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 667 B |
73
main.js
73
main.js
|
@ -11,6 +11,14 @@ import ToggleMenuControl from './ui/controls.js';
|
||||||
|
|
||||||
import layerCategories from './layers/index.js';
|
import layerCategories from './layers/index.js';
|
||||||
|
|
||||||
|
import VectorLayer from 'ol/layer/Vector';
|
||||||
|
import {Vector as VectorSource} from 'ol/source.js';
|
||||||
|
import GeoJSON from 'ol/format/GeoJSON.js';
|
||||||
|
import {Style} from 'ol/style.js';
|
||||||
|
import Icon from 'ol/style/Icon.js';
|
||||||
|
|
||||||
|
import pin from './generic-pin.svg?url';
|
||||||
|
|
||||||
// from https://openlayers.org/en/latest/examples/popup.html
|
// from https://openlayers.org/en/latest/examples/popup.html
|
||||||
const container = document.getElementById('popup');
|
const container = document.getElementById('popup');
|
||||||
const content = document.getElementById('popup-content');
|
const content = document.getElementById('popup-content');
|
||||||
|
@ -140,6 +148,71 @@ for (let category of layerCategories) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const customLayerDiv = document.createElement("div");
|
||||||
|
customLayerDiv.innerHTML = `
|
||||||
|
<details>
|
||||||
|
<summary>Custom</summary>
|
||||||
|
<label>Layer Name: <input name="label"></label><br>
|
||||||
|
<label>Layer URL: <input name="source"></label><br>
|
||||||
|
<label>Color (optional): <input name="color"></label><br>
|
||||||
|
<button>Add</button>
|
||||||
|
<small>(must be in GeoJSON format)</small>
|
||||||
|
<ul></ul>
|
||||||
|
</details>`;
|
||||||
|
const labelInput = customLayerDiv.querySelector('input[name=label]');
|
||||||
|
const sourceInput = customLayerDiv.querySelector('input[name=source]');
|
||||||
|
const colorInput = customLayerDiv.querySelector('input[name=color]');
|
||||||
|
|
||||||
|
customLayerDiv.querySelector("button").addEventListener("click", function(){
|
||||||
|
newCustomLayer(labelInput.value, sourceInput.value, colorInput.value);
|
||||||
|
});
|
||||||
|
document.querySelector("aside").appendChild(customLayerDiv);
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/64090995
|
||||||
|
let hslToRgb = (h,s,l, a=s*Math.min(l,1-l), f= (n,k=(n+h/30)%12) => l - a*Math.max(Math.min(k-3,9-k,1),-1)) => [f(0),f(8),f(4)];
|
||||||
|
|
||||||
|
function newCustomLayer(name, sourceURL, colorString) {
|
||||||
|
let color;
|
||||||
|
if (colorString) {
|
||||||
|
color = colorString.split(' ').map(Number);
|
||||||
|
if (color.length != 3 || color.some(Number.isNaN)) {
|
||||||
|
alert("Invalid color provided; using random color instead.");
|
||||||
|
color = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!color) {
|
||||||
|
color = hslToRgb(Math.random()*360, 1, 0.5).map(c => c * 255);
|
||||||
|
}
|
||||||
|
const li = document.createElement("li");
|
||||||
|
const layer = new VectorLayer({
|
||||||
|
source: new VectorSource({
|
||||||
|
// In case people put in layers that don't serve proper CORS headers, we
|
||||||
|
// wrap them in this proxy so they Just Work.
|
||||||
|
url: `https://corsproxy.io/?${encodeURIComponent(sourceURL)}`,
|
||||||
|
format: new GeoJSON,
|
||||||
|
}),
|
||||||
|
style: new Style({
|
||||||
|
image: new Icon({
|
||||||
|
anchor: [0.5, 1],
|
||||||
|
src: pin,
|
||||||
|
color: color,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
li.innerHTML = `
|
||||||
|
<label><input type="checkbox" checked> ${name}</label>
|
||||||
|
`;
|
||||||
|
li.querySelector("input").addEventListener("change", function(e){
|
||||||
|
if (e.target.checked) {
|
||||||
|
map.getLayers().push(layer);
|
||||||
|
} else {
|
||||||
|
map.getLayers().remove(layer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
map.getLayers().push(layer);
|
||||||
|
customLayerDiv.querySelector("ul").appendChild(li);
|
||||||
|
}
|
||||||
|
|
||||||
let location_set = false;
|
let location_set = false;
|
||||||
|
|
||||||
if (urlLayers.length > 0) {
|
if (urlLayers.length > 0) {
|
||||||
|
|
Loading…
Reference in a new issue