mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-20 21:46:00 +00:00
202 lines
5.2 KiB
Svelte
202 lines
5.2 KiB
Svelte
<script lang="ts" context="module">
|
|
export function selectionCouldBeShownOnMap(selection) {
|
|
if (selection.length > 0 && _.find(selection, x => isWktGeometry(x.value))) {
|
|
return true;
|
|
}
|
|
|
|
if (
|
|
selection.find(x => x.column.toLowerCase().includes('lat')) &&
|
|
(selection.find(x => x.column.toLowerCase().includes('lon')) ||
|
|
selection.find(x => x.column.toLowerCase().includes('lng')))
|
|
) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
</script>
|
|
|
|
<script lang="ts">
|
|
import _ from 'lodash';
|
|
import { onMount, tick } from 'svelte';
|
|
import 'leaflet/dist/leaflet.css';
|
|
import leaflet from 'leaflet';
|
|
import wellknown from 'wellknown';
|
|
import { isWktGeometry, ScriptWriter, ScriptWriterJson } from 'dbgate-tools';
|
|
import resizeObserver from '../utility/resizeObserver';
|
|
import openNewTab from '../utility/openNewTab';
|
|
import contextMenu from '../utility/contextMenu';
|
|
import { saveExportedFile, saveFileToDisk } from '../utility/exportFileTools';
|
|
import { getCurrentConfig } from '../stores';
|
|
import { apiCall } from '../utility/api';
|
|
|
|
export let selection;
|
|
|
|
let refContainer;
|
|
let map;
|
|
|
|
let selectionLayers = [];
|
|
let geoJson;
|
|
|
|
function createColumnsTable(cells) {
|
|
if (cells.length == 0) return '';
|
|
return `<table>${cells.map(cell => `<tr><td>${cell.column}</td><td>${cell.value}</td></tr>`).join('\n')}</table>`;
|
|
}
|
|
|
|
function addSelectionToMap() {
|
|
if (!map) return;
|
|
if (!selection) return;
|
|
|
|
for (const selectionLayer of selectionLayers) {
|
|
selectionLayer.remove();
|
|
}
|
|
selectionLayers = [];
|
|
|
|
const selectedRows = _.groupBy(selection || [], 'row');
|
|
|
|
const features = [];
|
|
|
|
for (const rowKey of _.keys(selectedRows)) {
|
|
const cells = selectedRows[rowKey];
|
|
const lat = cells.find(x => x.column.toLowerCase().includes('lat'));
|
|
const lon = cells.find(x => x.column.toLowerCase().includes('lon') || x.column.toLowerCase().includes('lng'));
|
|
|
|
const geoValues = cells.map(x => x.value).filter(isWktGeometry);
|
|
|
|
if (lat && lon) {
|
|
features.push({
|
|
type: 'Feature',
|
|
properties: {
|
|
popupContent: createColumnsTable(cells),
|
|
},
|
|
geometry: {
|
|
type: 'Point',
|
|
coordinates: [lon.value, lat.value],
|
|
},
|
|
});
|
|
}
|
|
|
|
if (geoValues.length > 0) {
|
|
// parse WKT to geoJSON array
|
|
features.push(
|
|
...geoValues.map(wellknown).map(geometry => ({
|
|
type: 'Feature',
|
|
properties: {
|
|
popupContent: createColumnsTable(cells.filter(x => !isWktGeometry(x.value))),
|
|
},
|
|
geometry,
|
|
}))
|
|
);
|
|
}
|
|
}
|
|
|
|
if (features.length == 0) {
|
|
return;
|
|
}
|
|
|
|
geoJson = {
|
|
type: 'FeatureCollection',
|
|
features,
|
|
};
|
|
|
|
const geoJsonObj = leaflet
|
|
.geoJSON(geoJson, {
|
|
style: function () {
|
|
return {
|
|
weight: 2,
|
|
fillColor: '#ff7800',
|
|
color: '#ff7800',
|
|
opacity: 0.8,
|
|
fillOpacity: 0.4,
|
|
};
|
|
},
|
|
pointToLayer: (feature, latlng) => {
|
|
return leaflet.circleMarker(latlng, {
|
|
radius: 7,
|
|
weight: 2,
|
|
fillColor: '#ff0000',
|
|
color: '#ff0000',
|
|
opacity: 0.9,
|
|
fillOpacity: 0.9,
|
|
});
|
|
},
|
|
onEachFeature: (feature, layer) => {
|
|
// does this feature have a property named popupContent?
|
|
if (feature.properties && feature.properties.popupContent) {
|
|
layer.bindPopup(feature.properties.popupContent);
|
|
layer.bindTooltip(feature.properties.popupContent);
|
|
}
|
|
},
|
|
})
|
|
.addTo(map);
|
|
// geoJsonObj.bindPopup('This is the Transamerica Pyramid'); //.openPopup();
|
|
map.fitBounds(geoJsonObj.getBounds());
|
|
selectionLayers.push(geoJsonObj);
|
|
}
|
|
|
|
onMount(() => {
|
|
map = leaflet.map(refContainer).setView([50, 15], 13);
|
|
|
|
leaflet
|
|
.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
maxZoom: 19,
|
|
attribution: '© OpenStreetMap',
|
|
})
|
|
.addTo(map);
|
|
|
|
addSelectionToMap();
|
|
// map.fitBounds([
|
|
// [50, 15],
|
|
// [50.1, 15],
|
|
// [50, 15.1],
|
|
// ]);
|
|
|
|
// const marker = leaflet.marker([50, 15]).addTo(map);
|
|
// <div bind:this={refContainer} class="flex1 map-container" />
|
|
});
|
|
|
|
$: {
|
|
selection;
|
|
addSelectionToMap();
|
|
}
|
|
|
|
function createMenu() {
|
|
return [
|
|
{
|
|
text: 'Open on new tab',
|
|
onClick: () => {
|
|
openNewTab(
|
|
{
|
|
title: 'Map',
|
|
icon: 'img map',
|
|
tabComponent: 'MapTab',
|
|
},
|
|
{ editor: selection.map(x => _.omit(x, ['engine'])) }
|
|
);
|
|
},
|
|
},
|
|
{
|
|
text: 'Export to HTML file',
|
|
onClick: () => {
|
|
saveFileToDisk(async filePath => {
|
|
await apiCall('files/export-map', {
|
|
geoJson,
|
|
filePath,
|
|
});
|
|
});
|
|
},
|
|
},
|
|
];
|
|
}
|
|
</script>
|
|
|
|
<div
|
|
bind:this={refContainer}
|
|
use:contextMenu={createMenu}
|
|
class="flex1"
|
|
use:resizeObserver={true}
|
|
on:resize={async e => {
|
|
await tick();
|
|
map.invalidateSize();
|
|
}}
|
|
/>
|