diff --git a/docs/examples/deck-arc-layer.vue b/docs/examples/deck-arc-layer.vue new file mode 100644 index 0000000..54aeda7 --- /dev/null +++ b/docs/examples/deck-arc-layer.vue @@ -0,0 +1,50 @@ +// Deck Arc Layer +// +// A Deck.gl Arc Layer Example + + + + + + \ No newline at end of file diff --git a/docs/examples/deck-geojson-layer.vue b/docs/examples/deck-geojson-layer.vue new file mode 100644 index 0000000..ac7d31c --- /dev/null +++ b/docs/examples/deck-geojson-layer.vue @@ -0,0 +1,54 @@ +// Deck Geojson Layer +// +// A Deck.gl Geojson Layer Example + + + + + + \ No newline at end of file diff --git a/docs/examples/deck-line-layer.vue b/docs/examples/deck-line-layer.vue new file mode 100644 index 0000000..6e1efc1 --- /dev/null +++ b/docs/examples/deck-line-layer.vue @@ -0,0 +1,101 @@ +// Deck Line Layer +// +// A Deck.gl Line Layer Example. + + + + + diff --git a/docs/examples/deck-polygon-layer.vue b/docs/examples/deck-polygon-layer.vue new file mode 100644 index 0000000..e2de968 --- /dev/null +++ b/docs/examples/deck-polygon-layer.vue @@ -0,0 +1,58 @@ +// Deck Polygon Layer +// +// A Deck.gl Polygon Layer Example. + + + + + diff --git a/docs/examples/deck-scatteredplot-layer.vue b/docs/examples/deck-scatteredplot-layer.vue new file mode 100644 index 0000000..aa52df7 --- /dev/null +++ b/docs/examples/deck-scatteredplot-layer.vue @@ -0,0 +1,45 @@ +// Deck Scattered Plot Layer +// +// A Deck.gl Scattered Plot Layer Example + + + + + + diff --git a/lib/components/deck-layers/arc.layer.ts b/lib/components/deck-layers/arc.layer.ts new file mode 100644 index 0000000..bdce11e --- /dev/null +++ b/lib/components/deck-layers/arc.layer.ts @@ -0,0 +1,31 @@ +import { defineComponent } from "vue"; +import { ArcLayer, type ArcLayerProps } from "@deck.gl/layers"; +import { useDeckLayer } from "@/lib/composable/useDeckLayer"; +import { type PickingInfo } from "@deck.gl/core"; +import { + arcProps, + arcPropsKeys, + genDeckLayerOpts, + type TooltipContent, +} from "@/lib/lib/deck.layer.lib"; + +/** + * Deck.gl Arc Layer + * + * See the [Deck.gl Arc Layer docs ](https://deck.gl/docs/api-reference/layers/arc-layer) + */ +export default defineComponent({ + name: "MglDeckArcLayer", + props: { + ...arcProps(), + }, + setup(props) { + const opts = { ...props } as ArcLayerProps & { + getTooltip?: ((info: PickingInfo) => TooltipContent) | null; + }; + return useDeckLayer( + opts, + new ArcLayer(genDeckLayerOpts({ ...opts }, arcPropsKeys)), + ); + }, +}); diff --git a/lib/components/deck-layers/geojson.layer.ts b/lib/components/deck-layers/geojson.layer.ts new file mode 100644 index 0000000..37b9808 --- /dev/null +++ b/lib/components/deck-layers/geojson.layer.ts @@ -0,0 +1,32 @@ +import { defineComponent } from "vue"; +import { GeoJsonLayer, type GeoJsonLayerProps } from "@deck.gl/layers"; +import { useDeckLayer } from "@/lib/composable/useDeckLayer"; +import { type PickingInfo } from "@deck.gl/core"; +import { + genDeckLayerOpts, + geojsonProps, + geoJsonPropsKeys, + type TooltipContent, +} from "@/lib/lib/deck.layer.lib"; + +/** + * Deck.gl Geojson Layer + * + * See the [Deck.gl Geojson Layer docs](https://deck.gl/docs/api-reference/layers/geojson-layer) + */ +export default defineComponent({ + name: "MglDeckGeojsonLayer", + props: { + ...geojsonProps(), + }, + setup(props) { + const opts = { ...props } as GeoJsonLayerProps & { + getTooltip?: ((info: PickingInfo) => TooltipContent) | null; + }; + + return useDeckLayer( + opts, + new GeoJsonLayer(genDeckLayerOpts({ ...opts }, geoJsonPropsKeys)), + ); + }, +}); diff --git a/lib/components/deck-layers/line.layer.ts b/lib/components/deck-layers/line.layer.ts new file mode 100644 index 0000000..11d564a --- /dev/null +++ b/lib/components/deck-layers/line.layer.ts @@ -0,0 +1,31 @@ +import { defineComponent } from "vue"; +import { LineLayer, type LineLayerProps } from "@deck.gl/layers"; +import { useDeckLayer } from "@/lib/composable/useDeckLayer"; +import { type PickingInfo } from "@deck.gl/core"; +import { + genDeckLayerOpts, + lineProps, + linePropsKeys, + type TooltipContent, +} from "@/lib/lib/deck.layer.lib"; + +/** + * Deck.gl Line Layer + * + * See the [Deck.gl Line Layer docs](https://deck.gl/docs/api-reference/layers/line-layer) + */ +export default defineComponent({ + name: "MglDeckLineLayer", + props: { + ...lineProps(), + }, + setup(props) { + const opts = { ...props } as LineLayerProps & { + getTooltip?: ((info: PickingInfo) => TooltipContent) | null; + }; + return useDeckLayer( + opts, + new LineLayer(genDeckLayerOpts({ ...opts }, linePropsKeys)), + ); + }, +}); diff --git a/lib/components/deck-layers/polygon.layer.ts b/lib/components/deck-layers/polygon.layer.ts new file mode 100644 index 0000000..2658bab --- /dev/null +++ b/lib/components/deck-layers/polygon.layer.ts @@ -0,0 +1,31 @@ +import { defineComponent } from "vue"; +import { PolygonLayer, type PolygonLayerProps } from "@deck.gl/layers"; +import { useDeckLayer } from "@/lib/composable/useDeckLayer"; +import { type PickingInfo } from "@deck.gl/core"; +import { + genDeckLayerOpts, + polygonProps, + polygonPropsKeys, + type TooltipContent, +} from "@/lib/lib/deck.layer.lib"; + +/** + * Deck.gl Polygon Layer + * + * See the [Deck.gl Polygon Layer docs](https://deck.gl/docs/api-reference/layers/polygon-layer) + */ +export default defineComponent({ + name: "MglDeckPolygonLayer", + props: { + ...polygonProps(), + }, + setup(props) { + const opts = { ...props } as PolygonLayerProps & { + getTooltip?: ((info: PickingInfo) => TooltipContent) | null; + }; + return useDeckLayer( + opts, + new PolygonLayer(genDeckLayerOpts({ ...opts }, polygonPropsKeys)), + ); + }, +}); diff --git a/lib/components/deck-layers/scatteredPlot.layer.ts b/lib/components/deck-layers/scatteredPlot.layer.ts new file mode 100644 index 0000000..4ab7391 --- /dev/null +++ b/lib/components/deck-layers/scatteredPlot.layer.ts @@ -0,0 +1,33 @@ +import { defineComponent } from "vue"; +import { ScatterplotLayer, type ScatterplotLayerProps } from "@deck.gl/layers"; +import { useDeckLayer } from "@/lib/composable/useDeckLayer"; +import { type PickingInfo } from "@deck.gl/core"; +import { + genDeckLayerOpts, + scatteredPlotProps, + scatteredPlotPropsKeys, + type TooltipContent, +} from "@/lib/lib/deck.layer.lib"; + +/** + * Deck.gl ScatteredPlot Layer + * + * See the [Deck.gl ScatteredPlot Layer docs](https://deck.gl/docs/api-reference/layers/scatterplot-layer) + */ +export default defineComponent({ + name: "MglDeckScatteredPlotLayer", + props: { + ...scatteredPlotProps(), + }, + setup(props) { + const opts = { ...props } as ScatterplotLayerProps & { + getTooltip?: ((info: PickingInfo) => TooltipContent) | null; + }; + return useDeckLayer( + opts, + new ScatterplotLayer( + genDeckLayerOpts({ ...opts }, scatteredPlotPropsKeys), + ), + ); + }, +}); diff --git a/lib/components/index.ts b/lib/components/index.ts index 4b2f25d..22726ee 100644 --- a/lib/components/index.ts +++ b/lib/components/index.ts @@ -24,3 +24,11 @@ export { default as MglHillshadeLayer } from "./layers/hillshade.layer"; export { default as MglLineLayer } from "./layers/line.layer"; export { default as MglRasterLayer } from "./layers/raster.layer"; export { default as MglSymbolLayer } from "./layers/symbol.layer"; + +// deck layers +export { default as MglDeckGeojsonLayer } from "./deck-layers/geojson.layer"; +export { default as MglDeckArcLayer } from "./deck-layers/arc.layer"; +export { default as MglDeckLineLayer } from "./deck-layers/line.layer"; +export { default as MglDeckScatteredPlotLayer } from "./deck-layers/scatteredPlot.layer"; +export { default as MglDeckPolygonLayer } from "./deck-layers/polygon.layer"; + diff --git a/lib/composable/useDeckLayer.ts b/lib/composable/useDeckLayer.ts new file mode 100644 index 0000000..be813b1 --- /dev/null +++ b/lib/composable/useDeckLayer.ts @@ -0,0 +1,55 @@ +import type { + DeckLayer, + DeckLayerProps, + TooltipContent, +} from "@/lib/lib/deck.layer.lib"; +import { + createCommentVNode, + inject, + onBeforeUnmount, + ref, + warn, + watch, +} from "vue"; +import { isLoadedSymbol, mapSymbol } from "@/lib/types"; +import { MapboxOverlay } from "@deck.gl/mapbox"; +import type { PickingInfo } from "@deck.gl/core"; + +export function useDeckLayer( + props: DeckLayerProps & { + getTooltip?: ((info: PickingInfo) => TooltipContent) | null; + }, + layerConstructor: DeckLayer, +) { + const map = inject(mapSymbol)!; + const isLoaded = inject(isLoadedSymbol)!; + const overlay = ref(); + + if (!map) { + warn(`Deck.gl layers require a Deck.gl map instance.`); + return; + } + + function addLayer() { + overlay.value = new MapboxOverlay({ + layers: [layerConstructor], + getTooltip: props.getTooltip + ? (f: PickingInfo) => props.getTooltip!(f) + : undefined, + }); + + map.value!.addControl(overlay.value); + } + + watch(isLoaded, (il) => { + if (il) { + addLayer(); + } + }); + + onBeforeUnmount(() => { + map.value!.removeControl(overlay.value); + }); + + return () => createCommentVNode(`${props.id} Deck Layer`); +} diff --git a/lib/lib/deck.layer.lib.ts b/lib/lib/deck.layer.lib.ts new file mode 100644 index 0000000..54f825a --- /dev/null +++ b/lib/lib/deck.layer.lib.ts @@ -0,0 +1,890 @@ +import type { + ArcLayerProps, + GeoJsonLayerProps, + BitmapLayerProps, + ColumnLayerProps, + LineLayerProps, + PolygonLayerProps, + ScatterplotLayerProps, + PathLayerProps, + IconLayerProps, + ArcLayer, + ColumnLayer, + GeoJsonLayer, + BitmapLayer, + LineLayer, + PolygonLayer, + ScatterplotLayer, + PathLayer, + IconLayer, +} from "@deck.gl/layers"; + +import { type ComponentPropsOptions, type PropType } from "vue"; +import { + COORDINATE_SYSTEM, + LayerExtension, + type PickingInfo, + type Color, + type Unit, + type Position, + type LayerProps, + type LayerData, + type Accessor, + type Material, AccessorFunction +} from "@deck.gl/core"; +import type { MjolnirEvent } from "mjolnir.js"; +import type { Feature, Geometry, Polygon } from "geojson"; + +export type DeckLayer = + | ArcLayer + | GeoJsonLayer + | BitmapLayer + | ColumnLayer + | LineLayer + | PolygonLayer + | ScatterplotLayer + | PathLayer + | IconLayer; + +export type DeckLayerProps = + | ArcLayerProps + | GeoJsonLayerProps + | BitmapLayerProps + | ColumnLayerProps + | LineLayerProps + | PolygonLayerProps + | ScatterplotLayerProps + | PathLayerProps + | IconLayerProps; + +export type PointType = + | "circle" + | "icon" + | "text" + | "circle+icon" + | "circle+text" + | "icon+text" + | "icon+circle" + | "text+circle" + | "text+icon"; + +export type TooltipContent = + | null + | string + | { + text?: string; + html?: string; + className?: string; + style?: Partial; + }; + +export const baseLayerProps: ComponentPropsOptions = { + // basic props + id: { + type: String as PropType, + required: true, + }, + data: { + type: [Object, String] as PropType, + }, + visible: { + type: Boolean as PropType, + default: true, + }, + opacity: { + type: Number as PropType, + default: 1, + }, + extensions: { + type: Array as PropType, + }, + onError: { + type: Function as unknown as PropType< + ((error: Error) => boolean | void) | null + >, + default: undefined, + }, + + // Interaction Properties + pickable: { + type: Boolean as PropType, + default: false, + }, + onHover: { + type: Function as unknown as PropType< + ((pickingInfo: PickingInfo, event: MjolnirEvent) => boolean | void) | null + >, + default: undefined, + }, + onClick: { + type: Function as unknown as PropType< + ((pickingInfo: PickingInfo, event: MjolnirEvent) => boolean | void) | null + >, + default: undefined, + }, + onDragStart: { + type: Function as unknown as PropType< + ((pickingInfo: PickingInfo, event: MjolnirEvent) => boolean | void) | null + >, + default: undefined, + }, + onDrag: { + type: Function as unknown as PropType< + ((pickingInfo: PickingInfo, event: MjolnirEvent) => boolean | void) | null + >, + default: undefined, + }, + onDragEnd: { + type: Function as unknown as PropType< + ((pickingInfo: PickingInfo, event: MjolnirEvent) => boolean | void) | null + >, + default: undefined, + }, + highlightColor: { + type: [Array, Function] as unknown as PropType< + Color | ((pickingInfo: PickingInfo) => void) + >, + default: () => [0, 0, 128, 128], + }, + highlightedObjectIndex: { + type: [Number, null], + default: null, + }, + autoHighlight: { + type: Boolean, + default: false, + }, + + // Coordinate System Properties + coordinateSystem: { + type: Number, + default: COORDINATE_SYSTEM.DEFAULT, + }, + coordinateOrigin: { + type: Array as unknown as PropType<[number, number, number]>, + default: () => [0, 0, 0], + }, + wrapLongitude: { + type: Boolean, + default: false, + }, + modelMatrix: { + type: Array as PropType, + default: undefined, + }, + + // data properties + dataComparator: { + type: Function as unknown as PropType< + | (>( + newData: LayerDataT, + oldData?: LayerDataT, + ) => boolean) + | null + >, + }, + _dataDiff: { + type: Function as unknown as PropType< + | (>( + newData: LayerDataT, + oldData?: LayerDataT, + ) => { startRow: number; endRow?: number }[]) + | null + >, + }, + dataTransform: { + type: Function as unknown as PropType< + | (>( + data: unknown, + previousData?: LayerDataT, + ) => LayerDataT) + | null + >, + default: undefined, + }, + positionFormat: { + type: String as PropType<"XYZ" | "XY">, + default: "XYZ", + }, + colorFormat: { + type: String as PropType<"RGBA" | "RGB">, + default: "RGBA", + }, + numInstances: { + type: Number as PropType, + default: undefined, + }, + updateTrigger: { + type: Object as PropType>, + }, + + // custom tooltip prop + getTooltip: { + type: Function as unknown as PropType< + ((info: PickingInfo) => TooltipContent) | null + >, + }, +}; +export const baseLayerKeys: (keyof LayerProps)[] = [ + "id", + "data", + "visible", + "opacity", + "extensions", + "onError", + "pickable", + "onHover", + "onClick", + "onDragStart", + "onDrag", + "onDragEnd", + "highlightColor", + "highlightedObjectIndex", + "autoHighlight", + "coordinateSystem", + "coordinateOrigin", + "wrapLongitude", + "modelMatrix", + "dataComparator", + "_dataDiff", + "dataTransform", + "positionFormat", + "colorFormat", + "numInstances", +]; + +export function arcProps(): ComponentPropsOptions { + return { + ...baseLayerProps, + greatCircle: { + type: Boolean as PropType, + default: false, + }, + numSegments: { + type: Number as PropType, + default: 50, + }, + widthUnits: { + type: String as PropType, + default: "pixels", + }, + widthScale: { + type: Number as PropType, + default: 1, + }, + widthMinPixels: { + type: Number as PropType, + default: 0, + }, + widthMaxPixels: { + type: Number as PropType, + default: Number.MAX_SAFE_INTEGER, + }, + getSourcePosition: { + type: Function as unknown as PropType>, + default: (object: { sourcePosition: Position }) => object.sourcePosition, + }, + getTargetPosition: { + type: Function as unknown as PropType>, + default: (object: { targetPosition: Position }) => object.targetPosition, + }, + getSourceColor: { + type: Function as unknown as PropType>, + default: () => [0, 0, 0, 255], + }, + getTargetColor: { + type: Function as unknown as PropType>, + default: () => [0, 0, 0, 255], + }, + getWidth: { + type: Number as PropType>, + default: 1, + }, + getHeight: { + type: Number as PropType>, + default: 1, + }, + getTilt: { + type: Number as PropType>, + default: 0, + }, + }; +} +export const arcPropsKeys: (keyof ArcLayerProps)[] = [ + ...baseLayerKeys, + "greatCircle", + "numSegments", + "widthUnits", + "widthScale", + "widthMinPixels", + "widthMaxPixels", + "getSourcePosition", + "getTargetPosition", + "getSourceColor", + "getTargetColor", + "getWidth", + "getHeight", + "getTilt", +]; + +export function geojsonProps(): ComponentPropsOptions { + return { + ...baseLayerProps, + pointType: { + type: String as PropType, + default: "circle", + }, + // fill color props + filled: { + type: Boolean as PropType, + default: true, + }, + getFillColor: { + type: [Array, Function] as unknown as PropType< + Accessor, Color> + >, + default: () => [0, 0, 0, 255], + }, + // stroke options + stroked: { + type: Boolean as PropType, + default: true, + }, + getLineColor: { + type: [Array, Function] as unknown as PropType< + Accessor, Color> + >, + default: () => [0, 0, 0, 255], + }, + getLineWidth: { + type: [Number, Function] as PropType< + Accessor, number> + >, + default: 1, + }, + lineWidthUnits: { + type: String as PropType, + default: "meters", + }, + lineWidthScale: { + type: Number as PropType, + default: 1, + }, + lineWidthMinPixels: { + type: Number as PropType, + default: 0, + }, + lineWidthMaxPixels: { + type: Number as PropType, + default: Number.MAX_SAFE_INTEGER, + }, + lineCapRounded: { + type: Boolean as PropType, + default: false, + }, + lineJointRounded: { + type: Boolean as PropType, + default: false, + }, + lineMiterLimit: { + type: Number as PropType, + default: 4, + }, + lineBillboard: { + type: Boolean as PropType, + default: false, + }, + // 3D options + extruded: { + type: Boolean as PropType, + default: false, + }, + wireframe: { + type: Boolean as PropType, + default: false, + }, + getElevation: { + type: [Number, Function] as PropType< + Accessor, number> + >, + default: 1000, + }, + elevationScale: { + type: Number as PropType, + default: 1, + }, + material: { + type: [Boolean, Object] as PropType, + default: true, + }, + _full3d: { + type: Boolean as PropType, + default: false, + }, + getPointRadius: { + type: [Number, Function] as PropType< + Accessor, number> + >, + default: 1, + }, + pointRadiusUnits: { + type: String as PropType, + }, + pointRadiusScale: { + type: Number as PropType, + default: 1, + }, + pointRadiusMinPixels: { + type: Number as PropType, + default: 0, + }, + pointRadiusMaxPixels: { + type: Number as PropType, + default: Number.MAX_SAFE_INTEGER, + }, + pointAntialiasing: { + type: Boolean as PropType, + default: true, + }, + pointBillboard: { + type: Boolean as PropType, + default: false, + }, + getText: { + type: Function as PropType, unknown>>, + default: (f: { properties: { text: unknown } }) => f.properties.text, + }, + getTextColor: { + type: [Array, Function] as unknown as PropType< + Accessor, Color> + >, + default: () => [0, 0, 0, 255], + }, + getTextAngle: { + type: Number as PropType, number>>, + default: 0, + }, + + getTextSize: { + type: Number as PropType, number>>, + default: 32, + }, + getTextAnchor: { + type: String as PropType, string>>, + default: "middle", + }, + getTextAlignmentBaseline: { + type: String as PropType, string>>, + default: "center", + }, + getTextPixelOffset: { + type: [Array, Function] as PropType< + Accessor, number[]> + >, + default: () => [0, 0], + }, + getTextBackgroundColor: { + type: [Array, Function] as unknown as PropType< + Accessor, Color> + >, + default: () => [255, 255, 255, 255], + }, + getTextBorderColor: { + type: [Array, Function] as unknown as PropType< + Accessor, Color> + >, + default: () => [0, 0, 0, 255], + }, + getTextBorderWidth: { + type: Number as PropType, number>>, + default: 0, + }, + textSizeUnits: { + type: String as PropType, + default: "pixels", + }, + textSizeScale: { + type: Number as PropType, + default: 1, + }, + textSizeMinPixels: { + type: Number as PropType, + default: 0, + }, + textSizeMaxPixels: { + type: Number as PropType, + default: Number.MAX_SAFE_INTEGER, + }, + textCharacterSet: { + type: [String, Array] as PropType, + }, + textFontFamily: { + type: String as PropType, + default: "Monaco, monospace", + }, + textFontWeight: { + type: [Number, String] as PropType, + default: "normal", + }, + textLineHeight: { + type: Number as PropType, + default: 1, + }, + textMaxWidth: { + type: Number as PropType, + default: -1, + }, + textWordBreak: { + type: String as PropType, + default: "break-word", + }, + textBackground: { + type: Boolean as PropType, + default: false, + }, + textBackgroundPadding: { + type: Array as PropType, + default: () => [0, 0], + }, + textOutlineColor: { + type: Array as unknown as PropType, + default: () => [0, 0, 0, 255], + }, + textOutlineWidth: { + type: Number as PropType, + default: 0, + }, + textBillboard: { + type: Boolean as PropType, + default: true, + }, + textFontSettings: { + type: Object, + }, + }; +} +export const geoJsonPropsKeys: (keyof GeoJsonLayerProps)[] = [ + ...baseLayerKeys, + "pointType", + "filled", + "getFillColor", + "stroked", + "getLineColor", + "getLineWidth", + "lineWidthUnits", + "lineWidthScale", + "lineWidthMinPixels", + "lineWidthMaxPixels", + "lineCapRounded", + "lineJointRounded", + "lineMiterLimit", + "lineBillboard", + "extruded", + "wireframe", + "getElevation", + "elevationScale", + "material", + "_full3d", + "getPointRadius", + "pointRadiusUnits", + "pointRadiusScale", + "pointRadiusMinPixels", + "pointRadiusMaxPixels", + "pointAntialiasing", + "pointBillboard", + "getText", + "getTextColor", + "getTextAngle", + "getTextSize", + "getTextAnchor", + "getTextAlignmentBaseline", + "getTextPixelOffset", + "getTextBackgroundColor", + "getTextBorderColor", + "getTextBorderWidth", + "textSizeUnits", + "textSizeScale", + "textSizeMinPixels", + "textSizeMaxPixels", + "textCharacterSet", + "textFontFamily", + "textFontWeight", + "textLineHeight", + "textMaxWidth", + "textWordBreak", + "textBackground", + "textBackgroundPadding", + "textOutlineColor", + "textOutlineWidth", + "textBillboard", + "textFontSettings", +]; + +export function lineProps(): ComponentPropsOptions { + return { + ...baseLayerProps, + widthUnits: { + type: String as PropType, + default: "pixels", + }, + + widthScale: { + type: Number as PropType, + default: 1, + }, + + widthMinPixels: { + type: Number as PropType, + default: 0, + }, + + widthMaxPixels: { + type: Number as PropType, + default: Number.MAX_SAFE_INTEGER, + }, + getSourcePosition: { + type: Function as unknown as PropType>, + default: (object: { sourcePosition: Position }) => object.sourcePosition, + }, + getTargetPosition: { + type: Function as unknown as PropType>, + default: (object: { targetPosition: Position }) => object.targetPosition, + }, + + getColor: { + type: [Function, Array] as unknown as PropType>, + default: () => [0, 0, 0, 255], + }, + getWidth: { + type: Number as PropType>, + default: 1, + }, + }; +} +export const linePropsKeys: (keyof LineLayerProps)[] = [ + ...baseLayerKeys, + "widthUnits", + "widthScale", + "widthMinPixels", + "widthMaxPixels", + "getSourcePosition", + "getTargetPosition", + "getColor", + "getWidth", +]; + +export function scatteredPlotProps(): ComponentPropsOptions { + return { + ...baseLayerProps, + radiusUnits: { + type: String as PropType, + default: "meters", + }, + radiusScale: { + type: Number as PropType, + default: 1, + }, + lineWidthUnits: { + type: String as PropType, + default: "meters", + }, + lineWidthScale: { + type: Number as PropType, + default: 1, + }, + filled: { + type: Boolean as PropType, + default: true, + }, + stroked: { + type: Boolean as PropType, + default: true, + }, + radiusMinPixels: { + type: Number as PropType, + default: 0, + }, + radiusMaxPixels: { + type: Number as PropType, + default: Number.MAX_SAFE_INTEGER, + }, + lineWidthMinPixels: { + type: Number as PropType, + default: 0, + }, + lineWidthMaxPixels: { + type: Number as PropType, + default: Number.MAX_SAFE_INTEGER, + }, + billboard: { + type: Boolean as PropType, + default: false, + }, + antialiasing: { + type: Boolean as PropType, + default: true, + }, + getPosition: { + type: Function as unknown as PropType>, + default: (object: { position: Position }) => object.position, + }, + getRadius: { + type: [Number, Function] as PropType>, + default: 1, + }, + getColor: { + type: [Function, Array] as unknown as PropType>, + default: () => [0, 0, 0, 255], + }, + getFillColor: { + type: [Array, Function] as unknown as PropType>, + default: () => [0, 0, 0, 255], + }, + getLineColor: { + type: [Array, Function] as unknown as PropType>, + default: () => [0, 0, 0, 255], + }, + getLineWidth: { + type: [Number, Function] as PropType>, + default: 1, + }, + }; +} +export const scatteredPlotPropsKeys: (keyof ScatterplotLayerProps)[] = [ + ...baseLayerKeys, + "radiusUnits", + "radiusScale", + "lineWidthUnits", + "lineWidthScale", + "filled", + "stroked", + "radiusMinPixels", + "radiusMaxPixels", + "lineWidthMinPixels", + "lineWidthMaxPixels", + "billboard", + "antialiasing", + "getPosition", + "getRadius", + "getColor", + "getFillColor", + "getLineColor", + "getLineWidth", +]; + +export function polygonProps(): ComponentPropsOptions { + return { + ...baseLayerProps, + filled: { + type: Boolean as PropType, + default: true, + }, + stroked: { + type: Boolean as PropType, + default: true, + }, + extruded: { + type: Boolean as PropType, + default: false, + }, + wireframe: { + type: Boolean as PropType, + default: false, + }, + elevationScale: { + type: Number as PropType, + default: 1, + }, + lineWidthUnits: { + type: String as PropType, + default: "meters", + }, + lineWidthScale: { + type: Number as PropType, + default: 1, + }, + lineWidthMinPixels: { + type: Number as PropType, + default: 0, + }, + lineWidthMaxPixels: { + type: Number as PropType, + default: Number.MAX_SAFE_INTEGER, + }, + lineJointRounded: { + type: Boolean as PropType, + default: false, + }, + lineMiterLimit: { + type: Number as PropType, + default: 4, + }, + material: { + type: [Boolean, Object] as PropType, + default: true, + }, + _normalize: { + type: Boolean as PropType, + default: true, + }, + _windingOrder: { + type: String as PropType<'CW' | 'CCW'>, + default: "CW", + }, + getPolygon: { + type: Function as PropType>, + default: (object: { polygon: Polygon }) => object.polygon, + }, + getFillColor: { + type: [Array, Function] as unknown as PropType>, + default: () => [0, 0, 0, 255], + }, + getLineColor: { + type: [Array, Function] as unknown as PropType>, + default: () => [0, 0, 0, 255], + }, + getLineWidth: { + type: [Number, Function] as PropType>, + default: 1, + }, + getElevation: { + type: [Number, Function] as PropType>, + default: 1000, + } + }; +} +export const polygonPropsKeys: (keyof PolygonLayerProps)[] = [ + ...baseLayerKeys, + 'filled', + 'stroked', + 'extruded', + 'wireframe', + 'elevationScale', + 'lineWidthUnits', + 'lineWidthScale', + 'lineWidthMinPixels', + 'lineWidthMaxPixels', + 'lineJointRounded', + 'lineMiterLimit', + 'material', + '_normalize', + '_windingOrder', + 'getPolygon', + 'getFillColor', + 'getLineColor', + 'getLineWidth', + 'getElevation' +] + +export function genDeckLayerOpts( + props: T & { getTooltip?: ((info: PickingInfo) => TooltipContent) | null }, + validProps: Array, +): Partial { + for (const opt of Object.keys(props) as Array) { + if (props[opt] === undefined || !validProps.includes(opt)) { + delete props[opt]; + } + } + + return props; +} diff --git a/package.json b/package.json index 0e1be77..fb00a2b 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,9 @@ }, "devDependencies": { "@babel/types": "^7.23.9", + "@deck.gl/core": "^9.0.35", + "@deck.gl/layers": "^9.0.35", + "@deck.gl/mapbox": "^9.0.35", "@eslint/js": "^9.1.1", "@indoorequal/vue-maplibre-gl": "workspace:^", "@maplibre/maplibre-gl-inspect": "^1.7.0", diff --git a/vite.config.ts b/vite.config.ts index dc160a0..1c844c7 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -24,7 +24,7 @@ export default defineConfig({ */`) ], ssr : { - external: [ 'vue', 'maplibre-gl', 'geojson' ] + external: [ 'vue', 'maplibre-gl', 'geojson', '@deck.gl/core', '@deck.gl/layers', '@deck.gl/mapbox' ] }, build : { sourcemap : true, @@ -39,7 +39,10 @@ export default defineConfig({ external: [ 'vue', 'maplibre-gl', - 'geojson' + 'geojson', + '@deck.gl/core', + '@deck.gl/layers', + '@deck.gl/mapbox' ], output : { assetFileNames: (assetInfo) => { @@ -51,7 +54,10 @@ export default defineConfig({ globals: { vue : 'Vue', 'maplibre-gl': 'maplibregl', - geojson : 'geojson' + geojson : 'geojson', + '@deck.gl/core' : 'deckGlCore', + '@deck.gl/layers' : 'deckGlLayers', + '@deck.gl/mapbox' : 'deckGlMapbox' }, }, }