Skip to content
Merged
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
109 changes: 91 additions & 18 deletions apps/react-storybook/stories/map/OSMMap.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,47 @@
import type { Meta, StoryObj } from '@storybook/react-webpack5';
import { useArgs } from 'storybook/preview-api';

import Attribution from 'ol/control/Attribution.js';
import type OpenLayersMap from 'ol/Map.js';
import 'ol/ol.css';
import { fromLonLat, transformExtent } from 'ol/proj.js';
import View from 'ol/View.js';
import React from 'react';
import Map from 'devextreme-react/map';
import type { ReadyEvent } from 'devextreme/ui/map';
import Map, { type MapRef } from 'devextreme-react/map';
import type {
MapLocation,
MapType,
ReadyEvent,
} from 'devextreme/ui/map';
import 'devextreme/ui/map/openlayers';

const CENTER = { lat: 40.7484, lng: -73.9857 };
const CENTRAL_PARK_CENTER = { lat: 40.7829, lng: -73.9654 };
const EXTENT: [number, number, number, number] = [-74.08, 40.67, -73.85, 40.88];
const TILE_SERVER = {
url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
maxZoom: 19,
};
const PROVIDER_CONFIG = { tileServer: TILE_SERVER };
const PROVIDER_CONFIG = { tileServer: () => TILE_SERVER };

interface OsmStoryArgs {
centerOnCentralPark: boolean;
controls: boolean;
disabled: boolean;
focusStateEnabled: boolean;
rtlEnabled: boolean;
type: MapType;
zoom: number;
}

const configureMap = (
interface OsmMapStoryProps extends OsmStoryArgs {
updateArgs: (args: Partial<OsmStoryArgs>) => void;
}

const configureOpenLayersMap = (
{ originalMap }: ReadyEvent,
center: MapLocation,
zoom: number,
): void => {
const map = originalMap as OpenLayersMap;
Expand All @@ -34,36 +51,86 @@ const configureMap = (
attribution?.setCollapsed(false);
attribution?.setCollapsible(false);
map.setView(new View({
center: fromLonLat([CENTER.lng, CENTER.lat]),
center: fromLonLat([center.lng, center.lat]),
extent: transformExtent(EXTENT, 'EPSG:4326', 'EPSG:3857'),
maxZoom: 16,
minZoom: 14,
showFullExtent: false,
smoothExtentConstraint: false,
zoom,
}));
};

const OsmMapStory = ({ zoom }: OsmStoryArgs): React.ReactElement => (
<Map
provider="osm"
providerConfig={PROVIDER_CONFIG}
center={CENTER}
zoom={zoom}
height={520}
width="100%"
onReady={(event) => configureMap(event, zoom)}
/>
);
const OsmMapStory = ({
centerOnCentralPark,
controls,
disabled,
focusStateEnabled,
rtlEnabled,
type,
updateArgs,
zoom,
}: OsmMapStoryProps): React.ReactElement => {
const mapRef = React.useRef<MapRef>(null);
const center = centerOnCentralPark ? CENTRAL_PARK_CENTER : CENTER;

React.useEffect(() => {
mapRef.current?.instance()?.option('center', center);
}, [center]);

return (
<Map
ref={mapRef}
provider="osm"
providerConfig={PROVIDER_CONFIG}
defaultCenter={CENTER}
controls={controls}
disabled={disabled}
focusStateEnabled={focusStateEnabled}
rtlEnabled={rtlEnabled}
type={type}
zoom={zoom}
height={520}
width="100%"
onReady={(event) => configureOpenLayersMap(event, center, zoom)}
onZoomChange={(value) => updateArgs({ zoom: value })}
/>
);
};

const meta: Meta<OsmStoryArgs> = {
title: 'Components/Map/OSM Provider',
component: OsmMapStory,
tags: ['!test'],
render: function Render() {
const [args, updateArgs] = useArgs<OsmStoryArgs>();

return <OsmMapStory {...args} updateArgs={updateArgs} />;
},
parameters: {
layout: 'fullscreen',
},
argTypes: {
centerOnCentralPark: {
control: 'boolean',
description: 'Switches the map center between the default New York location and Central Park.',
},
controls: {
control: 'boolean',
},
disabled: {
control: 'boolean',
},
focusStateEnabled: {
control: 'boolean',
},
rtlEnabled: {
control: 'boolean',
},
type: {
control: 'select',
options: ['roadmap', 'satellite', 'hybrid'],
description: 'The public OSM tile server provides one style, so this control exercises '
+ 'type changes without changing the map appearance.',
},
zoom: {
control: {
type: 'number',
Expand All @@ -81,6 +148,12 @@ type Story = StoryObj<OsmStoryArgs>;

export const Default: Story = {
args: {
centerOnCentralPark: false,
controls: true,
disabled: false,
focusStateEnabled: true,
rtlEnabled: false,
type: 'roadmap',
zoom: 15,
},
};
6 changes: 6 additions & 0 deletions packages/devextreme/js/__internal/ui/map/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,12 @@ class Map extends Widget<MapProperties> {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this._queueAsyncAction('updateDisabled');
break;
case 'focusStateEnabled':
case 'tabIndex':
super._optionChanged(args);
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this._queueAsyncAction('updateFocus');
break;
case 'width':
case 'height':
super._optionChanged(args);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { MapLocation } from '@js/ui/map';

export const SUBDOMAIN_PLACEHOLDER = '{s}';

export interface MapEngineTileLayerOptions {
attribution?: string;
maxZoom: number;
Expand All @@ -12,10 +14,34 @@ export interface MapEngineSetViewOptions {
zoom?: number;
}

export interface MapEngineBounds {
northEast: MapLocation;
southWest: MapLocation;
}

export interface MapEngineViewState extends MapEngineSetViewOptions {
bounds?: MapEngineBounds;
}

export interface MapEngineClickEvent {
event?: Event;
location: MapLocation;
}

export interface MapEngineEventHandlers {
click: (event: MapEngineClickEvent) => void;
viewChange: (view: MapEngineViewState) => void;
}

export interface MapEngineMap {
readonly originalMap: unknown;
attachHandlers: (handlers: MapEngineEventHandlers) => void;
dispose: () => void;
fitBounds: (bounds: MapEngineBounds) => void;
replaceTileLayer: (options: MapEngineTileLayerOptions) => void;
setControls: (visible: boolean) => void;
setDisabled: (disabled: boolean) => void;
setFocus: (enabled: boolean, tabIndex: number) => void;
setView: (options: MapEngineSetViewOptions) => void;
updateDimensions: () => void;
}
Expand Down
Loading
Loading