Skip to content
Snippets Groups Projects

feat(mapvis): export png from mapvis

Merged Marcos Pieras requested to merge feat/exportMapVis into main
1 file
+ 56
7
Compare changes
  • Side-by-side
  • Inline
import React, { useEffect, useCallback, useState, useRef } from 'react';
import DeckGL from '@deck.gl/react';
import React, { useEffect, useCallback, useState, useRef, forwardRef, useImperativeHandle } from 'react';
import DeckGL, { DeckGLProps, DeckGLRef } from '@deck.gl/react';
import { CompositeLayer, FlyToInterpolator, WebMercatorViewport } from '@deck.gl/core';
import { CompositeLayerType, Coordinate, LayerSettingsType, LocationInfo, SearchResultType } from './mapvis.types';
import { VISComponentType, VisualizationPropTypes } from '../../common';
@@ -30,7 +30,7 @@ const INITIAL_VIEW_STATE = {
const FLY_SPEED = 1000;
export const MapVis = (props: VisualizationPropTypes<MapProps>) => {
export const MapVis = forwardRef((props: VisualizationPropTypes<MapProps>, refExternal) => {
const ref = useRef<HTMLDivElement>(null);
const baseLayer = useRef(createBaseMap());
const [viewport, setViewport] = useState<Record<string, any>>(INITIAL_VIEW_STATE);
@@ -42,6 +42,50 @@ export const MapVis = (props: VisualizationPropTypes<MapProps>) => {
const [searchResult, setSearchResult] = useState<SearchResultType | undefined>(undefined);
const coordinateLookup = useCoordinateLookup(props.data.nodes, props.settings.location);
const [shouldExport, setShouldExport] = useState<boolean>(false);
const captureImage = () => {
const canvas = ref.current?.querySelector('canvas');
if (canvas) {
canvas.toBlob((blob) => {
if (blob) {
const link = document.createElement('a');
link.download = 'map-visualization.png';
link.href = URL.createObjectURL(blob);
link.click();
} else {
console.error('Failed to capture canvas');
}
}, 'image/png');
} else {
console.error('Canvas element not found');
}
};
const exportImageInternal = () => {
requestAnimationFrame(() => {
captureImage();
props.updateSettings({ export2PNG: false });
});
};
// !FIXME I have to wrap exportImageInternal() with a useEffect otherwise didnt work, by just calling exportImageInternal() from outside
useEffect(() => {
if (props.settings.export2PNG) {
exportImageInternal();
}
}, [props.settings.export2PNG]);
useEffect(() => {
if (shouldExport) {
exportImageInternal();
setShouldExport(false);
}
}, [shouldExport]);
useImperativeHandle(refExternal, () => ({
exportImageInternal: () => setShouldExport(true),
}));
const getFittedViewport = useCallback(
(minLat: number, maxLat: number, minLon: number, maxLon: number) => {
@@ -228,17 +272,22 @@ export const MapVis = (props: VisualizationPropTypes<MapProps>) => {
<Attribution />
</div>
);
};
});
const mapRef = React.createRef<{ exportImageInternal: () => void }>();
const MapComponent: VISComponentType<MapProps> = {
displayName: 'MapVis',
description: 'Geographical Features',
component: MapVis,
component: React.forwardRef((props: VisualizationPropTypes<MapProps>, ref) => <MapVis {...props} ref={mapRef} />),
settingsComponent: MapSettings,
settings: settings,
exportImage: () => {
alert('Not yet supported');
if (mapRef.current) {
mapRef.current.exportImageInternal();
} else {
console.error('Map reference is not set.');
}
},
};
export default MapComponent;
Loading