Skip to content

Commit 02045f0

Browse files
committed
add new resolution options
1 parent efb072e commit 02045f0

5 files changed

Lines changed: 170 additions & 9 deletions

File tree

src/components/src/plot-container.tsx

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,33 @@ const CLASS_FILTER = [
3939
const DOM_FILTER_FUNC = node => !CLASS_FILTER.includes(node.className);
4040
const OUT_OF_SCREEN_POSITION = -9999;
4141

42+
/**
43+
* Calculates legend zoom based on export height
44+
* Maps export height to a zoom factor between 0.5 and 3
45+
* @param height - export height in pixels
46+
* @returns zoom factor for legend panel
47+
*/
48+
function calculateLegendZoom(height: number): number {
49+
const baseHeight = 1080; // 1x zoom reference height
50+
const minZoom = 0.5;
51+
const maxZoom = 3;
52+
53+
// Linear mapping: height / baseHeight gives us the scale
54+
const zoomFactor = height / baseHeight;
55+
56+
// Clamp between min and max
57+
return Math.max(minZoom, Math.min(maxZoom, zoomFactor));
58+
}
59+
4260
PlotContainerFactory.deps = [MapContainerFactory, MapsLayoutFactory];
4361

4462
// Remove mapbox logo in exported map, because it contains non-ascii characters
4563
// Remove split viewport UI controls from exported images when the legend is shown
46-
const StyledPlotContainer = styled.div`
64+
interface StyledPlotContainerProps {
65+
legendZoom?: number;
66+
}
67+
68+
const StyledPlotContainer = styled.div<StyledPlotContainerProps>`
4769
.maplibregl-ctrl-bottom-left,
4870
.maplibregl-ctrl-bottom-right,
4971
.maplibre-attribution-container,
@@ -57,6 +79,11 @@ const StyledPlotContainer = styled.div`
5779
position: absolute;
5880
top: ${OUT_OF_SCREEN_POSITION}px;
5981
left: ${OUT_OF_SCREEN_POSITION}px;
82+
83+
/* Apply zoom to legend panel based on export height */
84+
.map-control-panel {
85+
zoom: ${props => props.legendZoom || 1} !important;
86+
}
6087
`;
6188

6289
interface StyledMapContainerProps {
@@ -153,6 +180,11 @@ export default function PlotContainerFactory(
153180
mapState.isSplit
154181
]);
155182

183+
// Memoize the legend zoom calculation based on export height
184+
const legendZoom = useMemo(() => {
185+
return calculateLegendZoom(imageSize.imageH);
186+
}, [imageSize.imageH]);
187+
156188
// Memoize the map style
157189
const scaledMapStyle = useMemo(() => {
158190
const mapStyle = mapFields.mapStyle;
@@ -312,7 +344,7 @@ export default function PlotContainerFactory(
312344
);
313345

314346
return (
315-
<StyledPlotContainer className="export-map-instance">
347+
<StyledPlotContainer className="export-map-instance" legendZoom={legendZoom}>
316348
<StyledMapContainer ref={plottingAreaRef} width={size.width} height={size.height}>
317349
<MapViewStateContextProvider mapState={newMapState}>
318350
{mapContainers}

src/constants/src/default-settings.ts

Lines changed: 97 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,11 +1025,24 @@ export const EXPORT_IMG_RATIO_OPTIONS: ReadonlyArray<ImageRatioOption> = [
10251025
SixteenByNineRatioOption
10261026
];
10271027

1028+
export type ExportResolutionOption =
1029+
| keyof typeof RESOLUTIONS
1030+
| '1280x720'
1031+
| '1920x1080'
1032+
| '2560x1440'
1033+
| '3840x2160'
1034+
| '1600x900'
1035+
| '1024x768'
1036+
| '1280x960'
1037+
| '1600x1200'
1038+
| '1920x1440'
1039+
| '2048x1536';
1040+
10281041
export type ImageResolutionOption = {
1029-
id: keyof typeof RESOLUTIONS;
1042+
id: ExportResolutionOption;
10301043
label: string;
10311044
available: boolean;
1032-
scale: number;
1045+
scale?: number;
10331046
getSize: (screenW: number, screenH: number) => {width: number; height: number};
10341047
};
10351048

@@ -1055,9 +1068,90 @@ export const TwoXResolutionOption: ImageResolutionOption = {
10551068
})
10561069
};
10571070

1071+
// Fixed dimension options
1072+
export const Resolution1920x1080Option: ImageResolutionOption = {
1073+
id: '1920x1080',
1074+
label: '1920 × 1080 (16:9)',
1075+
available: true,
1076+
getSize: () => ({width: 1920, height: 1080})
1077+
};
1078+
1079+
export const Resolution1280x720Option: ImageResolutionOption = {
1080+
id: '1280x720',
1081+
label: '1280 × 720 (16:9)',
1082+
available: true,
1083+
getSize: () => ({width: 1280, height: 720})
1084+
};
1085+
1086+
export const Resolution2560x1440Option: ImageResolutionOption = {
1087+
id: '2560x1440',
1088+
label: '2560 × 1440 (16:9)',
1089+
available: true,
1090+
getSize: () => ({width: 2560, height: 1440})
1091+
};
1092+
1093+
export const Resolution3840x2160Option: ImageResolutionOption = {
1094+
id: '3840x2160',
1095+
label: '3840 × 2160 (16:9)',
1096+
available: true,
1097+
getSize: () => ({width: 3840, height: 2160})
1098+
};
1099+
1100+
export const Resolution1600x900Option: ImageResolutionOption = {
1101+
id: '1600x900',
1102+
label: '1600 × 900 (16:9)',
1103+
available: true,
1104+
getSize: () => ({width: 1600, height: 900})
1105+
};
1106+
1107+
export const Resolution1024x768Option: ImageResolutionOption = {
1108+
id: '1024x768',
1109+
label: '1024 × 768 (4:3)',
1110+
available: true,
1111+
getSize: () => ({width: 1024, height: 768})
1112+
};
1113+
1114+
export const Resolution1280x960Option: ImageResolutionOption = {
1115+
id: '1280x960',
1116+
label: '1280 × 960 (4:3)',
1117+
available: true,
1118+
getSize: () => ({width: 1280, height: 960})
1119+
};
1120+
1121+
export const Resolution1600x1200Option: ImageResolutionOption = {
1122+
id: '1600x1200',
1123+
label: '1600 × 1200 (4:3)',
1124+
available: true,
1125+
getSize: () => ({width: 1600, height: 1200})
1126+
};
1127+
1128+
export const Resolution1920x1440Option: ImageResolutionOption = {
1129+
id: '1920x1440',
1130+
label: '1920 × 1440 (4:3)',
1131+
available: true,
1132+
getSize: () => ({width: 1920, height: 1440})
1133+
};
1134+
1135+
export const Resolution2048x1536Option: ImageResolutionOption = {
1136+
id: '2048x1536',
1137+
label: '2048 × 1536 (4:3)',
1138+
available: true,
1139+
getSize: () => ({width: 2048, height: 1536})
1140+
};
1141+
10581142
export const EXPORT_IMG_RESOLUTION_OPTIONS: ReadonlyArray<ImageResolutionOption> = [
10591143
OneXResolutionOption,
1060-
TwoXResolutionOption
1144+
TwoXResolutionOption,
1145+
Resolution1280x720Option,
1146+
Resolution1920x1080Option,
1147+
Resolution2560x1440Option,
1148+
Resolution3840x2160Option,
1149+
Resolution1600x900Option,
1150+
Resolution1024x768Option,
1151+
Resolution1280x960Option,
1152+
Resolution1600x1200Option,
1153+
Resolution1920x1440Option,
1154+
Resolution2048x1536Option
10611155
];
10621156

10631157
export const EXPORT_DATA_TYPE = keyMirror({

src/types/reducers.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import {Field, Millisecond} from './types';
55
import type {MapViewState} from '@deck.gl/core/typed';
6+
import type {ExportResolutionOption} from '@kepler.gl/constants';
67

78
export type MapState = {
89
pitch: number;
@@ -372,7 +373,7 @@ export type BaseMapStyle = {
372373

373374
export declare type ExportImage = {
374375
ratio: 'SCREEN' | 'FOUR_BY_THREE' | 'SIXTEEN_BY_NINE' | 'CUSTOM';
375-
resolution: 'ONE_X' | 'TWO_X';
376+
resolution: ExportResolutionOption;
376377
legend: boolean;
377378
mapH: number;
378379
mapW: number;

src/utils/src/export-utils.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import get from 'lodash/get';
77
import {
88
EXPORT_IMG_RESOLUTION_OPTIONS,
99
EXPORT_IMG_RATIO_OPTIONS,
10-
RESOLUTIONS,
1110
EXPORT_IMG_RATIOS,
1211
FourByThreeRatioOption,
13-
OneXResolutionOption
12+
OneXResolutionOption,
13+
type ExportResolutionOption
1414
} from '@kepler.gl/constants';
1515
import {ExportImage} from '@kepler.gl/types';
1616
import {generateHashId} from '@kepler.gl/common-utils';
@@ -47,7 +47,7 @@ export function calculateExportImageSize({
4747
mapW: number;
4848
mapH: number;
4949
ratio: keyof typeof EXPORT_IMG_RATIOS;
50-
resolution: keyof typeof RESOLUTIONS;
50+
resolution: ExportResolutionOption;
5151
}) {
5252
if (mapW <= 0 || mapH <= 0) {
5353
return null;

test/node/utils/export-utils-test.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,40 @@ test('exportUtils -> calculateExportImageSize', t => {
114114
'Should return a correct valid with a non valid resolution param'
115115
);
116116

117+
// Test fixed resolution options
118+
t.deepEqual(
119+
calculateExportImageSize({
120+
mapW: 1440,
121+
mapH: 990,
122+
ratio: EXPORT_IMG_RATIOS.SCREEN,
123+
resolution: '1920x1080'
124+
}),
125+
{scale: undefined, imageW: 1920, imageH: 1080},
126+
'Should return fixed resolution 1920x1080'
127+
);
128+
129+
t.deepEqual(
130+
calculateExportImageSize({
131+
mapW: 1440,
132+
mapH: 990,
133+
ratio: EXPORT_IMG_RATIOS.SCREEN,
134+
resolution: '1280x720'
135+
}),
136+
{scale: undefined, imageW: 1280, imageH: 720},
137+
'Should return fixed resolution 1280x720'
138+
);
139+
140+
t.deepEqual(
141+
calculateExportImageSize({
142+
mapW: 1440,
143+
mapH: 990,
144+
ratio: EXPORT_IMG_RATIOS.SCREEN,
145+
resolution: '2560x1440'
146+
}),
147+
{scale: undefined, imageW: 2560, imageH: 1440},
148+
'Should return fixed resolution 2560x1440'
149+
);
150+
117151
t.end();
118152
});
119153

0 commit comments

Comments
 (0)