Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions src/reducers/src/ui-state-updaters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ import {
MAP_CONTROLS
} from '@kepler.gl/constants';
import {LOCALE_CODES} from '@kepler.gl/localization';
import {createNotification, errorNotification, calculateExportImageSize} from '@kepler.gl/utils';
import {
createNotification,
errorNotification,
calculateExportImageSize,
getApplicationConfig
} from '@kepler.gl/utils';
import {payload_, apply_, compose_} from './composer-helpers';

import {
Expand Down Expand Up @@ -128,7 +133,7 @@ export const DEFAULT_MAP_CONTROLS: MapControls = (
* @property imageDataUri Default: `''`,
* @property exporting Default: `false`
* @property error Default: `false`
* @property escapeXhtmlForWebpack Default: `true`
* @property escapeXhtmlForWebpack Default: from application config (auto-detected: `true` for webpack)
* @public
*/
export const DEFAULT_EXPORT_IMAGE: ExportImage = {
Expand All @@ -153,8 +158,10 @@ export const DEFAULT_EXPORT_IMAGE: ExportImage = {
// processing: used as loading indicator when export image is being produced
processing: false,
error: false,
// whether to apply fix for uglify error in dom-to-image (should be true for webpack builds)
escapeXhtmlForWebpack: true
// whether to apply fix for uglify error in dom-to-image (from application config, auto-detects build tool)
get escapeXhtmlForWebpack() {
return getApplicationConfig().escapeXhtmlForWebpack;
}
};

Comment thread
igorDykhta marked this conversation as resolved.
Outdated
export const DEFAULT_LOAD_FILES = {
Expand Down
1 change: 0 additions & 1 deletion src/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@
"mapbox-gl": "^1.13.1",
"maplibre-gl": "^3.6.2",
"maplibregl-mapbox-request-transformer": "^0.0.2",
"mini-svg-data-uri": "^1.0.3",
"moment": "^2.10.6",
"moment-timezone": "^0.5.35",
"react": "^18.2.0",
Expand Down
18 changes: 17 additions & 1 deletion src/utils/src/application-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ import type {BaseMapLibraryType} from '@kepler.gl/constants';

import type {DatabaseAdapter} from './application-config-types';

/**
* Detect if running with webpack build tool
Comment thread
igorDykhta marked this conversation as resolved.
*/
function isWebpackBuild(): boolean {
// @ts-ignore - __webpack_require__ is injected by webpack at runtime
Comment thread
igorDykhta marked this conversation as resolved.
return typeof __webpack_require__ !== 'undefined';
}

export type MapLibInstance = MapLib<any>;
export type GetMapRef = ReturnType<MapRef['getMap']>;

Expand Down Expand Up @@ -74,6 +82,10 @@ export type KeplerApplicationConfig = {
// WMS layer config -- Experimental
// WMS layer is under development and not ready for production use. Disabled by default.
enableWMSLayer?: boolean;

// Image export config
/** Whether to apply fix for uglify error in dom-to-image (should be true for webpack builds, false for Vite) */
escapeXhtmlForWebpack?: boolean;
};

const DEFAULT_APPLICATION_CONFIG: Required<KeplerApplicationConfig> = {
Expand Down Expand Up @@ -126,7 +138,11 @@ const DEFAULT_APPLICATION_CONFIG: Required<KeplerApplicationConfig> = {
rasterServerMaxPerServerRequests: 0,

// WMS layer config
enableWMSLayer: true
enableWMSLayer: true,

// Image export config
// Default to true for webpack builds, false for other build tools (e.g., Vite)
escapeXhtmlForWebpack: isWebpackBuild()
};

const applicationConfig: Required<KeplerApplicationConfig> = DEFAULT_APPLICATION_CONFIG;
Expand Down
24 changes: 18 additions & 6 deletions src/utils/src/dom-to-image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import Window from 'global/window';
import document from 'global/document';
import Console from 'global/console';
import svgToMiniDataURI from 'mini-svg-data-uri';
import {IMAGE_EXPORT_ERRORS} from '@kepler.gl/constants';

import {
Expand Down Expand Up @@ -246,11 +245,24 @@ function makeSvgDataUri(node, width, height, escapeXhtmlForWebpack = true) {
const foreignObject = `<foreignObject x="0" y="0" width="100%" height="100%">${xhtml}</foreignObject>`;
const svgStr = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">${foreignObject}</svg>`;

// Optimizing SVGs in data URIs
// see https://codepen.io/tigt/post/optimizing-svgs-in-data-uris
// the best way of encoding SVG in a data: URI is data:image/svg+xml,[actual data].
// We don’t need the ;charset=utf-8 parameter because the given SVG is ASCII.
return svgToMiniDataURI(svgStr);
// Use base64 encoding
let base64Svg: string;
if (typeof Buffer !== 'undefined' && Buffer.from) {
base64Svg = Buffer.from(svgStr, 'utf8').toString('base64');
} else if (typeof TextEncoder !== 'undefined') {
// Modern browsers: TextEncoder handles Unicode → UTF-8 bytes
// Must chunk to avoid call stack limits with large arrays
const bytes = new TextEncoder().encode(svgStr);
Comment thread
igorDykhta marked this conversation as resolved.
const CHUNK_SIZE = 8192;
let binary = '';
for (let i = 0; i < bytes.length; i += CHUNK_SIZE) {
binary += String.fromCharCode.apply(null, Array.from(bytes.slice(i, i + CHUNK_SIZE)));
}
base64Svg = Window.btoa(binary);
Comment thread
igorDykhta marked this conversation as resolved.
} else {
throw new Error('No base64 encoder found');
Comment thread
igorDykhta marked this conversation as resolved.
}
return `data:image/svg+xml;base64,${base64Svg}`;
});
}

Expand Down
10 changes: 0 additions & 10 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5372,7 +5372,6 @@ __metadata:
mapbox-gl: "npm:^1.13.1"
maplibre-gl: "npm:^3.6.2"
maplibregl-mapbox-request-transformer: "npm:^0.0.2"
mini-svg-data-uri: "npm:^1.0.3"
moment: "npm:^2.10.6"
moment-timezone: "npm:^0.5.35"
react: "npm:^18.2.0"
Expand Down Expand Up @@ -22938,15 +22937,6 @@ __metadata:
languageName: node
linkType: hard

"mini-svg-data-uri@npm:^1.0.3":
version: 1.4.4
resolution: "mini-svg-data-uri@npm:1.4.4"
bin:
mini-svg-data-uri: cli.js
checksum: 10c0/24545fa30b5a45449241bf19c25b8bc37594b63ec06401b3d563bd1c2e8a6abb7c18741f8b354e0064baa63c291be214154bf3a66f201ae71dfab3cc1a5e3191
languageName: node
linkType: hard

"minimalistic-assert@npm:^1.0.0, minimalistic-assert@npm:^1.0.1":
version: 1.0.1
resolution: "minimalistic-assert@npm:1.0.1"
Expand Down