Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(widgets): New ScaleWidget #9491

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors

import {Deck} from '@deck.gl/core';
import {Deck, PickingInfo} from '@deck.gl/core';
import {GeoJsonLayer, ArcLayer} from '@deck.gl/layers';
import {
CompassWidget,
ZoomWidget,
FullscreenWidget,
ScreenshotWidget,
ResetViewWidget,
ScaleWidget,
DarkGlassTheme,
LightGlassTheme
} from '@deck.gl/widgets';
Expand All @@ -33,7 +34,7 @@ const INITIAL_VIEW_STATE = {
pitch: 30
};

new Deck({
const deck = new Deck({
initialViewState: INITIAL_VIEW_STATE,
controller: true,
layers: [
Expand All @@ -59,10 +60,7 @@ new Deck({
getFillColor: [200, 0, 80, 180],
// Interactive props
pickable: true,
autoHighlight: true,
onClick: info =>
// eslint-disable-next-line
info.object && alert(`${info.object.properties.name} (${info.object.properties.abbrev})`)
autoHighlight: true
}),
new ArcLayer({
id: 'arcs',
Expand All @@ -81,6 +79,7 @@ new Deck({
new CompassWidget({style: widgetTheme}),
new FullscreenWidget({style: widgetTheme}),
new ScreenshotWidget({style: widgetTheme}),
new ResetViewWidget({style: widgetTheme})
new ResetViewWidget({style: widgetTheme}),
new ScaleWidget({style: widgetTheme, placement: 'bottom-left'})
]
});
2 changes: 1 addition & 1 deletion examples/get-started/pure-js/widgets/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
</style>
</head>
<body></body>
<script type="module" src="app.js"></script>
<script type="module" src="app.ts"></script>
</html>
2 changes: 2 additions & 0 deletions modules/widgets/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ export {CompassWidget} from './compass-widget';
export {ZoomWidget} from './zoom-widget';
export {ScreenshotWidget} from './screenshot-widget';
export {ResetViewWidget} from './reset-view-widget';
export {ScaleWidget} from './scale-widget';

export type {FullscreenWidgetProps} from './fullscreen-widget';
export type {CompassWidgetProps} from './compass-widget';
export type {ZoomWidgetProps} from './zoom-widget';
export type {ScreenshotWidgetProps} from './screenshot-widget';
export type {ResetViewWidgetProps} from './reset-view-widget';
export type {ScaleWidgetProps} from './scale-widget';

export type {WidgetImplProps} from './widget-impl';
export {WidgetImpl as _WidgetImpl} from './widget-impl';
Expand Down
101 changes: 101 additions & 0 deletions modules/widgets/src/scale-widget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// deck.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors

/* global document */
import type {WidgetPlacement, Viewport} from '@deck.gl/core';
import {render} from 'preact';
import {WidgetImpl, WidgetImplProps} from './widget-impl';
import {IconButton} from './components';

/** Properties for the ScaleWidget */
export type ScaleWidgetProps = WidgetImplProps & {
/** Widget positioning within the view. Default 'top-left'. */
placement?: WidgetPlacement;
/** Tooltip message */
label?: string;
/** Callback, if defined user overrides the capture logic */
onCapture?: (widget: ScaleWidget) => void;
};

/**
* A button widget that display a scale
*/
export class ScaleWidget extends WidgetImpl<ScaleWidgetProps> {
static defaultProps: Required<ScaleWidgetProps> = {
...WidgetImpl.defaultProps,
id: 'scale',
placement: 'top-left',
label: 'Scale',
onCapture: undefined!
};

className = 'deck-widget-scale';
placement: WidgetPlacement = 'top-left';

scaleText = '';
scaleWidth = 10;

constructor(props: ScaleWidgetProps = {}) {
super({...ScaleWidget.defaultProps, ...props});
this.placement = props.placement ?? this.placement;
}

setProps(props: Partial<ScaleWidgetProps>) {
this.placement = props.placement ?? this.placement;
super.setProps(props);
}

onRenderHTML() {
const element = this.element;
if (!element) return;
render(
<div
className="deck-widget-scale"
style={{width: this.scaleWidth}}
onClick={this.handleClick.bind(this)}
>
{this.scaleText}
</div>,
element
);
}

onViewportChange?(viewport: Viewport): void {
// TODO - handle non-geospatial viewports
if (!('latitude' in viewport)) {
return;
}
const {latitude, zoom} = viewport as any;
const metersPerPixel = getMetersPerPixel(latitude, zoom);

// Define a fixed pixel width for the scale bar (for example, 100px)
const scaleBarPixelWidth = 100;
const distanceMeters = metersPerPixel * scaleBarPixelWidth;

// Format the distance for display (switching to kilometers if large)
let distanceText;
if (distanceMeters >= 1000) {
distanceText = `${(distanceMeters / 1000).toFixed(2)} km`;
} else {
distanceText = `${Math.round(distanceMeters)} m`;
}

this.scaleText = distanceText;
this.scaleWidth = scaleBarPixelWidth;

this.onRenderHTML();
}

handleClick() {}
}

// Function to compute meters per pixel at a given latitude and zoom
// For Web Mercator: resolution (m/px) = (Earth Circumference * cos(latitude)) / (2^(zoom+8))
function getMetersPerPixel(latitude, zoom) {
const earthCircumference = 40075016.686; // in meters
return (earthCircumference * Math.cos((latitude * Math.PI) / 180)) / Math.pow(2, zoom + 8);
}

// Update the scale indicator widget based on the current viewState
function updateScaleIndicator(viewState) {}
10 changes: 10 additions & 0 deletions modules/widgets/src/stylesheet.css
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,13 @@
);
}

.deck-widget .deck-widget-scale {
background-color: var(--button-icon-idle, #616166);
background-position: 50%;
display: block;
}

.deck-widget .deck-widget-geolocate {
pointer-events: auto;
cursor: pointer;
}
Loading