map view refactor

This commit is contained in:
Jan Prochazka
2022-12-31 12:43:27 +01:00
parent cb0a9770d2
commit 3aa7e6c022
6 changed files with 158 additions and 137 deletions

View File

@@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import _ from 'lodash'; import _ from 'lodash';
import MapView, { findAllObjectPaths, findLatPaths, findLonPaths } from '../elements/MapView.svelte'; import SelectionMapView, { findAllObjectPaths, findLatPaths, findLonPaths } from '../elements/SelectionMapView.svelte';
import SelectField from '../forms/SelectField.svelte'; import SelectField from '../forms/SelectField.svelte';
export let selection; export let selection;
@@ -48,7 +48,7 @@
</div> </div>
{/if} {/if}
<MapView {selection} {latitudeField} {longitudeField} /> <SelectionMapView {selection} {latitudeField} {longitudeField} />
</div> </div>
<style> <style>

View File

@@ -333,7 +333,7 @@
import { apiCall } from '../utility/api'; import { apiCall } from '../utility/api';
import getElectron from '../utility/getElectron'; import getElectron from '../utility/getElectron';
import { isCtrlOrCommandKey, isMac } from '../utility/common'; import { isCtrlOrCommandKey, isMac } from '../utility/common';
import { selectionCouldBeShownOnMap } from '../elements/MapView.svelte'; import { selectionCouldBeShownOnMap } from '../elements/SelectionMapView.svelte';
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte'; import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
import EditCellDataModal, { shouldOpenMultilineDialog } from '../modals/EditCellDataModal.svelte'; import EditCellDataModal, { shouldOpenMultilineDialog } from '../modals/EditCellDataModal.svelte';

View File

@@ -1,48 +1,3 @@
<script lang="ts" context="module">
function findLatLonPaths(obj, attrTest, res = [], prefix = '') {
for (const key of Object.keys(obj)) {
if (attrTest(key, obj[key])) {
res.push(prefix + key);
}
if (_.isPlainObject(obj[key])) {
findLatLonPaths(obj[key], attrTest, res, prefix + key + '.');
}
}
return res;
}
export function findLatPaths(obj) {
return findLatLonPaths(obj, x => x.includes('lat'));
}
export function findLonPaths(obj) {
return findLatLonPaths(obj, x => x.includes('lon') || x.includes('lng'));
}
export function findAllObjectPaths(obj) {
return findLatLonPaths(obj, (_k, v) => v != null && !_.isNaN(Number(v)));
}
export function selectionCouldBeShownOnMap(selection) {
if (selection.length > 0 && _.find(selection, x => isWktGeometry(x.value))) {
return true;
}
if (
selection.length > 0 &&
_.find(selection, x => findLatPaths(x.rowData).length > 0 && findLonPaths(x.rowData).length > 0)
) {
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"> <script lang="ts">
import _ from 'lodash'; import _ from 'lodash';
import { onMount, tick } from 'svelte'; import { onMount, tick } from 'svelte';
@@ -57,82 +12,19 @@
import { getCurrentConfig } from '../stores'; import { getCurrentConfig } from '../stores';
import { apiCall } from '../utility/api'; import { apiCall } from '../utility/api';
export let selection;
export let latitudeField = '';
export let longitudeField = '';
let refContainer; let refContainer;
let map; let map;
let selectionLayers = []; let layers = [];
let geoJson; export let geoJson;
function createColumnsTable(cells) { function addObjectToMap() {
if (cells.length == 0) return '';
return `<table>${cells
.map(cell => `<tr><td>${cell.column}</td><td>${stringifyCellValue(cell.value)}</td></tr>`)
.join('\n')}</table>`;
}
function addSelectionToMap() {
if (!map) return; if (!map) return;
if (!selection) return;
for (const selectionLayer of selectionLayers) { for (const layer of layers) {
selectionLayer.remove(); layer.remove();
} }
selectionLayers = []; layers = [];
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);
const lat = latitudeField ? Number(_.get(cells[0].rowData, latitudeField)) : NaN;
const lon = longitudeField ? Number(_.get(cells[0].rowData, longitudeField)) : NaN;
if (!_.isNaN(lat) && !_.isNaN(lon)) {
features.push({
type: 'Feature',
properties: {
popupContent: createColumnsTable(cells),
},
geometry: {
type: 'Point',
coordinates: [Number(lon), Number(lat)],
},
});
}
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 const geoJsonObj = leaflet
.geoJSON(geoJson, { .geoJSON(geoJson, {
@@ -166,7 +58,7 @@
.addTo(map); .addTo(map);
// geoJsonObj.bindPopup('This is the Transamerica Pyramid'); //.openPopup(); // geoJsonObj.bindPopup('This is the Transamerica Pyramid'); //.openPopup();
map.fitBounds(geoJsonObj.getBounds()); map.fitBounds(geoJsonObj.getBounds());
selectionLayers.push(geoJsonObj); layers.push(geoJsonObj);
} }
onMount(() => { onMount(() => {
@@ -179,22 +71,12 @@
}) })
.addTo(map); .addTo(map);
addSelectionToMap(); addObjectToMap();
// 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; geoJson;
latitudeField; addObjectToMap();
longitudeField;
addSelectionToMap();
} }
function createMenu() { function createMenu() {
@@ -208,7 +90,7 @@
icon: 'img map', icon: 'img map',
tabComponent: 'MapTab', tabComponent: 'MapTab',
}, },
{ editor: selection.map(x => _.omit(x, ['engine'])) } { editor: geoJson }
); );
}, },
}, },

View File

@@ -0,0 +1,139 @@
<script lang="ts" context="module">
function findLatLonPaths(obj, attrTest, res = [], prefix = '') {
for (const key of Object.keys(obj)) {
if (attrTest(key, obj[key])) {
res.push(prefix + key);
}
if (_.isPlainObject(obj[key])) {
findLatLonPaths(obj[key], attrTest, res, prefix + key + '.');
}
}
return res;
}
export function findLatPaths(obj) {
return findLatLonPaths(obj, x => x.includes('lat'));
}
export function findLonPaths(obj) {
return findLatLonPaths(obj, x => x.includes('lon') || x.includes('lng'));
}
export function findAllObjectPaths(obj) {
return findLatLonPaths(obj, (_k, v) => v != null && !_.isNaN(Number(v)));
}
export function selectionCouldBeShownOnMap(selection) {
if (selection.length > 0 && _.find(selection, x => isWktGeometry(x.value))) {
return true;
}
if (
selection.length > 0 &&
_.find(selection, x => findLatPaths(x.rowData).length > 0 && findLonPaths(x.rowData).length > 0)
) {
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, stringifyCellValue } 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';
import MapView from './MapView.svelte';
export let selection;
export let latitudeField = '';
export let longitudeField = '';
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>${stringifyCellValue(cell.value)}</td></tr>`)
.join('\n')}</table>`;
}
function createGeoJson() {
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);
const lat = latitudeField ? Number(_.get(cells[0].rowData, latitudeField)) : NaN;
const lon = longitudeField ? Number(_.get(cells[0].rowData, longitudeField)) : NaN;
if (!_.isNaN(lat) && !_.isNaN(lon)) {
features.push({
type: 'Feature',
properties: {
popupContent: createColumnsTable(cells),
},
geometry: {
type: 'Point',
coordinates: [Number(lon), Number(lat)],
},
});
}
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,
};
}
$: {
selection;
latitudeField;
longitudeField;
createGeoJson();
}
</script>
<MapView {geoJson} />

View File

@@ -4,16 +4,16 @@
import useEditorData from '../query/useEditorData'; import useEditorData from '../query/useEditorData';
export let tabid; export let tabid;
let selection; let geoJson;
useEditorData({ useEditorData({
tabid, tabid,
onInitialData: value => { onInitialData: value => {
selection = value; geoJson = value;
}, },
}); });
</script> </script>
{#if selection} {#if geoJson}
<MapView {selection} /> <MapView {geoJson} />
{/if} {/if}

View File

@@ -80,7 +80,7 @@
import TextCellViewNoWrap from '../celldata/TextCellViewNoWrap.svelte'; import TextCellViewNoWrap from '../celldata/TextCellViewNoWrap.svelte';
import TextCellViewWrap from '../celldata/TextCellViewWrap.svelte'; import TextCellViewWrap from '../celldata/TextCellViewWrap.svelte';
import ErrorInfo from '../elements/ErrorInfo.svelte'; import ErrorInfo from '../elements/ErrorInfo.svelte';
import { selectionCouldBeShownOnMap } from '../elements/MapView.svelte'; import { selectionCouldBeShownOnMap } from '../elements/SelectionMapView.svelte';
import SelectField from '../forms/SelectField.svelte'; import SelectField from '../forms/SelectField.svelte';
import { selectedCellsCallback } from '../stores'; import { selectedCellsCallback } from '../stores';
import WidgetTitle from './WidgetTitle.svelte'; import WidgetTitle from './WidgetTitle.svelte';