Skip to content

Commit

Permalink
Add the ability to drag the MMapRouteControl markers and fix minor bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
MokujinMap committed Jul 16, 2024
1 parent 199648f commit 8778850
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 68 deletions.
35 changes: 32 additions & 3 deletions example/route-control/react/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ async function main() {
const [fromCoords, setFromCoords] = React.useState<LngLat | undefined>();
const [toCoords, setToCoords] = React.useState<LngLat | undefined>();
const [previewCoords, setPreviewCoords] = React.useState<LngLat | undefined>();
const [waypoints, setWaypoints] = React.useState<[LngLat, LngLat]>([LOCATION.center, null]);

const onRouteResult = React.useCallback((result: BaseRouteResponse, type: RouteOptions['type']) => {
setRouteType(type);
Expand Down Expand Up @@ -69,6 +70,20 @@ async function main() {
},
[]
);

const onDragEndHandler = React.useCallback(
(coordinates: LngLat, type: 'from' | 'to') => {
if (type === 'from') {
setFromCoords(coordinates);
setWaypoints([coordinates, toCoords]);
} else {
setToCoords(coordinates);
setWaypoints([fromCoords, coordinates]);
}
},
[fromCoords, toCoords]
);

const features = React.useMemo(() => {
if (!routeResult) {
return null;
Expand Down Expand Up @@ -96,7 +111,7 @@ async function main() {
<MMapControls position="top left">
<MMapRouteControl
truckParameters={TRUCK_PARAMS}
waypoints={[LOCATION.center, null]}
waypoints={waypoints}
onRouteResult={onRouteResult}
onUpdateWaypoints={onUpdateWaypoints}
onBuildRouteError={onBuildRouteError}
Expand All @@ -105,8 +120,22 @@ async function main() {
</MMapControls>

{showFeature && features}
{fromCoords !== undefined && <MMapDefaultMarker coordinates={fromCoords} {...FROM_POINT_STYLE} />}
{toCoords !== undefined && <MMapDefaultMarker coordinates={toCoords} {...TO_POINT_STYLE} />}
{fromCoords !== undefined && (
<MMapDefaultMarker
coordinates={fromCoords}
draggable
onDragEnd={(coordinates) => onDragEndHandler(coordinates, 'from')}
{...FROM_POINT_STYLE}
/>
)}
{toCoords !== undefined && (
<MMapDefaultMarker
coordinates={toCoords}
draggable
onDragEnd={(coordinates) => onDragEndHandler(coordinates, 'to')}
{...TO_POINT_STYLE}
/>
)}
{previewCoords !== undefined && (
<MMapDefaultMarker coordinates={previewCoords} {...PREVIEW_POINT_STYLE} />
)}
Expand Down
110 changes: 60 additions & 50 deletions example/route-control/vanilla/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {BaseRouteResponse, LngLat, MMapFeature, RouteOptions, Stroke} from '@mappable-world/mappable-types';
import type {BaseRouteResponse, LngLat, MMapFeature, RouteOptions} from '@mappable-world/mappable-types';
import type {MMapDefaultMarker} from '../../src';
import {
FROM_POINT_STYLE,
Expand All @@ -24,12 +24,25 @@ async function main() {
new MMapDefaultFeaturesLayer({})
]);

const dragEndHandler = () => {
routeControl.update({
waypoints: [
map.children.includes(fromPoint) ? fromPoint.coordinates : null,
map.children.includes(toPoint) ? toPoint.coordinates : null
]
});
};

const fromPoint: MMapDefaultMarker = new MMapDefaultMarker({
coordinates: map.center as LngLat,
onDragEnd: dragEndHandler,
draggable: true,
...FROM_POINT_STYLE
});
const toPoint: MMapDefaultMarker = new MMapDefaultMarker({
coordinates: map.center as LngLat,
onDragEnd: dragEndHandler,
draggable: true,
...TO_POINT_STYLE
});
let previewPoint: MMapDefaultMarker = new MMapDefaultMarker({
Expand All @@ -39,59 +52,56 @@ async function main() {

let featuresOnMap: MMapFeature[] = [];

map.addChild(
new MMapControls({position: 'top left'}).addChild(
new MMapRouteControl({
truckParameters: TRUCK_PARAMS,
waypoints: [map.center as LngLat, null],
onBuildRouteError() {
featuresOnMap.forEach((f) => map.removeChild(f));
featuresOnMap = [];
},
onRouteResult(result, type) {
featuresOnMap.forEach((f) => map.removeChild(f));
featuresOnMap = getFeatures(result, type);
featuresOnMap.forEach((f) => map.addChild(f));
const routeControl = new MMapRouteControl({
truckParameters: TRUCK_PARAMS,
waypoints: [map.center as LngLat, null],
onBuildRouteError() {
featuresOnMap.forEach((f) => map.removeChild(f));
featuresOnMap = [];
},
onRouteResult(result, type) {
featuresOnMap.forEach((f) => map.removeChild(f));
featuresOnMap = getFeatures(result, type);
featuresOnMap.forEach((f) => map.addChild(f));

const bounds = computeBoundsForPoints(result.toRoute().geometry.coordinates);
map.update({location: {bounds, duration: 500}});
},
onUpdateWaypoints(waypoints) {
const [from, to] = waypoints;
if (from) {
const {coordinates} = from.geometry;
fromPoint.update({coordinates});
map.addChild(fromPoint);
} else {
map.removeChild(fromPoint);
}
const bounds = computeBoundsForPoints(result.toRoute().geometry.coordinates);
map.update({location: {bounds, duration: 500}});
},
onUpdateWaypoints(waypoints) {
const [from, to] = waypoints;
if (from) {
const {coordinates} = from.geometry;
fromPoint.update({coordinates});
map.addChild(fromPoint);
} else {
map.removeChild(fromPoint);
}

if (to) {
const {coordinates} = to.geometry;
toPoint.update({coordinates});
map.addChild(toPoint);
} else {
map.removeChild(toPoint);
}
if (!to && !from) {
featuresOnMap.forEach((f) => map.removeChild(f));
featuresOnMap = [];
}
},
onMouseMoveOnMap(coordinates, index, lastCall) {
if (!lastCall) {
previewPoint.update({coordinates});
if (to) {
const {coordinates} = to.geometry;
toPoint.update({coordinates});
map.addChild(toPoint);
} else {
map.removeChild(toPoint);
}
if (!to || !from) {
featuresOnMap.forEach((f) => map.removeChild(f));
featuresOnMap = [];
}
},
onMouseMoveOnMap(coordinates, index, lastCall) {
if (!lastCall) {
previewPoint.update({coordinates});

if (!map.children.includes(previewPoint)) {
map.addChild(previewPoint);
}
} else {
map.removeChild(previewPoint);
}
if (!map.children.includes(previewPoint)) {
map.addChild(previewPoint);
}
})
)
);
} else {
map.removeChild(previewPoint);
}
}
});
map.addChild(new MMapControls({position: 'top left'}).addChild(routeControl));

const getFeatures = (result: BaseRouteResponse, type: RouteOptions['type']): MMapFeature[] => {
if (type !== 'transit') {
Expand Down
22 changes: 19 additions & 3 deletions example/route-control/vue/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ async function main() {
const fromCoords = Vue.ref<LngLat | undefined>();
const toCoords = Vue.ref<LngLat | undefined>();
const previewCoords = Vue.ref<LngLat | undefined>();
const waypoints = Vue.ref<[LngLat, LngLat]>([LOCATION.center, null]);

const refMap = (ref: any) => {
window.map = ref?.entity;
Expand Down Expand Up @@ -69,6 +70,13 @@ async function main() {
const onMouseMoveOnMap: MMapRouteControlProps['onMouseMoveOnMap'] = (coordinates, index, lastCall) => {
previewCoords.value = lastCall ? undefined : coordinates;
};
const onDragEndHandler = (coordinates: LngLat, type: 'from' | 'to') => {
if (type === 'from') {
waypoints.value = [coordinates, toCoords.value];
} else {
waypoints.value = [fromCoords.value, coordinates];
}
};
const features = Vue.computed(() => {
if (!routeResult) {
return null;
Expand Down Expand Up @@ -105,11 +113,13 @@ async function main() {
fromCoords,
toCoords,
previewCoords,
waypoints,
features,
onRouteResult,
onUpdateWaypoints,
onBuildRouteError,
onMouseMoveOnMap,
onDragEndHandler,
refMap
};
},
Expand All @@ -120,7 +130,7 @@ async function main() {
<MMapControls position="top left">
<MMapRouteControl
:truckParameters="TRUCK_PARAMS"
:waypoints="[LOCATION.center, null]"
:waypoints="waypoints"
:onRouteResult="onRouteResult"
:onUpdateWaypoints="onUpdateWaypoints"
:onBuildRouteError="onBuildRouteError"
Expand All @@ -133,10 +143,16 @@ async function main() {
</template>
<MMapDefaultMarker
v-if="fromCoords !== undefined"
:coordinates="fromCoords" v-bind="FROM_POINT_STYLE" />
:coordinates="fromCoords"
draggable
:onDragEnd="(coordinates) => onDragEndHandler(coordinates, 'from')"
v-bind="FROM_POINT_STYLE" />
<MMapDefaultMarker
v-if="toCoords !== undefined"
:coordinates="toCoords" v-bind="TO_POINT_STYLE" />
:coordinates="toCoords"
draggable
:onDragEnd="(coordinates) => onDragEndHandler(coordinates, 'to')"
v-bind="TO_POINT_STYLE" />
<MMapDefaultMarker
v-if="previewCoords !== undefined"
:coordinates="previewCoords" v-bind="PREVIEW_POINT_STYLE" />
Expand Down
28 changes: 18 additions & 10 deletions src/controls/MMapRouteControl/MMapWaypointInput/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,18 +258,26 @@ export class MMapWaypointInput extends mappable.MMapComplexEntity<MMapWaypointIn
}

private async _search(params: SearchParams, reverseGeocodingCoordinate?: LngLat) {
const searchResult = (await this._props.search?.({params, map: this.root})) ?? (await mappable.search(params));
if (searchResult.length === 0) {
return;
}
try {
const searchResult =
(await this._props.search?.({params, map: this.root})) ?? (await mappable.search(params));

if (searchResult.length === 0) {
return;
}

const feature = searchResult[0];
if (reverseGeocodingCoordinate) {
this._inputEl.value = feature.properties.name;
feature.geometry.coordinates = reverseGeocodingCoordinate;
const feature = searchResult[0];
if (reverseGeocodingCoordinate) {
this._inputEl.value = feature.properties.name;
feature.geometry.coordinates = reverseGeocodingCoordinate;
}
this._updateIndicatorStatus('setted');
this._props.onSelectWaypoint({feature});
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
this._updateIndicatorStatus('empty');
}
this._updateIndicatorStatus('setted');
this._props.onSelectWaypoint({feature});
}

private _onMapMouseLeave = (object: DomEventHandlerObject, event: DomEvent): void => {
Expand Down
18 changes: 16 additions & 2 deletions src/controls/MMapRouteControl/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import debounce from 'lodash/debounce';
import {
BaseRouteResponse,
DomDetach,
Expand All @@ -21,6 +22,7 @@ import {
} from './helpers';
import './index.css';
import {formatDistance, formatDuration} from './utils';
import {MMapRouteControlVuefyOptions} from './vue';

export type WaypointsArray = Array<SelectWaypointArgs['feature'] | null>;

Expand Down Expand Up @@ -59,6 +61,7 @@ type DefaultProps = typeof defaultProps;

export class MMapRouteControl extends mappable.MMapComplexEntity<MMapRouteControlProps, DefaultProps> {
static defaultProps = defaultProps;
static [mappable.optionsKeyVuefy] = MMapRouteControlVuefyOptions;

private _control: MMapControl;
private _router: MMapCommonRouteControl;
Expand All @@ -76,6 +79,10 @@ export class MMapRouteControl extends mappable.MMapComplexEntity<MMapRouteContro
this._addDirectChild(this._control);
}

protected _onUpdate(props: Partial<MMapRouteControlProps>): void {
this._router.update(props);
}

protected _onDetach(): void {
this._removeDirectChild(this._control);
}
Expand Down Expand Up @@ -154,6 +161,13 @@ class MMapCommonRouteControl extends mappable.MMapComplexEntity<MMapRouteControl
);
}

protected _onUpdate(diffProps: Partial<MMapRouteControlProps>): void {
if (diffProps.waypoints) {
this._waypointInputFromElement.update({waypoint: diffProps.waypoints[0]});
this._waypointInputToElement.update({waypoint: diffProps.waypoints[1]});
}
}

protected _onDetach(): void {
this._detachDom?.();
this._detachDom = undefined;
Expand Down Expand Up @@ -215,7 +229,7 @@ class MMapCommonRouteControl extends mappable.MMapComplexEntity<MMapRouteControl
this._route();
};

private async _route() {
private _route = debounce(async () => {
if (!this._waypoints.every((point) => point !== null)) {
return;
}
Expand Down Expand Up @@ -245,7 +259,7 @@ class MMapCommonRouteControl extends mappable.MMapComplexEntity<MMapRouteControl
this._routeInfoElement.classList.add('mappable--route-control_info__error');
this._routeInfoElement.replaceChildren(...createRouteServerError(() => this._route()));
}
}
}, 200);

private _getRouteDetails(response: BaseRouteResponse): HTMLElement[] {
if (!response.toSteps) {
Expand Down
27 changes: 27 additions & 0 deletions src/controls/MMapRouteControl/vue/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {CustomVuefyOptions} from '@mappable-world/mappable-types/modules/vuefy';
import {TruckParameters} from '@mappable-world/mappable-types/imperative/route';
import {LngLat} from '@mappable-world/mappable-types';
import {MMapRouteControl, MMapRouteControlProps, AvailableTypes} from '..';
import type TVue from '@vue/runtime-core';

export const MMapRouteControlVuefyOptions: CustomVuefyOptions<MMapRouteControl> = {
props: {
geolocationTextInput: {type: String, default: 'My location'},
clearFieldsText: {type: String, default: 'Clear all'},
changeOrderText: {type: String, default: 'Change the order'},
availableTypes: {
type: Array as TVue.PropType<AvailableTypes[]>,
default: ['driving', 'truck', 'walking', 'transit']
},
truckParameters: Object as TVue.PropType<TruckParameters>,
waypoints: Array as unknown as TVue.PropType<[LngLat | null, LngLat | null]>,
waypointsPlaceholders: {type: Array as unknown as TVue.PropType<[string, string]>, default: ['From', 'To']},
search: Function as TVue.PropType<MMapRouteControlProps['search']>,
suggest: Function as TVue.PropType<MMapRouteControlProps['suggest']>,
route: Function as TVue.PropType<MMapRouteControlProps['route']>,
onMouseMoveOnMap: Function as TVue.PropType<MMapRouteControlProps['onMouseMoveOnMap']>,
onUpdateWaypoints: Function as TVue.PropType<MMapRouteControlProps['onUpdateWaypoints']>,
onRouteResult: Function as TVue.PropType<MMapRouteControlProps['onRouteResult']>,
onBuildRouteError: Function as TVue.PropType<MMapRouteControlProps['onBuildRouteError']>
}
};

0 comments on commit 8778850

Please sign in to comment.