@heycar/heycars-map 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -2
- package/dist/business-components/AddressBox/AddressBox.d.ts +1 -0
- package/dist/business-components/DrivingRoute/DrivingRoute.d.ts +5 -5
- package/dist/hooks/useGeoLocation.d.ts +22 -0
- package/dist/hooks/useMapAngle.d.ts +8 -9
- package/dist/hooks/useMapDrag.d.ts +10 -23
- package/dist/hooks/useMapPlace.d.ts +23 -0
- package/dist/hooks/useMapReady.d.ts +4 -0
- package/dist/hooks/useMapRecomendPlace.d.ts +27 -0
- package/dist/hooks-business/useBusinessMapRecomendPlace.d.ts +22 -0
- package/dist/index.cjs +55 -55
- package/dist/index.d.ts +4 -1
- package/dist/index.js +857 -721
- package/dist/style.css +1 -1
- package/dist/types/interface.d.ts +5 -0
- package/dist/utils/transform.d.ts +2 -0
- package/package.json +1 -1
- package/src/business-components/AddressBox/AddressBox.tsx +9 -3
- package/src/business-components/DrivingRoute/DrivingRoute.tsx +14 -14
- package/src/components/Demo/HeycarDemo.tsx +32 -8
- package/src/hooks/useDrivingRoute.ts +24 -21
- package/src/hooks/useGeoLocation.ts +44 -0
- package/src/hooks/useMapAngle.ts +12 -13
- package/src/hooks/useMapDrag.ts +30 -44
- package/src/hooks/useMapPlace.ts +66 -0
- package/src/hooks/useMapReady.ts +14 -0
- package/src/hooks/useMapRecomendPlace.ts +78 -0
- package/src/hooks-business/useBusinessMapRecomendPlace.ts +72 -0
- package/src/index.ts +4 -1
- package/src/types/interface.ts +5 -0
- package/src/utils/transform.ts +4 -0
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
._15rq2xn0{display:flex;flex-direction:column;align-items:center;margin-bottom:-1.6vw}._15rq2xn1{padding:2.13vw 4.5vw 2.67vw 4.27vw;display:flex;align-items:center;background:linear-gradient(90deg,#79AFFF 0%,#5C8DFF 32%,#507FFF 75%,#4471FF 100%);border-radius:3.2vw}._15rq2xn2{font-size:3.47vw;font-family:PingFangSC-Semibold,PingFang SC;font-weight:600;color:#fff;line-height:4.8vw;white-space:nowrap}._15rq2xn3{font-size:2.93vw;font-family:PingFangSC-Regular,PingFang SC;font-weight:400;color:#eafaf8;line-height:4.27vw;white-space:nowrap;opacity:.8}._15rq2xn4{margin-left:3.2vw;width:1.44vw;height:2.4vw}._15rq2xn5{width:.8vw;height:4vw;background:#4C80FF;border-radius:0vw 0vw 26.67vw 26.67vw;z-index:1}._15rq2xn6{margin-top:-1.5vw;width:3.2vw;height:3.2vw}.
|
|
1
|
+
.rgf09w0{width:7.1045vw;height:10.93vw;display:flex}._15rq2xn0{display:flex;flex-direction:column;align-items:center;margin-bottom:-1.6vw}._15rq2xn1{padding:2.13vw 4.5vw 2.67vw 4.27vw;display:flex;align-items:center;background:linear-gradient(90deg,#79AFFF 0%,#5C8DFF 32%,#507FFF 75%,#4471FF 100%);border-radius:3.2vw}._15rq2xn2{font-size:3.47vw;font-family:PingFangSC-Semibold,PingFang SC;font-weight:600;color:#fff;line-height:4.8vw;white-space:nowrap}._15rq2xn3{font-size:2.93vw;font-family:PingFangSC-Regular,PingFang SC;font-weight:400;color:#eafaf8;line-height:4.27vw;white-space:nowrap;opacity:.8}._15rq2xn4{margin-left:3.2vw;width:1.44vw;height:2.4vw}._15rq2xn5{width:.8vw;height:4vw;background:#4C80FF;border-radius:0vw 0vw 26.67vw 26.67vw;z-index:1}._15rq2xn6{margin-top:-1.5vw;width:3.2vw;height:3.2vw}._1l6offo0{display:flex;margin-bottom:-8.135vw;width:16.27vw;height:16.27vw}.fhyw80{display:flex;align-items:center}.fhyw81{flex-direction:row-reverse}.fhyw83{margin-right:-2.265vw}.fhyw84{margin-left:-2.265vw}.fhyw85{margin-bottom:-2.265vw}.fhyw86{margin-right:calc(50% - 2.265vw)}.fhyw87{margin-left:calc(50% - 2.265vw)}.fhyw88{display:flex;width:4.53vw;height:4.53vw}.fhyw89{font-size:3.47vw;font-family:PingFangSC-Semibold,PingFang SC;font-weight:600;color:#243e66;line-height:4.53vw;white-space:nowrap}._4a4ovk0{margin-bottom:-.4vw;display:flex;flex-direction:column;align-items:center}._4a4ovk1{padding:1.07vw 2.4vw 1.6vw 2.67vw;background:#FFFFFF;box-shadow:0 .53vw 2.4vw #3f3f3f33;border-radius:2.13vw}._4a4ovk2{padding:2.67vw 2.67vw 2.4vw 3.2vw;background:#FFFFFF;box-shadow:0 0 2.67vw #4e556c26;border-radius:4.8vw;font-size:3.2vw;font-family:PingFangSC-Medium,PingFang SC;font-weight:500;color:#1e1e1e;line-height:4.53vw;white-space:nowrap}._4a4ovk3{font-size:3.2vw;font-family:PingFangSC-Medium,PingFang SC;font-weight:500;color:#1e1e1e;line-height:4.53vw;white-space:nowrap}._4a4ovk4{font-size:2.4vw;font-family:PingFangSC-Regular,PingFang SC;font-weight:400;color:#7e7e7e;line-height:3.47vw;white-space:nowrap}._4a4ovk5{color:#4471ff;font-family:PingFangSC-Medium,PingFang SC;font-weight:500}._4a4ovk6{margin-top:1.33vw;width:6.192vw;height:7.998vw}._4a4ovk7{margin-top:2.4vw;width:6.192vw;height:7.998vw}._65j3sr1{margin-top:1.87vw;margin-bottom:-5.5vw;width:6vw;height:11vw}@keyframes rrvp0y0{0%{transform:scale(0);opacity:1}33.33%{transform:scale(.5);opacity:1}66.66%{transform:scale(1);opacity:0}to{transform:scale(1);opacity:0}}@keyframes rrvp0y1{0%{transform:scale(0);opacity:0}33.33%{transform:scale(0);opacity:1}66.66%{transform:scale(.5);opacity:1}to{transform:scale(1);opacity:0}}.rrvp0y2{display:flex;margin-bottom:-30.935vw;width:61.87vw;height:61.87vw;animation-name:rrvp0y0;animation-duration:3s;animation-iteration-count:infinite;animation-timing-function:linear}.rrvp0y3{animation-name:rrvp0y1}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/// <reference types="google.maps" />
|
|
2
|
+
import type { Place, Point } from "../types/interface";
|
|
2
3
|
export declare const vec2lnglat: ([lng, lat]: [number, number]) => google.maps.LatLngLiteral;
|
|
3
4
|
export interface AsteriskItem {
|
|
4
5
|
type: "normal" | "emphasize";
|
|
@@ -9,3 +10,4 @@ export declare const property2emitEventName: (propertyName: string) => string;
|
|
|
9
10
|
export declare const property2mapEventName: (propertyName: string) => string;
|
|
10
11
|
export type VectorMapForeign = "style_en" | "style_local" | "style_zh_cn";
|
|
11
12
|
export declare const language2vectorMapForeign: (lang: "en" | "zh") => VectorMapForeign;
|
|
13
|
+
export declare const place2point: (place: Place) => Point;
|
package/package.json
CHANGED
|
@@ -8,9 +8,11 @@ import { createElement, defineSetup } from "../../types/helper";
|
|
|
8
8
|
import type { Point } from "../../types/interface";
|
|
9
9
|
import { createDom } from "../../utils/dom";
|
|
10
10
|
import { vec2lnglat } from "../../utils/transform";
|
|
11
|
+
import { AAddressLocator, GAddressLocator } from "../AddressLocator";
|
|
11
12
|
import * as css from "./AddressBox.css";
|
|
12
13
|
|
|
13
14
|
interface AddressBoxProps {
|
|
15
|
+
type: "box" | "locator";
|
|
14
16
|
position: Point;
|
|
15
17
|
title: string;
|
|
16
18
|
description?: string;
|
|
@@ -31,9 +33,12 @@ export const AAddressBox = defineSetup(function AAddressBox(props: AddressBoxPro
|
|
|
31
33
|
</div>
|
|
32
34
|
`
|
|
33
35
|
);
|
|
34
|
-
return () =>
|
|
35
|
-
<
|
|
36
|
-
|
|
36
|
+
return () => {
|
|
37
|
+
if (props.type === "locator") return <AAddressLocator position={props.position} />;
|
|
38
|
+
return (
|
|
39
|
+
<AmapMarker position={props.position} content={contentRef.value} anchor={"bottom-center"} />
|
|
40
|
+
);
|
|
41
|
+
};
|
|
37
42
|
});
|
|
38
43
|
|
|
39
44
|
export const GAddressBox = defineSetup(function GAddressBox(props: AddressBoxProps) {
|
|
@@ -55,6 +60,7 @@ export const GAddressBox = defineSetup(function GAddressBox(props: AddressBoxPro
|
|
|
55
60
|
)
|
|
56
61
|
);
|
|
57
62
|
return () => {
|
|
63
|
+
if (props.type === "locator") return <GAddressLocator position={props.position} />;
|
|
58
64
|
return (
|
|
59
65
|
<GmapAdvancedMarkerView position={vec2lnglat(props.position)} content={contentRef.value} />
|
|
60
66
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { reactive, VNodeData } from "vue-demi";
|
|
2
2
|
import { useAmap } from "../../components/Amap/useAmap";
|
|
3
3
|
import { useGmap } from "../../components/Gmap/useGmap";
|
|
4
4
|
import { useMapSupplier } from "../../components/MapProvider/useMapSupplier";
|
|
@@ -11,31 +11,31 @@ import { useAmapAngle, useGmapAngle } from "../../hooks/useMapAngle";
|
|
|
11
11
|
import { createElement, defineSetup, VNodeChild } from "../../types/helper";
|
|
12
12
|
import type { Point } from "../../types/interface";
|
|
13
13
|
|
|
14
|
+
export type DrivingRouteRenderProps = {
|
|
15
|
+
path: Point[];
|
|
16
|
+
angle?: number;
|
|
17
|
+
};
|
|
14
18
|
export interface DrivingRouteProps extends UseDrivingRouteProps {
|
|
15
|
-
render?: (props:
|
|
16
|
-
pathRef: ShallowRef<Point[]>;
|
|
17
|
-
angleRef: Ref<number | undefined>;
|
|
18
|
-
}) => VNodeChild;
|
|
19
|
+
render?: (props: DrivingRouteRenderProps) => VNodeChild;
|
|
19
20
|
}
|
|
20
21
|
export const ADrivingRoute = defineSetup(function DrivingRoute(
|
|
21
22
|
props: DrivingRouteProps,
|
|
22
23
|
{ slots }
|
|
23
24
|
) {
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
return () => <div id="qyc">{slots.render?.({ pathRef, angleRef })}</div>;
|
|
25
|
+
const map = useAmap();
|
|
26
|
+
const path = useADrivingRoute(props);
|
|
27
|
+
const angle = useAmapAngle(reactive({ path, map }));
|
|
28
|
+
return () => <div>{slots.render?.(reactive({ path, angle }))}</div>;
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
export const GDrivingRoute = defineSetup(function DrivingRoute(
|
|
32
32
|
props: DrivingRouteProps,
|
|
33
33
|
{ slots }
|
|
34
34
|
) {
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
return () => <div>{slots.render?.({
|
|
35
|
+
const map = useGmap();
|
|
36
|
+
const path = useGDrivingRoute(props);
|
|
37
|
+
const angle = useGmapAngle(reactive({ path, map }));
|
|
38
|
+
return () => <div>{slots.render?.(reactive({ path, angle }))}</div>;
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
export const DrivingRoute = defineSetup(function DrivingRoute(props: DrivingRouteProps, { slots }) {
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import { AddressBox } from "../../business-components/AddressBox";
|
|
1
2
|
import { DrivingLine } from "../../business-components/DrivingLine";
|
|
2
3
|
import { DrivingRoute } from "../../business-components/DrivingRoute";
|
|
3
4
|
import { TaxiCar } from "../../business-components/TaxiCar";
|
|
5
|
+
import {
|
|
6
|
+
useBusinessMapRecomendPlace,
|
|
7
|
+
UseBusinessMapRecomendPlaceProps,
|
|
8
|
+
} from "../../hooks-business/useBusinessMapRecomendPlace";
|
|
4
9
|
import { useHeycarMap } from "../../hooks/useHeycarMap";
|
|
5
|
-
import { useMapDrag } from "../../hooks/useMapDrag";
|
|
6
10
|
import { defineSetup } from "../../types/helper";
|
|
7
11
|
import { HeycarMap, MapProvider } from "../MapProvider/MapProvider";
|
|
8
12
|
import * as css from "./Demo.css";
|
|
@@ -28,22 +32,42 @@ export const HeycarDemo = defineSetup(function HeycarDemo() {
|
|
|
28
32
|
|
|
29
33
|
export const SomePage = defineSetup(function Hello() {
|
|
30
34
|
const { mapRef, setMap, panTo } = useHeycarMap();
|
|
31
|
-
const
|
|
35
|
+
const getRecomendPlace: UseBusinessMapRecomendPlaceProps["getRecomendPlace"] = async (place) => {
|
|
36
|
+
const { lat, lng } = place;
|
|
37
|
+
console.log("typeof lat = ", typeof lat);
|
|
38
|
+
return [{ lat: lat + 0.0001, lng: lng + 0.0001, name: "place name 1" }];
|
|
39
|
+
};
|
|
40
|
+
const { centerPlace, centerPoint, isDragging, isGeoLoading, geoError } =
|
|
41
|
+
useBusinessMapRecomendPlace({
|
|
42
|
+
mapRef,
|
|
43
|
+
recomendPlaceGeoLimit: 300,
|
|
44
|
+
recomendPlaceDragLimit: 30,
|
|
45
|
+
getRecomendPlace,
|
|
46
|
+
onChangeGeoLocation: (v) => console.log("onChangeGeoLocation: ", v),
|
|
47
|
+
onChangePlace: (v) => console.log("onChangePlace: ", v),
|
|
48
|
+
onChangeRecomandPlace: (v) => console.log("onChangeRecomandPlace: ", v),
|
|
49
|
+
});
|
|
32
50
|
(window as any).panTo = panTo;
|
|
33
51
|
return () => {
|
|
34
52
|
return (
|
|
35
53
|
<div>
|
|
54
|
+
isGeoLoading: {`${isGeoLoading.value}`} <br />
|
|
36
55
|
isDragging: {`${isDragging.value}`} <br />
|
|
37
|
-
{centerPlace.lng} | {centerPlace.lat} | {centerPlace.name}
|
|
56
|
+
{centerPlace.lng} | {centerPlace.lat} | {centerPlace.name} <br />
|
|
38
57
|
<HeycarMap
|
|
39
58
|
class={css.demo}
|
|
40
59
|
fallback={() => <div>error</div>}
|
|
41
60
|
loading={() => <div>loading</div>}
|
|
42
|
-
center={[
|
|
61
|
+
center={[centerPlace.lng, centerPlace.lat]}
|
|
43
62
|
zoom={15}
|
|
44
63
|
mapRef={setMap}
|
|
45
64
|
>
|
|
46
|
-
|
|
65
|
+
<AddressBox
|
|
66
|
+
type="box"
|
|
67
|
+
position={centerPoint.value}
|
|
68
|
+
title={"Martyrs Lawn"}
|
|
69
|
+
description={"您将在此处上车"}
|
|
70
|
+
/>
|
|
47
71
|
{/* <TaxiCar position={[121, 31]} angle={0} /> */}
|
|
48
72
|
{/* <PickupPoints
|
|
49
73
|
positions={[
|
|
@@ -55,9 +79,9 @@ export const SomePage = defineSetup(function Hello() {
|
|
|
55
79
|
<DrivingRoute
|
|
56
80
|
from={[121, 31]}
|
|
57
81
|
to={[121.6, 31.3]}
|
|
58
|
-
render={({
|
|
59
|
-
|
|
60
|
-
<TaxiCar position={[121, 31]} angle={
|
|
82
|
+
render={({ path, angle }) => [
|
|
83
|
+
<DrivingLine path={path} />,
|
|
84
|
+
<TaxiCar position={[121, 31]} angle={angle} />,
|
|
61
85
|
]}
|
|
62
86
|
/>
|
|
63
87
|
</HeycarMap>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { ShallowRef, shallowRef
|
|
1
|
+
import { ShallowRef, shallowRef } from "vue-demi";
|
|
2
2
|
import { useMapSupplier } from "../components/MapProvider/useMapSupplier";
|
|
3
3
|
import type { Point } from "../types/interface";
|
|
4
|
+
import { watchPostEffectForDeepOption } from "../utils/compare";
|
|
4
5
|
|
|
5
6
|
export interface UseDrivingRouteProps {
|
|
6
7
|
from: Point;
|
|
@@ -10,9 +11,9 @@ export interface UseDrivingRouteProps {
|
|
|
10
11
|
export const useADrivingRoute = (props: UseDrivingRouteProps) => {
|
|
11
12
|
const pathRef = shallowRef<Point[]>([]);
|
|
12
13
|
const amapDriving = new AMap.Driving({});
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
(
|
|
14
|
+
watchPostEffectForDeepOption(
|
|
15
|
+
() => ({ ...props }),
|
|
16
|
+
({ from, to }) => {
|
|
16
17
|
amapDriving.search(
|
|
17
18
|
AMap.LngLat.from(from),
|
|
18
19
|
AMap.LngLat.from(to),
|
|
@@ -39,8 +40,7 @@ export const useADrivingRoute = (props: UseDrivingRouteProps) => {
|
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
);
|
|
42
|
-
}
|
|
43
|
-
{ immediate: true }
|
|
43
|
+
}
|
|
44
44
|
);
|
|
45
45
|
return pathRef;
|
|
46
46
|
};
|
|
@@ -48,22 +48,25 @@ export const useADrivingRoute = (props: UseDrivingRouteProps) => {
|
|
|
48
48
|
export const useGDrivingRoute = (props: UseDrivingRouteProps) => {
|
|
49
49
|
const pathRef = shallowRef<Point[]>([]);
|
|
50
50
|
const gmapDirectionsService = new google.maps.DirectionsService();
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
51
|
+
watchPostEffectForDeepOption(
|
|
52
|
+
() => ({ ...props }),
|
|
53
|
+
({ from, to }) => {
|
|
54
|
+
gmapDirectionsService
|
|
55
|
+
.route({
|
|
56
|
+
origin: { lng: from[0], lat: from[1] },
|
|
57
|
+
destination: { lng: to[0], lat: to[1] },
|
|
58
|
+
travelMode: google.maps.TravelMode.WALKING,
|
|
59
|
+
})
|
|
60
|
+
.then((result) => {
|
|
61
|
+
let path: Point[] = [];
|
|
62
|
+
result.routes.map((route) => {
|
|
63
|
+
const stepPath = route.overview_path.map<Point>((item) => [item.lng(), item.lat()]);
|
|
64
|
+
path = path.concat(stepPath);
|
|
65
|
+
});
|
|
66
|
+
pathRef.value = path;
|
|
63
67
|
});
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
});
|
|
68
|
+
}
|
|
69
|
+
);
|
|
67
70
|
return pathRef;
|
|
68
71
|
};
|
|
69
72
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ref, watchEffect } from "vue-demi";
|
|
2
|
+
import type { MapShallowRef, Point } from "../types/interface";
|
|
3
|
+
|
|
4
|
+
export interface UseGeoLocationProps {
|
|
5
|
+
mapRef: MapShallowRef;
|
|
6
|
+
onChange?: (value: { position: Point; coordinate: GeolocationCoordinates }) => any;
|
|
7
|
+
}
|
|
8
|
+
export const useGeoLocation = (props: UseGeoLocationProps) => {
|
|
9
|
+
const { mapRef, onChange } = props;
|
|
10
|
+
const loading = ref(false);
|
|
11
|
+
const errorRef = ref<GeolocationPositionError>();
|
|
12
|
+
const coordinateRef = ref<GeolocationCoordinates>({
|
|
13
|
+
accuracy: 0,
|
|
14
|
+
altitude: 0,
|
|
15
|
+
altitudeAccuracy: 0,
|
|
16
|
+
heading: 0,
|
|
17
|
+
latitude: 0,
|
|
18
|
+
longitude: 0,
|
|
19
|
+
speed: 0,
|
|
20
|
+
});
|
|
21
|
+
const positionRef = ref<Point>([coordinateRef.value.longitude, coordinateRef.value.latitude]);
|
|
22
|
+
watchEffect(() => {
|
|
23
|
+
mapRef.value;
|
|
24
|
+
loading.value = true;
|
|
25
|
+
navigator.geolocation.getCurrentPosition(
|
|
26
|
+
(position) => {
|
|
27
|
+
loading.value = false;
|
|
28
|
+
const coordinate = position.coords;
|
|
29
|
+
const point: Point = [position.coords.longitude, position.coords.latitude];
|
|
30
|
+
coordinateRef.value = coordinate;
|
|
31
|
+
positionRef.value = point;
|
|
32
|
+
onChange?.({ position: point, coordinate });
|
|
33
|
+
},
|
|
34
|
+
(error) => {
|
|
35
|
+
loading.value = false;
|
|
36
|
+
errorRef.value = error;
|
|
37
|
+
console.log("errorRef = ", errorRef);
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
{ timeout: 5000 }
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
return { errorRef, positionRef, coordinateRef, loading };
|
|
44
|
+
};
|
package/src/hooks/useMapAngle.ts
CHANGED
|
@@ -1,35 +1,34 @@
|
|
|
1
|
-
import { computed
|
|
1
|
+
import { computed } from "vue-demi";
|
|
2
2
|
import { useMapSupplier } from "../components/MapProvider/useMapSupplier";
|
|
3
|
-
import type {
|
|
3
|
+
import type { Point } from "../types/interface";
|
|
4
4
|
import { vec2lnglat } from "../utils/transform";
|
|
5
5
|
|
|
6
6
|
const amapComputeHeading = (from: Point, to: Point, map?: AMap.Map) => {
|
|
7
7
|
if (!map) return 0;
|
|
8
8
|
const { x: xFrom, y: yFrom } = map.lngLatToContainer(from);
|
|
9
9
|
const { x: xTo, y: yTo } = map.lngLatToContainer(to);
|
|
10
|
-
console.log("yTo - yFrom, xTo - xFrom = ", yTo - yFrom, xTo - xFrom);
|
|
11
10
|
const theta = Math.atan2(yFrom - yTo, xTo - xFrom);
|
|
12
11
|
return ((Math.PI / 2 - theta) / Math.PI) * 180;
|
|
13
12
|
};
|
|
14
13
|
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
14
|
+
export type UseMapAngleProps<M = AMap.Map | google.maps.Map> = {
|
|
15
|
+
path: Point[];
|
|
16
|
+
map?: M;
|
|
17
|
+
};
|
|
19
18
|
|
|
20
19
|
export const useAmapAngle = (props: UseMapAngleProps<AMap.Map>) => {
|
|
21
20
|
return computed(() => {
|
|
22
|
-
const {
|
|
23
|
-
const [from, to] =
|
|
24
|
-
if (!from || !to || !
|
|
25
|
-
return amapComputeHeading(from, to,
|
|
21
|
+
const { map, path } = props;
|
|
22
|
+
const [from, to] = path;
|
|
23
|
+
if (!from || !to || !map) return undefined;
|
|
24
|
+
return amapComputeHeading(from, to, map);
|
|
26
25
|
});
|
|
27
26
|
};
|
|
28
27
|
|
|
29
28
|
export const useGmapAngle = (props: UseMapAngleProps<google.maps.Map>) => {
|
|
30
29
|
return computed(() => {
|
|
31
|
-
const {
|
|
32
|
-
const [from, to] =
|
|
30
|
+
const { path } = props;
|
|
31
|
+
const [from, to] = path;
|
|
33
32
|
if (!from || !to) return undefined;
|
|
34
33
|
return google.maps.geometry.spherical.computeHeading(vec2lnglat(from), vec2lnglat(to));
|
|
35
34
|
});
|
package/src/hooks/useMapDrag.ts
CHANGED
|
@@ -1,81 +1,67 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ref, type ShallowRef } from "vue-demi";
|
|
2
2
|
import type { AmapProps } from "../components/Amap";
|
|
3
3
|
import type { GmapProps } from "../components/Gmap";
|
|
4
4
|
import { useMapSupplier } from "../components/MapProvider/useMapSupplier";
|
|
5
|
-
import {
|
|
6
|
-
import type {
|
|
5
|
+
import type { SetupContextEmitHandler } from "../types/helper";
|
|
6
|
+
import type { Point } from "../types/interface";
|
|
7
7
|
import { watchPostEffectForAMapEvent, watchPostEffectForGMapEvent } from "../utils/compare";
|
|
8
8
|
|
|
9
9
|
export const ON_CHANGE_CENTER_INTERVAL = 200;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
|
|
11
|
+
export interface UseMapDragProps<M = AMap.Map | google.maps.Map> {
|
|
12
|
+
mapRef: ShallowRef<M | undefined>;
|
|
13
|
+
onChange?: (value: Point) => any;
|
|
14
14
|
}
|
|
15
|
-
export const useAmapDrag = (
|
|
16
|
-
const
|
|
15
|
+
export const useAmapDrag = (props: UseMapDragProps<AMap.Map>) => {
|
|
16
|
+
const { mapRef, onChange } = props;
|
|
17
|
+
const centerRef = ref<Point>([0, 0]);
|
|
17
18
|
const isDragging = ref(false);
|
|
18
19
|
const emitDragStart: SetupContextEmitHandler<Pick<AmapProps, "onDragStart">> = () => {
|
|
19
20
|
Promise.resolve().then(() => (isDragging.value = true));
|
|
20
21
|
};
|
|
21
22
|
const emitDragEnd: SetupContextEmitHandler<Pick<AmapProps, "onDragEnd">> = (_, { target }) => {
|
|
22
23
|
isDragging.value = false;
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const geocoder = new AMap.Geocoder({ lang: LANGUAGE });
|
|
27
|
-
geocoder.getAddress(center, (status, result) => {
|
|
28
|
-
switch (status) {
|
|
29
|
-
case "complete":
|
|
30
|
-
centerPlace.name = (result as AMap.ReGeocoderResult).regeocode.formattedAddress;
|
|
31
|
-
return;
|
|
32
|
-
case "no_data":
|
|
33
|
-
return;
|
|
34
|
-
case "error":
|
|
35
|
-
throw result;
|
|
36
|
-
}
|
|
37
|
-
});
|
|
24
|
+
const { lng, lat } = target.getCenter();
|
|
25
|
+
centerRef.value = [lng, lat];
|
|
26
|
+
onChange?.([lng, lat]);
|
|
38
27
|
};
|
|
39
|
-
watchPostEffectForAMapEvent(
|
|
28
|
+
watchPostEffectForAMapEvent(mapRef, {} as Pick<AmapProps, "onDragStart">, emitDragStart, [
|
|
40
29
|
"onDragStart",
|
|
41
30
|
]);
|
|
42
|
-
watchPostEffectForAMapEvent(
|
|
31
|
+
watchPostEffectForAMapEvent(mapRef, {} as Pick<AmapProps, "onDragEnd">, emitDragEnd, [
|
|
43
32
|
"onDragEnd",
|
|
44
33
|
]);
|
|
45
|
-
return {
|
|
34
|
+
return { centerRef, isDragging };
|
|
46
35
|
};
|
|
47
36
|
|
|
48
|
-
export const useGmapDrag = (
|
|
49
|
-
const
|
|
37
|
+
export const useGmapDrag = (props: UseMapDragProps<google.maps.Map>) => {
|
|
38
|
+
const { mapRef, onChange } = props;
|
|
39
|
+
const centerRef = ref<Point>([0, 0]);
|
|
50
40
|
const isDragging = ref(false);
|
|
51
41
|
const emitDragStart: SetupContextEmitHandler<Pick<GmapProps, "onDragStart">> = () => {
|
|
52
42
|
Promise.resolve().then(() => (isDragging.value = true));
|
|
53
43
|
};
|
|
54
44
|
const emitDragEnd: SetupContextEmitHandler<Pick<GmapProps, "onDragEnd">> = async () => {
|
|
55
45
|
isDragging.value = false;
|
|
56
|
-
const center =
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (lat) centerPlace.lat = lat;
|
|
62
|
-
const geocoder = new google.maps.Geocoder();
|
|
63
|
-
const { results } = await geocoder.geocode({ language: LANGUAGE, location: center });
|
|
64
|
-
centerPlace.name = results[0].formatted_address;
|
|
46
|
+
const center = mapRef.value?.getCenter();
|
|
47
|
+
const lng = center?.lng() as number;
|
|
48
|
+
const lat = center?.lat() as number;
|
|
49
|
+
centerRef.value = [lng, lat];
|
|
50
|
+
onChange?.([lng, lat]);
|
|
65
51
|
};
|
|
66
|
-
watchPostEffectForGMapEvent(
|
|
52
|
+
watchPostEffectForGMapEvent(mapRef!, {} as Pick<GmapProps, "onDragStart">, emitDragStart, [
|
|
67
53
|
"onDragStart",
|
|
68
54
|
]);
|
|
69
|
-
watchPostEffectForGMapEvent(
|
|
55
|
+
watchPostEffectForGMapEvent(mapRef!, {} as Pick<GmapProps, "onDragEnd">, emitDragEnd, [
|
|
70
56
|
"onDragEnd",
|
|
71
57
|
]);
|
|
72
|
-
return {
|
|
58
|
+
return { centerRef, isDragging };
|
|
73
59
|
};
|
|
74
60
|
|
|
75
|
-
export const useMapDrag = (
|
|
61
|
+
export const useMapDrag = (props: UseMapDragProps) => {
|
|
76
62
|
const { supplier } = useMapSupplier();
|
|
77
63
|
// todo: 这里违反 react hook 规则,但 react 版本应该可以同时调用 useAmap 和 useGmap
|
|
78
64
|
return supplier === "gmap"
|
|
79
|
-
? useGmapDrag(
|
|
80
|
-
: useAmapDrag(
|
|
65
|
+
? useGmapDrag(props as UseMapDragProps<google.maps.Map>)
|
|
66
|
+
: useAmapDrag(props as UseMapDragProps<AMap.Map>);
|
|
81
67
|
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { reactive, Ref, watchEffect } from "vue-demi";
|
|
2
|
+
import { useMapSupplier } from "../components/MapProvider/useMapSupplier";
|
|
3
|
+
import { LANGUAGE } from "../types/helper";
|
|
4
|
+
import type { MapShallowRef, Place, Point } from "../types/interface";
|
|
5
|
+
import { useMapReady } from "./useMapReady";
|
|
6
|
+
|
|
7
|
+
export interface UseMapPlaceProps<M = AMap.Map | google.maps.Map> {
|
|
8
|
+
pointRef: Ref<Point>;
|
|
9
|
+
mapRef: MapShallowRef<M>;
|
|
10
|
+
onChange?: (value: Place) => any;
|
|
11
|
+
}
|
|
12
|
+
export const useAmapPlace = (props: UseMapPlaceProps<AMap.Map>) => {
|
|
13
|
+
const { mapRef, pointRef, onChange } = props;
|
|
14
|
+
const { readyRef } = useMapReady(mapRef);
|
|
15
|
+
const place = reactive<Place>({ lng: pointRef.value[0], lat: pointRef.value[1], name: "" });
|
|
16
|
+
watchEffect(() => {
|
|
17
|
+
if (!readyRef.value) return;
|
|
18
|
+
const geocoder = new AMap.Geocoder({ lang: LANGUAGE });
|
|
19
|
+
const [lng, lat] = pointRef.value;
|
|
20
|
+
place.lng = lng;
|
|
21
|
+
place.lat = lat;
|
|
22
|
+
geocoder.getAddress(new AMap.LngLat(lng, lat), (status, result) => {
|
|
23
|
+
switch (status) {
|
|
24
|
+
case "complete": {
|
|
25
|
+
const name = (result as AMap.ReGeocoderResult).regeocode.formattedAddress;
|
|
26
|
+
place.name = name;
|
|
27
|
+
onChange?.({ lng, lat, name });
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
case "no_data":
|
|
32
|
+
place.name = "";
|
|
33
|
+
onChange?.({ lng, lat, name: "" });
|
|
34
|
+
return;
|
|
35
|
+
case "error":
|
|
36
|
+
throw result;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
return place;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const useGmapPlace = (props: UseMapPlaceProps<google.maps.Map>) => {
|
|
44
|
+
const { mapRef, pointRef, onChange } = props;
|
|
45
|
+
const { readyRef } = useMapReady(mapRef);
|
|
46
|
+
const place = reactive<Place>({ lng: pointRef.value[0], lat: pointRef.value[1], name: "" });
|
|
47
|
+
watchEffect(async () => {
|
|
48
|
+
if (!readyRef.value) return;
|
|
49
|
+
const geocoder = new google.maps.Geocoder();
|
|
50
|
+
const [lng, lat] = pointRef.value;
|
|
51
|
+
place.lng = lng;
|
|
52
|
+
place.lat = lat;
|
|
53
|
+
const { results } = await geocoder.geocode({ language: LANGUAGE, location: { lng, lat } });
|
|
54
|
+
const name = results[0].formatted_address;
|
|
55
|
+
place.name = name;
|
|
56
|
+
onChange?.({ lng, lat, name });
|
|
57
|
+
});
|
|
58
|
+
return place;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const useMapPlace = (props: UseMapPlaceProps) => {
|
|
62
|
+
const { supplier } = useMapSupplier();
|
|
63
|
+
return supplier === "gmap"
|
|
64
|
+
? useGmapPlace(props as UseMapPlaceProps<google.maps.Map>)
|
|
65
|
+
: useAmapPlace(props as UseMapPlaceProps<AMap.Map>);
|
|
66
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ref, watch } from "vue-demi";
|
|
2
|
+
import type { MapShallowRef } from "../types/interface";
|
|
3
|
+
|
|
4
|
+
export const useMapReady = (mapRef: MapShallowRef) => {
|
|
5
|
+
const readyRef = ref(!!mapRef.value);
|
|
6
|
+
watch(
|
|
7
|
+
() => mapRef.value,
|
|
8
|
+
(map) => {
|
|
9
|
+
if (!map) return;
|
|
10
|
+
readyRef.value = true;
|
|
11
|
+
}
|
|
12
|
+
);
|
|
13
|
+
return { readyRef };
|
|
14
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { reactive, Ref, watchEffect } from "vue-demi";
|
|
2
|
+
import { useMapSupplier } from "../components/MapProvider/useMapSupplier";
|
|
3
|
+
import type { MapShallowRef, Place, Point } from "../types/interface";
|
|
4
|
+
import { place2point } from "../utils/transform";
|
|
5
|
+
import { useAmapPlace, useGmapPlace, UseMapPlaceProps } from "./useMapPlace";
|
|
6
|
+
import { useMapReady } from "./useMapReady";
|
|
7
|
+
|
|
8
|
+
const findAmapNearestPlace = (place: Place, candidates: Place[]) => {
|
|
9
|
+
let shortestDistance = Infinity;
|
|
10
|
+
let shortestPlace = place;
|
|
11
|
+
for (const candidate of candidates) {
|
|
12
|
+
const distance = AMap.GeometryUtil.distance(place2point(place), place2point(candidate));
|
|
13
|
+
if (distance >= shortestDistance) continue;
|
|
14
|
+
shortestPlace = candidate;
|
|
15
|
+
shortestDistance = distance;
|
|
16
|
+
}
|
|
17
|
+
return { shortestPlace, shortestDistance };
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const findGmapNearestPlace = (place: Place, candidates: Place[]) => {
|
|
21
|
+
let shortestDistance = Infinity;
|
|
22
|
+
let shortestPlace = place;
|
|
23
|
+
for (const candidate of candidates) {
|
|
24
|
+
const distance = google.maps.geometry.spherical.computeDistanceBetween(place, candidate);
|
|
25
|
+
if (distance >= shortestDistance) continue;
|
|
26
|
+
shortestPlace = candidate;
|
|
27
|
+
shortestDistance = distance;
|
|
28
|
+
}
|
|
29
|
+
return { shortestPlace, shortestDistance };
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export interface UseMapRecomendPlaceProps<M = AMap.Map | google.maps.Map> {
|
|
33
|
+
mapRef: MapShallowRef<M>;
|
|
34
|
+
pointRef: Ref<Point>;
|
|
35
|
+
limit: number;
|
|
36
|
+
getRecomendPlace: (place: Place) => Promise<Place[]>;
|
|
37
|
+
onChangePlace?: UseMapPlaceProps["onChange"];
|
|
38
|
+
onChange?: (place: Place) => any;
|
|
39
|
+
}
|
|
40
|
+
export const useAmapRecomendPlace = (props: UseMapRecomendPlaceProps<AMap.Map>) => {
|
|
41
|
+
const { pointRef, mapRef, getRecomendPlace, limit, onChange, onChangePlace } = props;
|
|
42
|
+
const { readyRef } = useMapReady(mapRef);
|
|
43
|
+
const place = useAmapPlace({ pointRef, mapRef, onChange: onChangePlace });
|
|
44
|
+
const recomendPlace = reactive<Place>({ ...place });
|
|
45
|
+
watchEffect(async () => {
|
|
46
|
+
if (!readyRef.value) return;
|
|
47
|
+
const placeCandidates = await getRecomendPlace({ ...place });
|
|
48
|
+
const { shortestPlace, shortestDistance } = findAmapNearestPlace(place, placeCandidates);
|
|
49
|
+
console.log("shortestPlace, shortestDistance = ", shortestPlace, shortestDistance);
|
|
50
|
+
const resultPlace = shortestDistance > limit ? place : shortestPlace;
|
|
51
|
+
Object.assign(recomendPlace, { ...resultPlace });
|
|
52
|
+
onChange?.({ ...resultPlace });
|
|
53
|
+
});
|
|
54
|
+
return recomendPlace;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const useGmapRecomendPlace = (props: UseMapRecomendPlaceProps<google.maps.Map>) => {
|
|
58
|
+
const { pointRef, mapRef, getRecomendPlace, limit, onChange, onChangePlace } = props;
|
|
59
|
+
const { readyRef } = useMapReady(mapRef);
|
|
60
|
+
const place = useGmapPlace({ pointRef, mapRef, onChange: onChangePlace });
|
|
61
|
+
const recomendPlace = reactive<Place>({ ...place });
|
|
62
|
+
watchEffect(async () => {
|
|
63
|
+
if (!readyRef.value) return;
|
|
64
|
+
const placeCandidates = await getRecomendPlace({ ...place });
|
|
65
|
+
const { shortestPlace, shortestDistance } = findGmapNearestPlace(place, placeCandidates);
|
|
66
|
+
const resultPlace = shortestDistance > limit ? place : shortestPlace;
|
|
67
|
+
Object.assign(recomendPlace, { ...resultPlace });
|
|
68
|
+
onChange?.({ ...resultPlace });
|
|
69
|
+
});
|
|
70
|
+
return recomendPlace;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const useMapRecomendPlace = (props: UseMapRecomendPlaceProps) => {
|
|
74
|
+
const { supplier } = useMapSupplier();
|
|
75
|
+
return supplier === "gmap"
|
|
76
|
+
? useGmapRecomendPlace(props as UseMapRecomendPlaceProps<google.maps.Map>)
|
|
77
|
+
: useAmapRecomendPlace(props as UseMapRecomendPlaceProps<AMap.Map>);
|
|
78
|
+
};
|