Compare commits
6 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
d331af259e | 3 years ago |
|
|
ca020ab3b3 | 3 years ago |
|
|
f838889afd | 3 years ago |
|
|
6f0ed6960b | 3 years ago |
|
|
ed609322fa | 3 years ago |
|
|
78df895fe9 | 3 years ago |
@ -1,228 +1,303 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="map-wrap">
|
<div class="map-wrap">
|
||||||
<div id="map" class="map" ref="mapContainer"></div>
|
<div id="layer-control" class="d-flex flex-direction-column">
|
||||||
|
<va-radio
|
||||||
|
v-for="(option, index) in options"
|
||||||
|
:key="index"
|
||||||
|
v-model="selectedOption"
|
||||||
|
:option="option"
|
||||||
|
:label="labels[index]"
|
||||||
|
/>
|
||||||
|
<va-checkbox class="mb-4" v-model="valuecb" :label="label" />
|
||||||
</div>
|
</div>
|
||||||
|
<div id="map" class="map" ref="mapContainer"></div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import maplibregl from "maplibre-gl";
|
import maplibregl from "maplibre-gl";
|
||||||
import { markRaw, onMounted, onUnmounted, reactive, shallowRef, watch } from "vue";
|
import {
|
||||||
|
markRaw,
|
||||||
|
onMounted,
|
||||||
|
onUnmounted,
|
||||||
|
reactive,
|
||||||
|
shallowRef,
|
||||||
|
watch,
|
||||||
|
} from "vue";
|
||||||
export default {
|
export default {
|
||||||
name: "map-component",
|
name: "map-component",
|
||||||
props: {
|
props: {
|
||||||
idlist: {
|
idlist: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: true,
|
required: true,
|
||||||
}
|
|
||||||
},
|
},
|
||||||
setup(props, context) {
|
},
|
||||||
const mapContainer = shallowRef(null);
|
data() {
|
||||||
const map = shallowRef(null);
|
return {
|
||||||
let currentFadr = reactive({ "fadr": [] });
|
valuebm: "",
|
||||||
|
options: ["Карта", "Спутник", "Монохром"],
|
||||||
|
valuecb: true,
|
||||||
|
label: "Месторождения",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
setup(props, context) {
|
||||||
|
const mapContainer = shallowRef(null);
|
||||||
|
const map = shallowRef(null);
|
||||||
|
let currentFadr = reactive({ fadr: [] });
|
||||||
|
|
||||||
|
const apiKey =
|
||||||
|
"pk.eyJ1IjoiZ2hlcm1hbnQiLCJhIjoiY2pncDUwcnRmNDQ4ZjJ4czdjZXMzaHZpNyJ9.3rFyYRRtvLUngHm027HZ7A";
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => [...props.idlist],
|
||||||
|
(_currentValue, _oldValue) => {
|
||||||
|
updateSamplesLayer();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const buildMap = () => {
|
||||||
|
map.value = markRaw(
|
||||||
|
new maplibregl.Map({
|
||||||
|
container: mapContainer.value, // container id
|
||||||
|
// DOCS: https://maplibre.org/maplibre-gl-js-docs/style-spec/
|
||||||
|
style: {
|
||||||
|
version: 8,
|
||||||
|
sources: {},
|
||||||
|
layers: [],
|
||||||
|
},
|
||||||
|
center: [80, 40], // starting position [lng, lat]
|
||||||
|
zoom: 2, // starting zoom
|
||||||
|
maxZoom: 10,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const apiKey = "pk.eyJ1IjoiZ2hlcm1hbnQiLCJhIjoiY2pncDUwcnRmNDQ4ZjJ4czdjZXMzaHZpNyJ9.3rFyYRRtvLUngHm027HZ7A";
|
map.value.on("load", () => {
|
||||||
|
const basemapTiles = {
|
||||||
|
"topo": [`https://api.mapbox.com/styles/v1/ghermant/cl9vd1nji002n15s2xxj25f4m/tiles/256/{z}/{x}/{y}@2x?access_token=${apiKey}`],
|
||||||
|
"satellite": [`https://api.mapbox.com/styles/v1/ghermant/cl9vd1nji002n15s2xxj25f4m/tiles/256/{z}/{x}/{y}@2x?access_token=${apiKey}`],
|
||||||
|
"mono": [`https://api.mapbox.com/styles/v1/ghermant/cl9olarp0002i14vq9a2d0e7g/tiles/256/{z}/{x}/{y}@2x?access_token=${apiKey}`]
|
||||||
|
}
|
||||||
|
|
||||||
|
map.value.addSource("basemap", {
|
||||||
|
type: "raster",
|
||||||
|
tiles: [
|
||||||
|
`https://api.mapbox.com/styles/v1/ghermant/cl9vd1nji002n15s2xxj25f4m/tiles/256/{z}/{x}/{y}@2x?access_token=${apiKey}`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
watch(() => [...props.idlist], (_currentValue, _oldValue) => {
|
map.value.addLayer({
|
||||||
updateSamplesLayer()
|
id: "basemap-layer",
|
||||||
|
type: "raster",
|
||||||
|
source: "topo-basemap",
|
||||||
|
paint: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
const buildMap = () => {
|
map.value.addSource("fields", {
|
||||||
map.value = markRaw(new maplibregl.Map({
|
type: "vector",
|
||||||
container: mapContainer.value, // container id
|
tiles: [
|
||||||
// DOCS: https://maplibre.org/maplibre-gl-js-docs/style-spec/
|
`https://api.mapbox.com/v4/ghermant.cpc0xaaw/{z}/{x}/{y}.mvt?access_token=${apiKey}`,
|
||||||
style: {
|
],
|
||||||
version: 8,
|
});
|
||||||
sources: {},
|
map.value.addLayer({
|
||||||
layers: []
|
id: "fields-layer",
|
||||||
},
|
type: "fill",
|
||||||
center: [80, 40], // starting position [lng, lat]
|
source: "fields",
|
||||||
zoom: 2, // starting zoom
|
"source-layer": "mygeomapZoom2-2utkfs",
|
||||||
maxZoom: 10
|
paint: {
|
||||||
}));
|
"fill-color": "#fc9272",
|
||||||
|
"fill-opacity": 0.5,
|
||||||
map.value.on('load', () => {
|
},
|
||||||
map.value.addSource('basemap-source', {
|
layout: {
|
||||||
'type': 'raster',
|
visibility: "visible",
|
||||||
'tiles': [`https://api.mapbox.com/styles/v1/ghermant/cl8vg2r97001m14o4c2qzw9t6/tiles/256/{z}/{x}/{y}@2x?access_token=${apiKey}`]
|
},
|
||||||
})
|
minzoom: 4
|
||||||
|
|
||||||
map.value.addLayer(
|
|
||||||
{
|
|
||||||
'id': 'basemap-layer',
|
|
||||||
'type': 'raster',
|
|
||||||
'source': 'basemap-source',
|
|
||||||
'paint': {}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
map.value.addSource('samples', {
|
|
||||||
'type': 'vector',
|
|
||||||
"tiles": ["http://localhost:8080/martin/public.geodata/{z}/{x}/{y}.pbf"],
|
|
||||||
'promoteId': 'fadr',
|
|
||||||
});
|
|
||||||
|
|
||||||
map.value.addLayer({
|
|
||||||
'id': 'samples-layer',
|
|
||||||
'source': 'samples',
|
|
||||||
'source-layer': 'public.geodata',
|
|
||||||
'type': 'circle',
|
|
||||||
'paint': {
|
|
||||||
'circle-stroke-width': 1,
|
|
||||||
'circle-stroke-color': '#FFFFFF',
|
|
||||||
'circle-color': [
|
|
||||||
'case',
|
|
||||||
['boolean', ['feature-state', 'beenClicked'], false],
|
|
||||||
'#fec44f',
|
|
||||||
'#d95f0e'
|
|
||||||
],
|
|
||||||
'circle-opacity': 0.8,
|
|
||||||
'circle-radius': 8
|
|
||||||
},
|
|
||||||
filter: ["match", ["get", "internal_id"], props.idlist, true, false]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const popup = new maplibregl.Popup({
|
|
||||||
closeButton: false,
|
|
||||||
closeOnClick: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
map.value.on('mouseover', 'samples-layer', (e) => {
|
|
||||||
// Change the cursor style as a UI indicator.
|
|
||||||
map.value.getCanvas().style.cursor = 'pointer';
|
|
||||||
// Populate the popup and set its coordinates
|
|
||||||
// based on the feature found.
|
|
||||||
popup
|
|
||||||
.setLngLat(e.lngLat)
|
|
||||||
.setHTML(`Записей в точке: <b>${e.features.length}</b>`)
|
|
||||||
.addTo(map.value);
|
|
||||||
});
|
|
||||||
|
|
||||||
map.value.on('mouseleave', 'samples-layer', (e) => {
|
|
||||||
map.value.getCanvas().style.cursor = '';
|
|
||||||
popup.remove();
|
|
||||||
});
|
|
||||||
|
|
||||||
map.value.on('click', 'samples-layer', (e) => {
|
|
||||||
let newFadr = e.features[0].properties["fadr"];
|
|
||||||
|
|
||||||
let newFadrFound = currentFadr["fadr"].indexOf(newFadr)
|
|
||||||
if (newFadrFound > -1) {
|
|
||||||
//remove old paint
|
|
||||||
map.value.setFeatureState(
|
|
||||||
{
|
|
||||||
source: 'samples',
|
|
||||||
sourceLayer: 'public.geodata',
|
|
||||||
id: newFadr
|
|
||||||
},
|
|
||||||
{ beenClicked: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
// remove from filters
|
|
||||||
currentFadr["fadr"].splice(newFadrFound, 1)
|
|
||||||
} else {
|
|
||||||
// apply new paint
|
|
||||||
map.value.setFeatureState(
|
|
||||||
{
|
|
||||||
source: 'samples',
|
|
||||||
sourceLayer: 'public.geodata',
|
|
||||||
id: newFadr
|
|
||||||
},
|
|
||||||
{ beenClicked: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
// add to filters
|
|
||||||
currentFadr["fadr"].push(newFadr);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.emit('mapClick', currentFadr);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
map.value.on('click', (e) => {
|
|
||||||
const features = map.value.queryRenderedFeatures(e.point)
|
|
||||||
if (!features.length) {
|
|
||||||
currentFadr["fadr"].forEach((oldFadr) => {
|
|
||||||
map.value.setFeatureState(
|
|
||||||
{
|
|
||||||
source: 'samples',
|
|
||||||
sourceLayer: 'public.geodata',
|
|
||||||
id: oldFadr
|
|
||||||
},
|
|
||||||
{ beenClicked: false }
|
|
||||||
);
|
|
||||||
})
|
|
||||||
currentFadr["fadr"].length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
context.emit('mapClick', currentFadr);
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateSamplesLayer = () => {
|
|
||||||
if (map.value.getLayer('samples-layer')) {
|
|
||||||
map.value.removeLayer('samples-layer');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.idlist.length) {
|
|
||||||
map.value.addLayer({
|
|
||||||
'id': 'samples-layer',
|
|
||||||
'source': 'samples',
|
|
||||||
'source-layer': 'public.geodata',
|
|
||||||
'type': 'circle',
|
|
||||||
'paint': {
|
|
||||||
'circle-stroke-width': 1,
|
|
||||||
'circle-stroke-color': '#FFFFFF',
|
|
||||||
'circle-color': [
|
|
||||||
'case',
|
|
||||||
['boolean', ['feature-state', 'beenClicked'], false],
|
|
||||||
'#fec44f',
|
|
||||||
'#d95f0e'
|
|
||||||
],
|
|
||||||
'circle-opacity': 0.8,
|
|
||||||
'circle-radius': 8
|
|
||||||
},
|
|
||||||
filter: ["match", ["get", "internal_id"], props.idlist, true, false]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
buildMap()
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
map.value.addSource("samples", {
|
||||||
// TODO: remove even listeners too
|
type: "vector",
|
||||||
map.value?.remove();
|
tiles: [
|
||||||
})
|
"http://localhost:8080/martin/public.geodata/{z}/{x}/{y}.pbf",
|
||||||
|
],
|
||||||
|
promoteId: "fadr",
|
||||||
|
});
|
||||||
|
|
||||||
|
map.value.addLayer({
|
||||||
|
id: "samples-layer",
|
||||||
|
source: "samples",
|
||||||
|
"source-layer": "public.geodata",
|
||||||
|
type: "circle",
|
||||||
|
paint: {
|
||||||
|
"circle-stroke-width": 1,
|
||||||
|
"circle-stroke-color": "#FFFFFF",
|
||||||
|
"circle-color": [
|
||||||
|
"case",
|
||||||
|
["boolean", ["feature-state", "beenClicked"], false],
|
||||||
|
"#fec44f",
|
||||||
|
"#d95f0e",
|
||||||
|
],
|
||||||
|
"circle-opacity": 0.8,
|
||||||
|
"circle-radius": 8,
|
||||||
|
},
|
||||||
|
filter: ["match", ["get", "internal_id"], props.idlist, true, false],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const popup = new maplibregl.Popup({
|
||||||
|
closeButton: false,
|
||||||
|
closeOnClick: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
map.value.on("click", "fields-layer", (e) => {
|
||||||
|
new maplibregl.Popup({})
|
||||||
|
.setLngLat(e.lngLat)
|
||||||
|
.setHTML(e.features[0].properties["descriptio"])
|
||||||
|
.addTo(map.value);
|
||||||
|
})
|
||||||
|
|
||||||
|
map.value.on("mouseover", "fields-layer", (e) => {
|
||||||
|
map.value.getCanvas().style.cursor = "pointer";
|
||||||
|
})
|
||||||
|
|
||||||
|
map.value.on("mouseleave", "fields-layer", (e) => {
|
||||||
|
map.value.getCanvas().style.cursor = "";
|
||||||
|
})
|
||||||
|
|
||||||
|
map.value.on("mouseover", "samples-layer", (e) => {
|
||||||
|
// Change the cursor style as a UI indicator.
|
||||||
|
map.value.getCanvas().style.cursor = "pointer";
|
||||||
|
// Populate the popup and set its coordinates
|
||||||
|
// based on the feature found.
|
||||||
|
popup
|
||||||
|
.setLngLat(e.lngLat)
|
||||||
|
.setHTML(`Записей в точке: <b>${e.features.length}</b>`)
|
||||||
|
.addTo(map.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
map.value.on("mouseleave", "samples-layer", (e) => {
|
||||||
|
map.value.getCanvas().style.cursor = "";
|
||||||
|
popup.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
map.value.on("click", "samples-layer", (e) => {
|
||||||
|
let newFadr = e.features[0].properties["fadr"];
|
||||||
|
|
||||||
|
let newFadrFound = currentFadr["fadr"].indexOf(newFadr);
|
||||||
|
if (newFadrFound > -1) {
|
||||||
|
//remove old paint
|
||||||
|
map.value.setFeatureState(
|
||||||
|
{
|
||||||
|
source: "samples",
|
||||||
|
sourceLayer: "public.geodata",
|
||||||
|
id: newFadr,
|
||||||
|
},
|
||||||
|
{ beenClicked: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
// remove from filters
|
||||||
|
currentFadr["fadr"].splice(newFadrFound, 1);
|
||||||
|
} else {
|
||||||
|
// apply new paint
|
||||||
|
map.value.setFeatureState(
|
||||||
|
{
|
||||||
|
source: "samples",
|
||||||
|
sourceLayer: "public.geodata",
|
||||||
|
id: newFadr,
|
||||||
|
},
|
||||||
|
{ beenClicked: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
// add to filters
|
||||||
|
currentFadr["fadr"].push(newFadr);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
context.emit("mapClick", currentFadr);
|
||||||
map, mapContainer, currentFadr
|
});
|
||||||
|
|
||||||
|
map.value.on("click", (e) => {
|
||||||
|
const features = map.value.queryRenderedFeatures(e.point);
|
||||||
|
if (!features.length) {
|
||||||
|
currentFadr["fadr"].forEach((oldFadr) => {
|
||||||
|
map.value.setFeatureState(
|
||||||
|
{
|
||||||
|
source: "samples",
|
||||||
|
sourceLayer: "public.geodata",
|
||||||
|
id: oldFadr,
|
||||||
|
},
|
||||||
|
{ beenClicked: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
currentFadr["fadr"].length = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
context.emit("mapClick", currentFadr);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateSamplesLayer = () => {
|
||||||
|
if (map.value.getLayer("samples-layer")) {
|
||||||
|
map.value.removeLayer("samples-layer");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.idlist.length) {
|
||||||
|
map.value.addLayer({
|
||||||
|
id: "samples-layer",
|
||||||
|
source: "samples",
|
||||||
|
"source-layer": "public.geodata",
|
||||||
|
type: "circle",
|
||||||
|
paint: {
|
||||||
|
"circle-stroke-width": 1,
|
||||||
|
"circle-stroke-color": "#FFFFFF",
|
||||||
|
"circle-color": [
|
||||||
|
"case",
|
||||||
|
["boolean", ["feature-state", "beenClicked"], false],
|
||||||
|
"#fec44f",
|
||||||
|
"#d95f0e",
|
||||||
|
],
|
||||||
|
"circle-opacity": 0.8,
|
||||||
|
"circle-radius": 8,
|
||||||
|
},
|
||||||
|
filter: ["match", ["get", "internal_id"], props.idlist, true, false],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
buildMap();
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
// TODO: remove even listeners too
|
||||||
|
map.value?.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
map,
|
||||||
|
mapContainer,
|
||||||
|
currentFadr,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style lang="css">
|
<style lang="css">
|
||||||
.map-wrap {
|
.map-wrap {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.map {
|
.map {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
/* z-index: -1; */
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#layer-control {
|
||||||
|
position: absolute;
|
||||||
|
top: 1rem;
|
||||||
|
right: 1rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Loading…
Reference in new issue