mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-23 16:16:02 +00:00
map - show geometry in MySQL
This commit is contained in:
@@ -483,6 +483,22 @@ export abstract class GridDisplay {
|
||||
|
||||
processReferences(select: Select, displayedColumnInfo: DisplayedColumnInfo, options) {}
|
||||
|
||||
createColumnExpression(col, source, alias?) {
|
||||
let expr = null;
|
||||
if (this.dialect.createColumnViewExpression) {
|
||||
expr = this.dialect.createColumnViewExpression(col.columnName, col.dataType, source, alias);
|
||||
if (expr) {
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
return {
|
||||
exprType: 'column',
|
||||
alias: alias || col.columnName,
|
||||
source,
|
||||
...col,
|
||||
};
|
||||
}
|
||||
|
||||
createSelectBase(name: NamedObjectInfo, columns: ColumnInfo[], options) {
|
||||
if (!columns) return null;
|
||||
const orderColumnName = columns[0].columnName;
|
||||
@@ -492,12 +508,7 @@ export abstract class GridDisplay {
|
||||
name: _.pick(name, ['schemaName', 'pureName']),
|
||||
alias: 'basetbl',
|
||||
},
|
||||
columns: columns.map(col => ({
|
||||
exprType: 'column',
|
||||
alias: col.columnName,
|
||||
source: { alias: 'basetbl' },
|
||||
...col,
|
||||
})),
|
||||
columns: columns.map(col => this.createColumnExpression(col, { alias: 'basetbl' })),
|
||||
orderBy: [
|
||||
{
|
||||
exprType: 'column',
|
||||
|
||||
@@ -267,12 +267,9 @@ export class TableGridDisplay extends GridDisplay {
|
||||
) {
|
||||
for (const column of columns) {
|
||||
if (this.addAllExpandedColumnsToSelected || this.config.addedColumns.includes(column.uniqueName)) {
|
||||
select.columns.push({
|
||||
exprType: 'column',
|
||||
columnName: column.columnName,
|
||||
alias: column.uniqueName,
|
||||
source: { name: column, alias: parentAlias },
|
||||
});
|
||||
select.columns.push(
|
||||
this.createColumnExpression(column, { name: column, alias: parentAlias }, column.uniqueName)
|
||||
);
|
||||
displayedColumnInfo[column.uniqueName] = {
|
||||
...column,
|
||||
sourceAlias: parentAlias,
|
||||
|
||||
@@ -84,3 +84,18 @@ export function getIconForRedisType(type) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function isWktGeometry(s) {
|
||||
if (!_isString(s)) return false;
|
||||
|
||||
return (
|
||||
s.startsWith('POINT(') ||
|
||||
s.startsWith('LINESTRING(') ||
|
||||
s.startsWith('POLYGON(') ||
|
||||
s.startsWith('MULTIPOINT(') ||
|
||||
s.startsWith('MULTILINESTRING(') ||
|
||||
s.startsWith('MULTIPOLYGON(') ||
|
||||
s.startsWith('GEOMCOLLECTION(') ||
|
||||
s.startsWith('GEOMETRYCOLLECTION(')
|
||||
);
|
||||
}
|
||||
|
||||
3
packages/types/dialect.d.ts
vendored
3
packages/types/dialect.d.ts
vendored
@@ -34,4 +34,7 @@ export interface SqlDialect {
|
||||
disableExplicitTransaction?: boolean;
|
||||
|
||||
predefinedDataTypes: string[];
|
||||
|
||||
// create sql-tree expression
|
||||
createColumnViewExpression(columnName: string, dataType: string, source: { alias: string }, alias?: string): any;
|
||||
}
|
||||
|
||||
@@ -57,6 +57,8 @@
|
||||
"dependencies": {
|
||||
"chartjs-plugin-zoom": "^1.2.0",
|
||||
"date-fns": "^2.28.0",
|
||||
"interval-operations": "^1.0.7"
|
||||
"interval-operations": "^1.0.7",
|
||||
"leaflet": "^1.8.0",
|
||||
"wellknown": "^0.5.0"
|
||||
}
|
||||
}
|
||||
|
||||
111
packages/web/src/celldata/MapCellView.svelte
Normal file
111
packages/web/src/celldata/MapCellView.svelte
Normal file
@@ -0,0 +1,111 @@
|
||||
<script lang="ts">
|
||||
import _ from 'lodash';
|
||||
import { onMount } from 'svelte';
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
import leaflet from 'leaflet';
|
||||
import wellknown from 'wellknown';
|
||||
import { isWktGeometry } from 'dbgate-tools';
|
||||
|
||||
// import Map from 'ol/Map';
|
||||
// import View from 'ol/View';
|
||||
// import TileLayer from 'ol/layer/Tile';
|
||||
// import XYZ from 'ol/source/XYZ';
|
||||
|
||||
export let selection;
|
||||
export let wrap;
|
||||
|
||||
let refContainer;
|
||||
let map;
|
||||
|
||||
let selectionLayers = [];
|
||||
|
||||
function addSelectionToMap() {
|
||||
if (!map) return;
|
||||
if (!selection) return;
|
||||
|
||||
for (const selectionLayer of selectionLayers) {
|
||||
selectionLayer.remove();
|
||||
}
|
||||
selectionLayers = [];
|
||||
|
||||
const geoValues = selection.map(x => x.value).filter(isWktGeometry);
|
||||
|
||||
if (geoValues.length > 0) {
|
||||
// parse WKT to geoJSON array
|
||||
const geometries = geoValues.map(wellknown);
|
||||
const geoJson = {
|
||||
type: 'GeometryCollection',
|
||||
geometries,
|
||||
};
|
||||
|
||||
const geoJsonObj = leaflet
|
||||
.geoJSON(geoJson, {
|
||||
style: function () {
|
||||
return {
|
||||
weight: 2,
|
||||
fillColor: '#ff7800',
|
||||
color: '#ff7800',
|
||||
opacity: 0.8,
|
||||
fillOpacity: 0.4,
|
||||
};
|
||||
},
|
||||
pointToLayer: function (feature, latlng) {
|
||||
return leaflet.circleMarker(latlng, {
|
||||
radius: 7,
|
||||
weight: 2,
|
||||
fillColor: '#ff7800',
|
||||
color: '#ff7800',
|
||||
opacity: 0.8,
|
||||
fillOpacity: 0.4,
|
||||
});
|
||||
},
|
||||
})
|
||||
.addTo(map);
|
||||
map.fitBounds(geoJsonObj.getBounds());
|
||||
selectionLayers.push(geoJsonObj);
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
// new Map({
|
||||
// target: refContainer,
|
||||
// layers: [
|
||||
// new TileLayer({
|
||||
// source: new XYZ({
|
||||
// url: 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
// }),
|
||||
// }),
|
||||
// ],
|
||||
// view: new View({
|
||||
// center: [0, 0],
|
||||
// zoom: 2,
|
||||
// }),
|
||||
// });
|
||||
|
||||
map = leaflet.map(refContainer); // .setView([51.505, -0.09], 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();
|
||||
}
|
||||
</script>
|
||||
|
||||
<div bind:this={refContainer} class="flex1" />
|
||||
@@ -1,4 +1,6 @@
|
||||
<script lang="ts" context="module">
|
||||
import { isWktGeometry } from 'dbgate-tools';
|
||||
|
||||
const formats = [
|
||||
{
|
||||
type: 'textWrap',
|
||||
@@ -36,12 +38,31 @@
|
||||
component: HtmlCellView,
|
||||
single: false,
|
||||
},
|
||||
{
|
||||
type: 'map',
|
||||
title: 'Map',
|
||||
component: MapCellView,
|
||||
single: false,
|
||||
},
|
||||
];
|
||||
|
||||
function autodetect(selection) {
|
||||
if (selection[0]?.engine?.databaseEngineTypes?.includes('document')) {
|
||||
return 'jsonRow';
|
||||
}
|
||||
|
||||
if (selection.length > 0 && _.every(selection, x => isWktGeometry(x.value))) {
|
||||
return 'map';
|
||||
}
|
||||
|
||||
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 'map';
|
||||
}
|
||||
|
||||
const value = selection.length == 1 ? selection[0].value : null;
|
||||
if (_.isString(value)) {
|
||||
if (value.startsWith('[') || value.startsWith('{')) return 'json';
|
||||
@@ -62,6 +83,7 @@
|
||||
import HtmlCellView from '../celldata/HtmlCellView.svelte';
|
||||
import JsonCellView from '../celldata/JsonCellView.svelte';
|
||||
import JsonRowView from '../celldata/JsonRowView.svelte';
|
||||
import MapCellView from '../celldata/MapCellView.svelte';
|
||||
import PictureCellView from '../celldata/PictureCellView.svelte';
|
||||
import TextCellViewNoWrap from '../celldata/TextCellViewNoWrap.svelte';
|
||||
import TextCellViewWrap from '../celldata/TextCellViewWrap.svelte';
|
||||
|
||||
Reference in New Issue
Block a user