mirror of
https://github.com/apache/superset.git
synced 2026-04-19 08:04:53 +00:00
fix(deckgl): fix deckgl multiple layers chart filter and viewport (#33364)
This commit is contained in:
@@ -38,9 +38,20 @@ import {
|
||||
} from '../DeckGLContainer';
|
||||
import { getExploreLongUrl } from '../utils/explore';
|
||||
import layerGenerators from '../layers';
|
||||
import { Viewport } from '../utils/fitViewport';
|
||||
import fitViewport, { Viewport } from '../utils/fitViewport';
|
||||
import { TooltipProps } from '../components/Tooltip';
|
||||
|
||||
import { getPoints as getPointsArc } from '../layers/Arc/Arc';
|
||||
import { getPoints as getPointsPath } from '../layers/Path/Path';
|
||||
import { getPoints as getPointsPolygon } from '../layers/Polygon/Polygon';
|
||||
import { getPoints as getPointsGrid } from '../layers/Grid/Grid';
|
||||
import { getPoints as getPointsScatter } from '../layers/Scatter/Scatter';
|
||||
import { getPoints as getPointsContour } from '../layers/Contour/Contour';
|
||||
import { getPoints as getPointsHeatmap } from '../layers/Heatmap/Heatmap';
|
||||
import { getPoints as getPointsHex } from '../layers/Hex/Hex';
|
||||
import { getPoints as getPointsGeojson } from '../layers/Geojson/Geojson';
|
||||
import { getPoints as getPointsScreengrid } from '../layers/Screengrid/Screengrid';
|
||||
|
||||
export type DeckMultiProps = {
|
||||
formData: QueryFormData;
|
||||
payload: JsonObject;
|
||||
@@ -56,7 +67,35 @@ export type DeckMultiProps = {
|
||||
const DeckMulti = (props: DeckMultiProps) => {
|
||||
const containerRef = useRef<DeckGLContainerHandle>();
|
||||
|
||||
const [viewport, setViewport] = useState<Viewport>();
|
||||
const getAdjustedViewport = useCallback(() => {
|
||||
let viewport = { ...props.viewport };
|
||||
const points = [
|
||||
...getPointsPolygon(props.payload.data.features.deck_polygon || []),
|
||||
...getPointsPath(props.payload.data.features.deck_path || []),
|
||||
...getPointsGrid(props.payload.data.features.deck_grid || []),
|
||||
...getPointsScatter(props.payload.data.features.deck_scatter || []),
|
||||
...getPointsContour(props.payload.data.features.deck_contour || []),
|
||||
...getPointsHeatmap(props.payload.data.features.deck_heatmap || []),
|
||||
...getPointsHex(props.payload.data.features.deck_hex || []),
|
||||
...getPointsArc(props.payload.data.features.deck_arc || []),
|
||||
...getPointsGeojson(props.payload.data.features.deck_geojson || []),
|
||||
...getPointsScreengrid(props.payload.data.features.deck_screengrid || []),
|
||||
];
|
||||
|
||||
if (props.formData) {
|
||||
viewport = fitViewport(viewport, {
|
||||
width: props.width,
|
||||
height: props.height,
|
||||
points,
|
||||
});
|
||||
}
|
||||
if (viewport.zoom < 0) {
|
||||
viewport.zoom = 0;
|
||||
}
|
||||
return viewport;
|
||||
}, [props]);
|
||||
|
||||
const [viewport, setViewport] = useState<Viewport>(getAdjustedViewport());
|
||||
const [subSlicesLayers, setSubSlicesLayers] = useState<Record<number, Layer>>(
|
||||
{},
|
||||
);
|
||||
@@ -70,23 +109,31 @@ const DeckMulti = (props: DeckMultiProps) => {
|
||||
|
||||
const loadLayers = useCallback(
|
||||
(formData: QueryFormData, payload: JsonObject, viewport?: Viewport) => {
|
||||
setViewport(viewport);
|
||||
setViewport(getAdjustedViewport());
|
||||
setSubSlicesLayers({});
|
||||
payload.data.slices.forEach(
|
||||
(subslice: { slice_id: number } & JsonObject) => {
|
||||
// Filters applied to multi_deck are passed down to underlying charts
|
||||
// note that dashboard contextual information (filter_immune_slices and such) aren't
|
||||
// taken into consideration here
|
||||
const filters = [
|
||||
...(subslice.form_data.filters || []),
|
||||
...(formData.filters || []),
|
||||
const extra_filters = [
|
||||
...(subslice.form_data.extra_filters || []),
|
||||
...(formData.extra_filters || []),
|
||||
...(formData.extra_form_data?.filters || []),
|
||||
];
|
||||
|
||||
const adhoc_filters = [
|
||||
...(formData.adhoc_filters || []),
|
||||
...(subslice.formData?.adhoc_filters || []),
|
||||
...(formData.extra_form_data?.adhoc_filters || []),
|
||||
];
|
||||
|
||||
const subsliceCopy = {
|
||||
...subslice,
|
||||
form_data: {
|
||||
...subslice.form_data,
|
||||
filters,
|
||||
extra_filters,
|
||||
adhoc_filters,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -117,7 +164,13 @@ const DeckMulti = (props: DeckMultiProps) => {
|
||||
},
|
||||
);
|
||||
},
|
||||
[props.datasource, props.onAddFilter, props.onSelect, setTooltip],
|
||||
[
|
||||
props.datasource,
|
||||
props.onAddFilter,
|
||||
props.onSelect,
|
||||
setTooltip,
|
||||
getAdjustedViewport,
|
||||
],
|
||||
);
|
||||
|
||||
const prevDeckSlices = usePrevious(props.formData.deck_slices);
|
||||
@@ -136,7 +189,7 @@ const DeckMulti = (props: DeckMultiProps) => {
|
||||
<DeckGLContainerStyledWrapper
|
||||
ref={containerRef}
|
||||
mapboxApiAccessToken={payload.data.mapboxApiKey}
|
||||
viewport={viewport || props.viewport}
|
||||
viewport={viewport}
|
||||
layers={layers}
|
||||
mapStyle={formData.mapbox_style}
|
||||
setControlValue={setControlValue}
|
||||
|
||||
@@ -29,7 +29,7 @@ import TooltipRow from '../../TooltipRow';
|
||||
import { TooltipProps } from '../../components/Tooltip';
|
||||
import { Point } from '../../types';
|
||||
|
||||
function getPoints(data: JsonObject[]) {
|
||||
export function getPoints(data: JsonObject[]) {
|
||||
const points: Point[] = [];
|
||||
data.forEach(d => {
|
||||
points.push(d.sourcePosition);
|
||||
|
||||
@@ -97,7 +97,7 @@ export const getLayer: getLayerType<unknown> = function (
|
||||
});
|
||||
};
|
||||
|
||||
function getPoints(data: any[]) {
|
||||
export function getPoints(data: any[]) {
|
||||
return data.map(d => d.position);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ import { commonLayerProps } from '../common';
|
||||
import TooltipRow from '../../TooltipRow';
|
||||
import fitViewport, { Viewport } from '../../utils/fitViewport';
|
||||
import { TooltipProps } from '../../components/Tooltip';
|
||||
import { Point } from '../../types';
|
||||
|
||||
type ProcessedFeature = Feature<Geometry, GeoJsonProperties> & {
|
||||
properties: JsonObject;
|
||||
@@ -172,6 +173,17 @@ export type DeckGLGeoJsonProps = {
|
||||
width: number;
|
||||
};
|
||||
|
||||
export function getPoints(data: Point[]) {
|
||||
return data.reduce((acc: Array<any>, feature: any) => {
|
||||
const bounds = geojsonExtent(feature);
|
||||
if (bounds) {
|
||||
return [...acc, [bounds[0], bounds[1]], [bounds[2], bounds[3]]];
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
|
||||
const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => {
|
||||
const containerRef = useRef<DeckGLContainerHandle>();
|
||||
const setTooltip = useCallback((tooltip: TooltipProps['tooltip']) => {
|
||||
@@ -186,24 +198,13 @@ const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => {
|
||||
|
||||
const viewport: Viewport = useMemo(() => {
|
||||
if (formData.autozoom) {
|
||||
const points =
|
||||
payload?.data?.features?.reduce?.(
|
||||
(acc: [number, number, number, number][], feature: any) => {
|
||||
const bounds = geojsonExtent(feature);
|
||||
if (bounds) {
|
||||
return [...acc, [bounds[0], bounds[1]], [bounds[2], bounds[3]]];
|
||||
}
|
||||
|
||||
return acc;
|
||||
},
|
||||
[],
|
||||
) || [];
|
||||
const points = getPoints(payload.data.features) || [];
|
||||
|
||||
if (points.length) {
|
||||
return fitViewport(props.viewport, {
|
||||
width,
|
||||
height,
|
||||
points,
|
||||
points: getPoints(payload.data.features) || [],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ export function getLayer(
|
||||
});
|
||||
}
|
||||
|
||||
function getPoints(data: JsonObject[]) {
|
||||
export function getPoints(data: JsonObject[]) {
|
||||
return data.map(d => d.position);
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ export const getLayer: getLayerType<unknown> = (
|
||||
});
|
||||
};
|
||||
|
||||
function getPoints(data: any[]) {
|
||||
export function getPoints(data: any[]) {
|
||||
return data.map(d => d.position);
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ export function getLayer(
|
||||
});
|
||||
}
|
||||
|
||||
function getPoints(data: JsonObject[]) {
|
||||
export function getPoints(data: JsonObject[]) {
|
||||
return data.map(d => d.position);
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ export function getLayer(
|
||||
});
|
||||
}
|
||||
|
||||
function getPoints(data: JsonObject[]) {
|
||||
export function getPoints(data: JsonObject[]) {
|
||||
let points: Point[] = [];
|
||||
data.forEach(d => {
|
||||
points = points.concat(d.path);
|
||||
|
||||
@@ -173,6 +173,10 @@ export type DeckGLPolygonProps = {
|
||||
height: number;
|
||||
};
|
||||
|
||||
export function getPoints(data: JsonObject[]) {
|
||||
return data.flatMap(getPointsFromPolygon);
|
||||
}
|
||||
|
||||
const DeckGLPolygon = (props: DeckGLPolygonProps) => {
|
||||
const containerRef = useRef<DeckGLContainerHandle>();
|
||||
|
||||
@@ -183,7 +187,7 @@ const DeckGLPolygon = (props: DeckGLPolygonProps) => {
|
||||
viewport = fitViewport(viewport, {
|
||||
width: props.width,
|
||||
height: props.height,
|
||||
points: features.flatMap(getPointsFromPolygon),
|
||||
points: getPoints(features),
|
||||
});
|
||||
}
|
||||
if (viewport.zoom < 0) {
|
||||
|
||||
@@ -30,7 +30,7 @@ import TooltipRow from '../../TooltipRow';
|
||||
import { unitToRadius } from '../../utils/geo';
|
||||
import { TooltipProps } from '../../components/Tooltip';
|
||||
|
||||
function getPoints(data: JsonObject[]) {
|
||||
export function getPoints(data: JsonObject[]) {
|
||||
return data.map(d => d.position);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ import {
|
||||
} from '../../DeckGLContainer';
|
||||
import { TooltipProps } from '../../components/Tooltip';
|
||||
|
||||
function getPoints(data: JsonObject[]) {
|
||||
export function getPoints(data: JsonObject[]) {
|
||||
return data.map(d => d.position);
|
||||
}
|
||||
|
||||
|
||||
@@ -1532,7 +1532,31 @@ class DeckGLMultiLayer(BaseViz):
|
||||
|
||||
slice_ids = self.form_data.get("deck_slices")
|
||||
slices = db.session.query(Slice).filter(Slice.id.in_(slice_ids)).all()
|
||||
|
||||
features: dict[str, list[Any]] = {}
|
||||
|
||||
for slc in slices:
|
||||
form_data = slc.form_data
|
||||
|
||||
form_data["extra_filters"] = self.form_data.get("extra_filters", [])
|
||||
form_data["extra_form_data"] = self.form_data.get("extra_form_data", {})
|
||||
form_data["adhoc_filters"] = self.form_data.get("adhoc_filters")
|
||||
|
||||
viz_type_name = form_data.get("viz_type")
|
||||
viz_class = viz_types.get(viz_type_name)
|
||||
if not viz_class:
|
||||
continue # skip unknown viz types
|
||||
|
||||
viz_instance = viz_class(datasource=slc.datasource, form_data=form_data)
|
||||
payload = viz_instance.get_payload()
|
||||
|
||||
if payload and "data" in payload and "features" in payload["data"]:
|
||||
if viz_type_name not in features:
|
||||
features[viz_type_name] = []
|
||||
features[viz_type_name].extend(payload["data"]["features"])
|
||||
|
||||
return {
|
||||
"features": features,
|
||||
"mapboxApiKey": config["MAPBOX_API_KEY"],
|
||||
"slices": [slc.data for slc in slices],
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user