mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
map - show geometry in MySQL
This commit is contained in:
parent
0a0ce6ad98
commit
343cf84a58
@ -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';
|
||||
|
@ -2,6 +2,18 @@ const { driverBase } = global.DBGATE_TOOLS;
|
||||
const { mysqlSplitterOptions } = require('dbgate-query-splitter/lib/options');
|
||||
const Dumper = require('./Dumper');
|
||||
|
||||
const spatialTypes = [
|
||||
'POINT',
|
||||
'LINESTRING',
|
||||
'POLYGON',
|
||||
'GEOMETRY',
|
||||
'MULTIPOINT',
|
||||
'MULTILINESTRING',
|
||||
'MULTIPOLYGON',
|
||||
'GEOMCOLLECTION',
|
||||
'GEOMETRYCOLLECTION',
|
||||
];
|
||||
|
||||
/** @type {import('dbgate-types').SqlDialect} */
|
||||
const dialect = {
|
||||
rangeSelect: true,
|
||||
@ -68,6 +80,23 @@ const dialect = {
|
||||
'time',
|
||||
'year',
|
||||
],
|
||||
|
||||
createColumnViewExpression(columnName, dataType, source, alias) {
|
||||
if (dataType && spatialTypes.includes(dataType.toUpperCase())) {
|
||||
return {
|
||||
exprType: 'call',
|
||||
func: 'ST_AsText',
|
||||
alias: alias || columnName,
|
||||
args: [
|
||||
{
|
||||
exprType: 'column',
|
||||
columnName,
|
||||
source,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const mysqlDriverBase = {
|
||||
|
46
yarn.lock
46
yarn.lock
@ -2956,6 +2956,15 @@ concat-stream@^1.5.0:
|
||||
readable-stream "^2.2.2"
|
||||
typedarray "^0.0.6"
|
||||
|
||||
concat-stream@~1.5.0:
|
||||
version "1.5.2"
|
||||
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266"
|
||||
integrity sha512-H6xsIBfQ94aESBG8jGHXQ7i5AEpy5ZeVaLDOisDICiTCKpqEfr34/KmTrspKQNoLKNu9gTkovlpQcUi630AKiQ==
|
||||
dependencies:
|
||||
inherits "~2.0.1"
|
||||
readable-stream "~2.0.0"
|
||||
typedarray "~0.0.5"
|
||||
|
||||
concurrently@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-5.1.0.tgz#05523986ba7aaf4b58a49ddd658fab88fa783132"
|
||||
@ -6993,6 +7002,11 @@ lcid@^2.0.0:
|
||||
dependencies:
|
||||
invert-kv "^2.0.0"
|
||||
|
||||
leaflet@^1.8.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.8.0.tgz#4615db4a22a304e8e692cae9270b983b38a2055e"
|
||||
integrity sha512-gwhMjFCQiYs3x/Sf+d49f10ERXaEFCPr+nVTryhAW8DWbMGqJqt9G4XuIaHmFW08zYvhgdzqXGr8AlW8v8dQkA==
|
||||
|
||||
left-pad@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e"
|
||||
@ -7520,6 +7534,11 @@ minimist@^1.2.3, minimist@^1.2.5:
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||
|
||||
minimist@~1.2.0:
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
|
||||
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
|
||||
|
||||
minipass-collect@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617"
|
||||
@ -8841,6 +8860,11 @@ printj@~1.1.0, printj@~1.1.2:
|
||||
resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222"
|
||||
integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==
|
||||
|
||||
process-nextick-args@~1.0.6:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
|
||||
integrity sha512-yN0WQmuCX63LP/TMvAg31nvT6m4vDqJEiiv2CAZqWOGNWutc9DfDk1NPYYmKUFmaVM2UwDowH4u5AHWYP/jxKw==
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
|
||||
@ -9156,6 +9180,18 @@ readable-stream@~1.1.9:
|
||||
isarray "0.0.1"
|
||||
string_decoder "~0.10.x"
|
||||
|
||||
readable-stream@~2.0.0:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e"
|
||||
integrity sha512-TXcFfb63BQe1+ySzsHZI/5v1aJPCShfqvWJ64ayNImXMsN1Cd0YGk/wm8KB7/OeessgPc9QvS9Zou8QTkFzsLw==
|
||||
dependencies:
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.1"
|
||||
isarray "~1.0.0"
|
||||
process-nextick-args "~1.0.6"
|
||||
string_decoder "~0.10.x"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
readdirp@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
|
||||
@ -10960,7 +10996,7 @@ typedarray-to-buffer@^3.1.5:
|
||||
dependencies:
|
||||
is-typedarray "^1.0.0"
|
||||
|
||||
typedarray@^0.0.6:
|
||||
typedarray@^0.0.6, typedarray@~0.0.5:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
||||
@ -11332,6 +11368,14 @@ webpack@^4.42.0:
|
||||
watchpack "^1.6.0"
|
||||
webpack-sources "^1.4.1"
|
||||
|
||||
wellknown@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/wellknown/-/wellknown-0.5.0.tgz#09ae9871fa826cf0a6ec1537ef00c379d78d7101"
|
||||
integrity sha1-Ca6YcfqCbPCm7BU37wDDedeNcQE=
|
||||
dependencies:
|
||||
concat-stream "~1.5.0"
|
||||
minimist "~1.2.0"
|
||||
|
||||
whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3, whatwg-encoding@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0"
|
||||
|
Loading…
Reference in New Issue
Block a user