Skip to content

Commit

Permalink
update VectorTile to support wq.db's MVT server
Browse files Browse the repository at this point in the history
  • Loading branch information
sheppard committed Feb 9, 2024
1 parent 2cf4d59 commit 8849220
Show file tree
Hide file tree
Showing 9 changed files with 282 additions and 51 deletions.
27 changes: 13 additions & 14 deletions packages/map-gl-web/src/overlays/VectorTile.js
@@ -1,5 +1,6 @@
import React, { useMemo, useState, useEffect } from "react";
import PropTypes from "prop-types";
import { useStyleProp } from "@wq/map";
import { Source, Layer } from "react-map-gl";

function AutoLayer({ id, active, before, layout = {}, paint = {}, ...rest }) {
Expand All @@ -15,19 +16,17 @@ function AutoLayer({ id, active, before, layout = {}, paint = {}, ...rest }) {
return <Layer beforeId={before} {...layer} {...rest} />;
}

export default function VectorTile({ name, active, before, url, style }) {
if (url) {
return (
<UrlVectorTile
name={name}
active={active}
url={url}
before={before}
/>
);
export default function VectorTile(props) {
if (props.url) {
return <UrlVectorTile {...props} />;
} else {
return <StyleVectorTile {...props} />;
}
}

function StyleVectorTile(props) {
const { sources, layers } = useStyleProp(props);

const { sources, layers } = style;
if (!sources || !layers) {
return null;
}
Expand All @@ -40,8 +39,8 @@ export default function VectorTile({ name, active, before, url, style }) {
{layers.map((layer) => (
<AutoLayer
key={layer.id}
active={active}
before={before}
active={props.active}
before={props.before}
{...layer}
/>
))}
Expand All @@ -62,7 +61,7 @@ function UrlVectorTile({ name, active, before, url }) {

if (style) {
return (
<VectorTile
<StyleVectorTile
name={name}
active={active}
before={before}
Expand Down
36 changes: 33 additions & 3 deletions packages/map/src/components/AutoMap.js
@@ -1,4 +1,4 @@
import React from "react";
import React, { useMemo } from "react";
import { useComponents, usePlugin } from "@wq/react";
import { useMapState, useOverlayComponents } from "../hooks.js";
import PropTypes from "prop-types";
Expand Down Expand Up @@ -36,8 +36,35 @@ export default function AutoMap({
return null;
}

const { basemaps, overlays, initBounds, mapProps, autoZoom, highlight } =
state;
const {
basemaps,
overlays,
initBounds,
tiles,
mapProps,
autoZoom,
highlight,
} = state;

const defaultTileSource = useMemo(() => {
if (!tiles) {
return null;
}
const origin = tiles.startsWith("/") ? window.location.origin : "";
return {
name: "Default Tile Source",
type: "vector-tile",
style: {
sources: {
_default: {
type: "vector",
tiles: [origin + tiles],
},
},
layers: [],
},
};
}, [tiles]);

const identify = overlays.some((overlay) => !!overlay.popup);

Expand Down Expand Up @@ -82,6 +109,9 @@ export default function AutoMap({
<MapIdentify name={name} mapId={mapId} context={context} />
)}
<MapLayers>
{defaultTileSource && (
<AutoOverlay active {...defaultTileSource} />
)}
{basemaps.map((conf) => (
<AutoBasemap key={conf.name} {...conf} />
))}
Expand Down
3 changes: 3 additions & 0 deletions packages/map/src/components/MapLayers.js
Expand Up @@ -25,6 +25,9 @@ MapLayers.propTypes = {
};

export function MapLayer({ element }) {
if (!element || !element.type) {
return null;
}
const type = element.type.isAutoBasemap ? "Basemap" : "Overlay",
{ name, active } = element.props;
return (
Expand Down
4 changes: 1 addition & 3 deletions packages/map/src/components/OverlayToggle.js
Expand Up @@ -18,9 +18,7 @@ export default function OverlayToggle({ name, legend, active, setActive }) {
onValueChange={setActive}
/>
)}
description={
active && legend ? () => <Legend legend={legend} /> : null
}
description={active && legend ? <Legend legend={legend} /> : null}
>
{name}
</ListItem>
Expand Down
174 changes: 174 additions & 0 deletions packages/map/src/hooks.js
Expand Up @@ -8,6 +8,8 @@ import {
useApp,
useComponents,
usePluginComponentMap,
useModel,
useReverse,
} from "@wq/react";
import Mustache from "mustache";

Expand Down Expand Up @@ -168,6 +170,7 @@ export function routeMapConf(config, routeInfo, context = {}) {
...((conf[mode] || { maps: {} }).maps[mapname] || {}),
basemaps: config.basemaps.map(checkGroupLayers),
bounds: config.bounds,
tiles: config.tiles,
};

if (config.mapProps) {
Expand Down Expand Up @@ -576,3 +579,174 @@ export function useGeolocation() {
},
};
}

export function useStyleProp({ name, style, layer, color, icon }) {
return useMemo(() => {
if (!style && !layer) {
console.warn(`Specify style or layer for "${name}"`);
return { sources: {}, layers: [] };
}
if (typeof layer === "string") {
layer = { id: layer, "source-layer": layer };
}
if (style) {
return style;
} else if (icon) {
return {
sources: {},
layers: makeSymbolLayers(layer, icon),
};
} else if (color) {
return {
sources: {},
layers: makeColorLayers(layer, color),
};
} else {
return {
sources: {},
layers: makeColorLayers(layer, "#3388ff", "#3086cc"),
};
}
}, [name, style, layer, color, icon]);
}

function makeSymbolLayers(layer, icon) {
const { id, ["source-layer"]: sourceLayer, ...rest } = layer;
return [
{
id: id,
source: "_default",
"source-layer": sourceLayer || id,
type: "symbol",
layout: {
"icon-image": icon,
"icon-allow-overlap": true,
},
...rest,
},
];
}

function makeColorLayers(layer, color, pointColor = color) {
const { id, ["source-layer"]: sourceLayer, ...rest } = layer;
return [
{
id: `${id}-fill`,
source: "_default",
"source-layer": sourceLayer || id,
type: "fill",
paint: {
"fill-color": color,
"fill-opacity": [
"match",
["geometry-type"],
["Polygon", "MultiPolygon"],
0.2,
0,
],
},
...rest,
},
{
id: `${id}-line`,
source: "_default",
"source-layer": sourceLayer || id,
type: "line",
paint: {
"line-width": 3,
"line-color": color,
"line-opacity": 1,
},
...rest,
},
{
id: `${id}-circle`,
source: "_default",
"source-layer": sourceLayer || id,
type: "circle",
paint: {
"circle-color": "white",
"circle-radius": [
"match",
["geometry-type"],
["Point", "MultiPoint"],
3,
0,
],
"circle-stroke-color": pointColor,
"circle-stroke-width": [
"match",
["geometry-type"],
["Point", "MultiPoint"],
3,
0,
],
"circle-opacity": [
"match",
["geometry-type"],
["Point", "MultiPoint"],
1,
0,
],
},
...rest,
},
];
}

export function useFeatureValues(feature, modelConf) {
const slug = feature.properties[modelConf.lookup] || feature.id,
form = modelConf.form || [{ name: "label" }],
emptyForm = makeEmptyForm(form),
app = useApp(),
modelData = useModel(modelConf.name, slug),
[fetchData, setFetchData] = useState({});

useEffect(() => {
loadData();
async function loadData() {
const data = await app.models[modelConf.name].find(slug);
if (data) {
setFetchData(data);
}
}
}, [app, modelConf, slug]);

return {
...emptyForm,
...feature.properties,
...fetchData,
...modelData,
};
}

function makeEmptyForm(form) {
const values = {};
for (const field of form) {
if (field.name === "" && field.type === "group") {
Object.assign(values, makeEmptyForm(field.children));
} else if (field.type === "group") {
values[field.name] = makeEmptyForm(field.children);
} else {
values[field.name] = "-";
}
}
return values;
}

export function useFeatureUrl(feature, modelConf, mode = "edit") {
const slug = feature.properties[modelConf.lookup] || feature.id,
reverse = useReverse(),
authState = usePluginState("auth"),
perms =
authState &&
authState.config &&
authState.config.pages &&
authState.config.pages[modelConf.name];

if ((perms && perms.can_change) || mode !== "edit") {
return reverse(`${modelConf.name}_${mode}`, slug);
} else {
return null;
}
}
9 changes: 8 additions & 1 deletion packages/map/src/index.js
Expand Up @@ -12,6 +12,9 @@ import {
asFeatureCollection,
computeBounds,
useGeolocation,
useStyleProp,
useFeatureValues,
useFeatureUrl,
} from "./hooks.js";
import {
AutoMap,
Expand All @@ -27,7 +30,7 @@ import {
} from "./components/index.js";
import { Geo } from "./inputs/index.js";
import { GeoHelp, GeoLocate, GeoCode, GeoCoords } from "./geotools/index.js";
import { DefaultList, DefaultDetail } from "./views/index.js";
import { DefaultList, DefaultDetail, DefaultPopup } from "./views/index.js";

export default map;

Expand All @@ -44,6 +47,9 @@ export {
asFeatureCollection,
computeBounds,
useGeolocation,
useStyleProp,
useFeatureValues,
useFeatureUrl,
AutoMap,
AutoBasemap,
AutoOverlay,
Expand All @@ -61,4 +67,5 @@ export {
GeoCoords,
DefaultList,
DefaultDetail,
DefaultPopup,
};
3 changes: 3 additions & 0 deletions packages/map/src/reducer.js
Expand Up @@ -57,6 +57,7 @@ export default function reducer(state = {}, action, config) {
),
viewState,
initBounds: conf.bounds,
tiles: conf.tiles,
autoZoom: conf.autoZoom,
mapProps: conf.mapProps,
highlight: isSameView ? highlight : null,
Expand Down Expand Up @@ -304,6 +305,7 @@ function reduceMapState(state) {
overlays,
viewState,
initBounds,
tiles,
autoZoom,
mapProps,
highlight,
Expand All @@ -320,6 +322,7 @@ function reduceMapState(state) {
overlays,
viewState,
initBounds,
tiles,
autoZoom,
mapProps,
highlight,
Expand Down

0 comments on commit 8849220

Please sign in to comment.