mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-30 22:03:58 +00:00
map view refactor
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|
||||||
|
|||||||
@@ -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 }
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
139
packages/web/src/elements/SelectionMapView.svelte
Normal file
139
packages/web/src/elements/SelectionMapView.svelte
Normal 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} />
|
||||||
@@ -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}
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
Reference in New Issue
Block a user