@heycar/heycars-map 0.2.2 → 0.2.4

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.
Files changed (33) hide show
  1. package/dist/api/geometry.d.ts +3 -3
  2. package/dist/business-components/DrivingRoute/DrivingRoute.d.ts +2 -0
  3. package/dist/business-components/PassengerCircle/PassengerCircle.css.d.ts +14 -1
  4. package/dist/business-components/PassengerCircle/PassengerCircle.d.ts +1 -0
  5. package/dist/business-components/PlaceCircle/PlaceCircle.css.d.ts +8 -1
  6. package/dist/business-components/PlaceCircle/PlaceCircle.d.ts +1 -0
  7. package/dist/hooks/useDrivingRoute.d.ts +12 -5
  8. package/dist/hooks/useGeoLocation.d.ts +1 -1
  9. package/dist/hooks/useMapGeometry.d.ts +10 -0
  10. package/dist/index.cjs +45 -45
  11. package/dist/index.d.ts +1 -0
  12. package/dist/index.js +921 -817
  13. package/dist/style.css +1 -1
  14. package/dist/types/interface.d.ts +5 -0
  15. package/package.json +1 -1
  16. package/src/api/geometry.ts +3 -4
  17. package/src/business-components/DrivingRoute/DrivingRoute.tsx +7 -5
  18. package/src/business-components/PassengerCircle/PassengerCircle.css.ts +19 -6
  19. package/src/business-components/PassengerCircle/PassengerCircle.tsx +14 -8
  20. package/src/business-components/PlaceCircle/PlaceCircle.css.ts +14 -4
  21. package/src/business-components/PlaceCircle/PlaceCircle.tsx +35 -29
  22. package/src/business-components/WalkingLine/WalkingLine.tsx +6 -2
  23. package/src/business-components/WalkingRoute/WalkingRoute.tsx +2 -8
  24. package/src/components/Demo/HeycarDemo.tsx +22 -9
  25. package/src/hooks/useDrivingRoute.ts +55 -25
  26. package/src/hooks/useGeoLocation.ts +2 -2
  27. package/src/hooks/useMapGeometry.ts +27 -0
  28. package/src/hooks/useMapLoader.ts +1 -1
  29. package/src/hooks/useWalkingRoute.ts +24 -11
  30. package/src/index.ts +1 -0
  31. package/src/types/amap/plugin.d.ts +1 -1
  32. package/src/types/interface.ts +6 -0
  33. package/todo.md +10 -5
package/dist/style.css CHANGED
@@ -1 +1 @@
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
+ .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}._1l6offo1{width:4.53vw;height:4.53vw;margin-bottom:-2.265vw}._1l6offo2{width:16.27vw;height:16.27vw;margin-bottom:-8.135vw}.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{opacity:0}.fhyw8b{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}
@@ -25,3 +25,8 @@ export interface RegisterOverlay<T> {
25
25
  add: (overlay: T) => void;
26
26
  remove: (overlay: T) => void;
27
27
  }
28
+ export interface Route {
29
+ path: Point[];
30
+ distance: number;
31
+ duration: number;
32
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heycar/heycars-map",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite -c vite.config.dev.ts",
@@ -5,11 +5,10 @@ export interface ApiMapMeta {
5
5
  }
6
6
 
7
7
  const point2latlng = ([lng, lat]: Point): google.maps.LatLngLiteral => ({ lng, lat });
8
-
9
8
  export interface DistanceOfLineProps extends ApiMapMeta {
10
9
  path: Point[];
11
10
  }
12
- export function apiDistanceOfLine(props: DistanceOfLineProps): number {
11
+ export function apiMapDistanceOfLine(props: DistanceOfLineProps): number {
13
12
  const { path, isGoogle } = props;
14
13
  if (!isGoogle) {
15
14
  return AMap.GeometryUtil.distanceOfLine(path);
@@ -21,7 +20,7 @@ export interface IsPointInRingProps extends ApiMapMeta {
21
20
  point: Point;
22
21
  path: Point[];
23
22
  }
24
- export function apiIsPointInRing(props: IsPointInRingProps): boolean {
23
+ export function apiMapIsPointInRing(props: IsPointInRingProps): boolean {
25
24
  const { point, path, isGoogle } = props;
26
25
  if (!isGoogle) {
27
26
  return AMap.GeometryUtil.isPointInRing(point, path);
@@ -35,7 +34,7 @@ export interface IsPointInLineProps extends ApiMapMeta {
35
34
  path: Point[];
36
35
  tolerance: number;
37
36
  }
38
- export function apiIsPointInLine(props: IsPointInLineProps): boolean {
37
+ export function apiMapIsPointInLine(props: IsPointInLineProps): boolean {
39
38
  const { point, path, tolerance, isGoogle } = props;
40
39
  if (!isGoogle) {
41
40
  return AMap.GeometryUtil.isPointOnLine(point, path, tolerance);
@@ -1,4 +1,4 @@
1
- import { reactive, VNodeData } from "vue-demi";
1
+ import { reactive, toRefs, VNodeData } from "vue-demi";
2
2
  import {
3
3
  useADrivingRoute,
4
4
  UseDrivingRouteProps,
@@ -13,6 +13,8 @@ import type { Point } from "../../types/interface";
13
13
  export type DrivingRouteRenderProps = {
14
14
  path: Point[];
15
15
  angle?: number;
16
+ distance: number;
17
+ duration: number;
16
18
  };
17
19
  export interface DrivingRouteProps extends UseDrivingRouteProps {
18
20
  render?: (props: DrivingRouteRenderProps) => VNodeChild;
@@ -22,9 +24,9 @@ export const ADrivingRoute = defineSetup(function DrivingRoute(
22
24
  { slots }
23
25
  ) {
24
26
  const map = useAmap();
25
- const path = useADrivingRoute(props);
27
+ const { path, distance, duration } = toRefs(useADrivingRoute(props));
26
28
  const angle = useAmapAngle(reactive({ path, map }));
27
- return () => <div>{slots.render?.(reactive({ path, angle }))}</div>;
29
+ return () => <div>{slots.render?.(reactive({ path, angle, distance, duration }))}</div>;
28
30
  });
29
31
 
30
32
  export const GDrivingRoute = defineSetup(function DrivingRoute(
@@ -32,9 +34,9 @@ export const GDrivingRoute = defineSetup(function DrivingRoute(
32
34
  { slots }
33
35
  ) {
34
36
  const map = useGmap();
35
- const path = useGDrivingRoute(props);
37
+ const { path, distance, duration } = toRefs(useGDrivingRoute(props));
36
38
  const angle = useGmapAngle(reactive({ path, map }));
37
- return () => <div>{slots.render?.(reactive({ path, angle }))}</div>;
39
+ return () => <div>{slots.render?.(reactive({ path, angle, distance, duration }))}</div>;
38
40
  });
39
41
 
40
42
  export const DrivingRoute = defineSetup(function DrivingRoute(props: DrivingRouteProps, { slots }) {
@@ -1,8 +1,21 @@
1
- import { style } from "@vanilla-extract/css";
1
+ import { recipe } from "@vanilla-extract/recipes";
2
2
 
3
- export const passengerCircle = style({
4
- display: "flex",
5
- marginBottom: "-8.135vw",
6
- width: "16.27vw",
7
- height: "16.27vw",
3
+ export const passengerCircle = recipe({
4
+ base: {
5
+ display: "flex",
6
+ },
7
+ variants: {
8
+ size: {
9
+ small: {
10
+ width: "4.53vw",
11
+ height: "4.53vw",
12
+ marginBottom: "-2.265vw",
13
+ },
14
+ large: {
15
+ width: "16.27vw",
16
+ height: "16.27vw",
17
+ marginBottom: "-8.135vw",
18
+ },
19
+ },
20
+ },
8
21
  });
@@ -1,5 +1,6 @@
1
1
  import { computed } from "vue";
2
2
  import imgPassengerCircle from "../../assets/icons/svg/passenger-circle.svg";
3
+ import imgPlaceCircle from "../../assets/icons/svg/place-circle.svg";
3
4
  import { AmapMarker } from "../../components/AmapMarker";
4
5
  import { GmapAdvancedMarkerView } from "../../components/GmapAdvancedMarkerView";
5
6
  import { useMapSupplier } from "../../hooks/useMapSupplier";
@@ -11,22 +12,27 @@ import * as css from "./PassengerCircle.css";
11
12
 
12
13
  interface PassengerCircleProps {
13
14
  position: [number, number];
15
+ size?: "small" | "large";
14
16
  }
15
17
  export const APassengerCircle = defineSetup(function APassengerCircle(props: PassengerCircleProps) {
16
- const contentRef = computed(
17
- () => `
18
- <img src="${imgPassengerCircle}" class="${css.passengerCircle}">
19
- `
20
- );
18
+ const contentRef = computed(() => {
19
+ const { size = "large" } = props;
20
+ const src = size === "large" ? imgPassengerCircle : imgPlaceCircle;
21
+ return `
22
+ <img src="${src}" class="${css.passengerCircle({ size })}">
23
+ `;
24
+ });
21
25
  return () => (
22
26
  <AmapMarker position={props.position} content={contentRef.value} anchor={"bottom-center"} />
23
27
  );
24
28
  });
25
29
 
26
30
  export const GPassengerCircle = defineSetup(function GPassengerCircle(props: PassengerCircleProps) {
27
- const contentRef = computed(() =>
28
- createDom("img", { class: css.passengerCircle, src: imgPassengerCircle })
29
- );
31
+ const contentRef = computed(() => {
32
+ const { size = "large" } = props;
33
+ const src = size === "large" ? imgPassengerCircle : imgPlaceCircle;
34
+ return createDom("img", { class: css.passengerCircle({ size }), src });
35
+ });
30
36
  return () => (
31
37
  <GmapAdvancedMarkerView position={vec2lnglat(props.position)} content={contentRef.value} />
32
38
  );
@@ -45,10 +45,20 @@ export const gmapPlaceIconLayout = recipe({
45
45
  },
46
46
  });
47
47
 
48
- export const placeIcon = style({
49
- display: "flex",
50
- width: "4.53vw",
51
- height: "4.53vw",
48
+ export const placeIcon = recipe({
49
+ base: {
50
+ display: "flex",
51
+ width: "4.53vw",
52
+ height: "4.53vw",
53
+ },
54
+ variants: {
55
+ hideIcon: {
56
+ true: {
57
+ opacity: 0,
58
+ },
59
+ false: {},
60
+ },
61
+ },
52
62
  });
53
63
 
54
64
  export const label = style({
@@ -4,7 +4,7 @@ import { AmapMarker } from "../../components/AmapMarker";
4
4
  import { GmapAdvancedMarkerView } from "../../components/GmapAdvancedMarkerView";
5
5
  import { useMapSupplier } from "../../hooks/useMapSupplier";
6
6
  import { AnchorType } from "../../types/amap/marker";
7
- import { createElement, defineSetup } from "../../types/helper";
7
+ import { createElement, defineLagecySetup, defineSetup } from "../../types/helper";
8
8
  import { createDom } from "../../utils/dom";
9
9
  import { vec2lnglat } from "../../utils/transform";
10
10
  import * as css from "./PlaceCircle.css";
@@ -13,25 +13,27 @@ export interface PlaceCircleProps {
13
13
  position: [number, number];
14
14
  label?: string;
15
15
  textAlign?: "left" | "right";
16
+ hideIcon?: boolean;
16
17
  }
17
- export const APlaceCircle = defineSetup(function APlaceCircle(props: PlaceCircleProps) {
18
+ export const APlaceCircle = defineLagecySetup(function APlaceCircle(props: PlaceCircleProps) {
18
19
  const textAlignRef = computed(() => props.textAlign ?? "right");
19
- const contentRef = computed(
20
- () => `
21
- <div class="${css.placeCircleLayout({ textAlign: textAlignRef.value })}" >
22
- <img class="${css.placeIcon} ${css.amapPlaceIconLayout({
20
+ const contentRef = computed(() => {
21
+ const { hideIcon = false } = props;
22
+ return `
23
+ <div class="${css.placeCircleLayout({ textAlign: textAlignRef.value })}">
24
+ <img class="${css.placeIcon({ hideIcon })} ${css.amapPlaceIconLayout({
23
25
  textAlign: textAlignRef.value,
24
26
  })}" src="${imgPlaceCircle}">
25
- <div class="${css.label}">${props.label}</div>
26
- </div>
27
- `
28
- );
29
- const contentWithoutLabelRef = computed(
30
- () =>
31
- `<img class="${css.placeIcon} ${css.amapPlaceIconLayout({
32
- textAlign: textAlignRef.value,
33
- })}" src="${imgPlaceCircle}">`
34
- );
27
+ <div class="${css.label}">${props.label}</div>
28
+ </div>
29
+ `;
30
+ });
31
+ const contentWithoutLabelRef = computed(() => {
32
+ const { hideIcon = false } = props;
33
+ return `<img class="${css.placeIcon({ hideIcon })} ${css.amapPlaceIconLayout({
34
+ textAlign: textAlignRef.value,
35
+ })}" src="${imgPlaceCircle}">`;
36
+ });
35
37
  return () => (
36
38
  <AmapMarker
37
39
  position={props.position}
@@ -39,12 +41,13 @@ export const APlaceCircle = defineSetup(function APlaceCircle(props: PlaceCircle
39
41
  anchor={textAlignRef.value === "left" ? AnchorType.middleRight : AnchorType.middleLeft}
40
42
  />
41
43
  );
42
- });
44
+ }).props(["hideIcon", "label", "position", "textAlign"]);
43
45
 
44
- export const GPlaceCircle = defineSetup(function GPlaceCircle(props: PlaceCircleProps) {
46
+ export const GPlaceCircle = defineLagecySetup(function GPlaceCircle(props: PlaceCircleProps) {
45
47
  const textAlignRef = computed(() => props.textAlign ?? "right");
46
- const contentRef = computed(() =>
47
- createDom(
48
+ const contentRef = computed(() => {
49
+ const { hideIcon = false } = props;
50
+ return createDom(
48
51
  "div",
49
52
  {
50
53
  class: `${css.placeCircleLayout({
@@ -52,24 +55,27 @@ export const GPlaceCircle = defineSetup(function GPlaceCircle(props: PlaceCircle
52
55
  })} ${css.gmapPlaceIconLayout({ textAlign: textAlignRef.value })}`,
53
56
  },
54
57
  `
55
- <img class="${css.placeIcon}" src="${imgPlaceCircle}">
58
+ <img class="${css.placeIcon({ hideIcon })}" src="${imgPlaceCircle}">
56
59
  <div class="${css.label}">${props.label}</div>
57
60
  `
58
- )
59
- );
60
- const contentWithoutLabelRef = computed(() =>
61
- createDom("img", {
62
- class: `${css.placeIcon} ${css.gmapPlaceIconLayout({ textAlign: textAlignRef.value })}`,
61
+ );
62
+ });
63
+ const contentWithoutLabelRef = computed(() => {
64
+ const { hideIcon = false } = props;
65
+ return createDom("img", {
66
+ class: `${css.placeIcon({ hideIcon })} ${css.gmapPlaceIconLayout({
67
+ textAlign: textAlignRef.value,
68
+ })}`,
63
69
  src: imgPlaceCircle,
64
- })
65
- );
70
+ });
71
+ });
66
72
  return () => (
67
73
  <GmapAdvancedMarkerView
68
74
  position={vec2lnglat(props.position)}
69
75
  content={props.label ? contentRef.value : contentWithoutLabelRef.value}
70
76
  />
71
77
  );
72
- });
78
+ }).props(["hideIcon", "label", "position", "textAlign"]);
73
79
 
74
80
  export const PlaceCircle = defineSetup(function PlaceCircle(props: PlaceCircleProps) {
75
81
  const payload = useMapSupplier();
@@ -10,11 +10,13 @@ export interface WalkingLineProps {
10
10
  }
11
11
  export const AWalkingLine = defineSetup(function AWalkingLine(props: WalkingLineProps) {
12
12
  return () => {
13
+ const { path } = props;
14
+ if (path.length === 0) return null;
13
15
  const vw = window.innerWidth * 0.01;
14
16
  const strokeWidth = 2 * vw;
15
17
  return (
16
18
  <AmapPolyline
17
- path={props.path}
19
+ path={path}
18
20
  strokeWeight={strokeWidth}
19
21
  strokeOpacity={1}
20
22
  strokeColor={"#38A3FE"}
@@ -30,12 +32,14 @@ export const AWalkingLine = defineSetup(function AWalkingLine(props: WalkingLine
30
32
  export const GWalkingLine = defineSetup(function GWalkingLine(props: WalkingLineProps) {
31
33
  const pathRef = computed(() => props.path.map(vec2lnglat));
32
34
  return () => {
35
+ const path = pathRef.value;
36
+ if (path.length === 0) return null;
33
37
  const vw = window.innerWidth * 0.01;
34
38
  const strokeWidth = 2 * vw;
35
39
  const r = strokeWidth / 4;
36
40
  return (
37
41
  <GmapPolyline
38
- path={pathRef.value}
42
+ path={path}
39
43
  strokeWeight={strokeWidth}
40
44
  strokeOpacity={1}
41
45
  strokeColor={"transparent"}
@@ -1,6 +1,4 @@
1
1
  import { reactive, VNodeData } from "vue-demi";
2
- import { useAmap, useGmap } from "../../hooks/useMap";
3
- import { useAmapAngle, useGmapAngle } from "../../hooks/useMapAngle";
4
2
  import { useMapSupplier } from "../../hooks/useMapSupplier";
5
3
  import {
6
4
  useAWalkingRoute,
@@ -21,20 +19,16 @@ export const AWalkingRoute = defineSetup(function WalkingRoute(
21
19
  props: WalkingRouteProps,
22
20
  { slots }
23
21
  ) {
24
- const map = useAmap();
25
22
  const path = useAWalkingRoute(props);
26
- const angle = useAmapAngle(reactive({ path, map }));
27
- return () => <div>{slots.render?.(reactive({ path, angle }))}</div>;
23
+ return () => <div>{slots.render?.(reactive({ path }))}</div>;
28
24
  });
29
25
 
30
26
  export const GWalkingRoute = defineSetup(function WalkingRoute(
31
27
  props: WalkingRouteProps,
32
28
  { slots }
33
29
  ) {
34
- const map = useGmap();
35
30
  const path = useGWalkingRoute(props);
36
- const angle = useGmapAngle(reactive({ path, map }));
37
- return () => <div>{slots.render?.(reactive({ path, angle }))}</div>;
31
+ return () => <div>{slots.render?.(reactive({ path }))}</div>;
38
32
  });
39
33
 
40
34
  export const WalkingRoute = defineSetup(function WalkingRoute(props: WalkingRouteProps, { slots }) {
@@ -1,5 +1,8 @@
1
1
  import { computed } from "vue-demi";
2
- import { StartEndPoint } from "../../business-components/StartEndPoint";
2
+ import { DrivingLine } from "../../business-components/DrivingLine";
3
+ import { DrivingRoute } from "../../business-components/DrivingRoute";
4
+ import { PlaceCircle } from "../../business-components/PlaceCircle";
5
+ import { TaxiCar } from "../../business-components/TaxiCar";
3
6
  import { useBusinessMapAutoComplete } from "../../hooks-business/useBusinessMapAutoComplete";
4
7
  import {
5
8
  useBusinessMapRecomendPlace,
@@ -7,6 +10,7 @@ import {
7
10
  } from "../../hooks-business/useBusinessMapRecomendPlace";
8
11
  import { useHeycarMap } from "../../hooks/useHeycarMap";
9
12
  import { useMapFitView } from "../../hooks/useMapFitView";
13
+ import { useMapGeometry } from "../../hooks/useMapGeometry";
10
14
  import { defineSetup } from "../../types/helper";
11
15
  import { HeycarMap, MapProvider } from "../MapProvider/MapProvider";
12
16
  import * as css from "./Demo.css";
@@ -23,7 +27,7 @@ export const HeycarDemo = defineSetup(function HeycarDemo() {
23
27
  amapSecret={amapApiSecret}
24
28
  gmapId={gmapId}
25
29
  gmapKey={gmapApiKey}
26
- supplier={"amap"}
30
+ supplier={"gmap"}
27
31
  >
28
32
  <SomeHomePage />
29
33
  </MapProvider>
@@ -94,11 +98,18 @@ export const SomeHomePage = defineSetup(function SomeHomePage() {
94
98
  padding: [15, 15, 5, 15],
95
99
  autoFitTimeout: 5000,
96
100
  });
101
+ const { apiMapDistance } = useMapGeometry();
97
102
  (window as any).setCenterPlaceByRecomand = setCenterPlaceByRecomand;
98
103
  (window as any).setFitView = setFitView;
99
104
  return () => {
100
105
  return (
101
106
  <div>
107
+ distance:{" "}
108
+ {apiMapDistance(centerPoint.value, [
109
+ centerPoint.value[0] + 0.01,
110
+ centerPoint.value[1] + 0.01,
111
+ ])}{" "}
112
+ <br />
102
113
  geoLoading: {`${geoLoading.value}`} <br />
103
114
  isDragging: {`${isDragging.value}`} <br />
104
115
  geoPosition: {geoPosition.value[0]} | {geoPosition.value[1]} <br />
@@ -112,18 +123,18 @@ export const SomeHomePage = defineSetup(function SomeHomePage() {
112
123
  zoom={centerPoint.value[0] === 0 ? 3 : 13}
113
124
  mapRef={setMap}
114
125
  >
115
- <StartEndPoint
126
+ {/* <StartEndPoint
116
127
  registerOverlay={registerFitVeiw}
117
128
  position={[121.4897065, 31.0842552]}
118
129
  title={"start point"}
119
130
  type="start"
120
- />
121
- <StartEndPoint
131
+ /> */}
132
+ {/* <StartEndPoint
122
133
  registerOverlay={registerFitVeiw}
123
134
  position={[centerPoint.value[0] + 0.01, centerPoint.value[1] + 0.01]}
124
135
  title={"end point"}
125
136
  type="end"
126
- />
137
+ /> */}
127
138
  {/* <PickupPoints places={placeCandidates.value} /> */}
128
139
  {/* <AddressBox
129
140
  type="box"
@@ -139,17 +150,19 @@ export const SomeHomePage = defineSetup(function SomeHomePage() {
139
150
  ]}
140
151
  labels={["place name 1", "place name 2"]}
141
152
  /> */}
142
- {/* <DrivingRoute
153
+ <DrivingRoute
143
154
  from={[121, 31]}
144
155
  to={[121.6, 31.3]}
145
156
  render={({ path, angle }) => [
146
157
  <DrivingLine path={path} />,
147
158
  <TaxiCar position={[121, 31]} angle={angle} />,
148
159
  ]}
149
- /> */}
160
+ />
161
+ {/* <PassengerCircle position={centerPoint.value} size="small" /> */}
162
+ <PlaceCircle position={centerPoint.value} label={"some place"} hideIcon />
150
163
  {/* <WalkingRoute
151
164
  from={centerPoint.value}
152
- to={[centerPoint.value[0] + 0.1, centerPoint.value[1] + 0.1]}
165
+ to={[centerPoint.value[0] + 0.01, centerPoint.value[1] + 0.01]}
153
166
  render={({ path }) => <WalkingLine path={path} />}
154
167
  /> */}
155
168
  </HeycarMap>
@@ -1,5 +1,5 @@
1
- import { ShallowRef, shallowRef } from "vue-demi";
2
- import type { Point } from "../types/interface";
1
+ import { reactive } from "vue-demi";
2
+ import type { Point, Route } from "../types/interface";
3
3
  import { watchPostEffectForDeepOption } from "../utils/compare";
4
4
  import { useMapSupplier } from "./useMapSupplier";
5
5
 
@@ -9,7 +9,7 @@ export interface UseDrivingRouteProps {
9
9
  }
10
10
 
11
11
  export const useADrivingRoute = (props: UseDrivingRouteProps) => {
12
- const pathRef = shallowRef<Point[]>([]);
12
+ const outputRoute = reactive<Route>({ path: [], distance: 0, duration: 0 });
13
13
  const amapDriving = new AMap.Driving({});
14
14
  watchPostEffectForDeepOption(
15
15
  () => ({ ...props }),
@@ -23,17 +23,22 @@ export const useADrivingRoute = (props: UseDrivingRouteProps) => {
23
23
  case "complete": {
24
24
  let path: Point[] = [];
25
25
  const drivingResult = result as AMap.DrivingResult;
26
- for (const route of drivingResult.routes) {
27
- for (const step of route.steps) {
28
- const basicStep = step as AMap.DriveStepBasic;
29
- const stepPath = basicStep.path.map<Point>(({ lng, lat }) => [lng, lat]);
30
- path = path.concat(stepPath);
31
- }
26
+ // todo 多条导航路线的情况
27
+ const firstRoute = drivingResult.routes[0];
28
+ for (const step of firstRoute.steps) {
29
+ const basicStep = step as AMap.DriveStepBasic;
30
+ const stepPath = basicStep.path.map<Point>(({ lng, lat }) => [lng, lat]);
31
+ path = path.concat(stepPath);
32
32
  }
33
- pathRef.value = path;
33
+ outputRoute.path = path;
34
+ outputRoute.distance = firstRoute.distance;
35
+ outputRoute.duration = firstRoute.time;
34
36
  return;
35
37
  }
36
38
  case "no_data":
39
+ outputRoute.path = [];
40
+ outputRoute.distance = 0;
41
+ outputRoute.duration = 0;
37
42
  return;
38
43
  default:
39
44
  throw result;
@@ -42,35 +47,60 @@ export const useADrivingRoute = (props: UseDrivingRouteProps) => {
42
47
  );
43
48
  }
44
49
  );
45
- return pathRef;
50
+ return outputRoute;
46
51
  };
47
52
 
48
53
  export const useGDrivingRoute = (props: UseDrivingRouteProps) => {
49
- const pathRef = shallowRef<Point[]>([]);
54
+ const outputRoute = reactive<Route>({ path: [], distance: 0, duration: 0 });
50
55
  const gmapDirectionsService = new google.maps.DirectionsService();
51
56
  watchPostEffectForDeepOption(
52
57
  () => ({ ...props }),
53
58
  ({ from, to }) => {
54
- gmapDirectionsService
55
- .route({
59
+ gmapDirectionsService.route(
60
+ {
56
61
  origin: { lng: from[0], lat: from[1] },
57
62
  destination: { lng: to[0], lat: to[1] },
58
63
  travelMode: google.maps.TravelMode.DRIVING,
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;
67
- });
64
+ },
65
+ (result, status) => {
66
+ switch (status) {
67
+ case google.maps.DirectionsStatus.OK: {
68
+ let path: Point[] = [];
69
+ let distance = 0;
70
+ let duration = 0;
71
+ const firstRoute = result!.routes[0];
72
+ const stepPath = firstRoute.overview_path.map<Point>((item) => [
73
+ item.lng(),
74
+ item.lat(),
75
+ ]);
76
+ path = path.concat(stepPath);
77
+ for (const leg of firstRoute.legs) {
78
+ distance += leg.distance?.value ?? 0;
79
+ // todo 考虑用 duration_in_traffic 但这个字段上有条件的
80
+ duration += leg.duration?.value ?? 0;
81
+ }
82
+ outputRoute.path = path;
83
+ outputRoute.distance = distance;
84
+ outputRoute.duration = duration;
85
+ return;
86
+ }
87
+ case google.maps.DirectionsStatus.ZERO_RESULTS:
88
+ case google.maps.DirectionsStatus.NOT_FOUND:
89
+ outputRoute.path = [];
90
+ outputRoute.distance = 0;
91
+ outputRoute.duration = 0;
92
+ return;
93
+ default:
94
+ throw new Error(status);
95
+ }
96
+ }
97
+ );
68
98
  }
69
99
  );
70
- return pathRef;
100
+ return outputRoute;
71
101
  };
72
102
 
73
- export const useDrivingRoute = (props: UseDrivingRouteProps): ShallowRef<Point[]> => {
103
+ export const useDrivingRoute = (props: UseDrivingRouteProps): Route => {
74
104
  const { supplier } = useMapSupplier();
75
105
  return supplier === "gmap" ? useGDrivingRoute(props) : useADrivingRoute(props);
76
106
  };
@@ -5,8 +5,8 @@ export interface UseGeoLocationProps {
5
5
  onChange?: (value: { position: Point; coordinate: GeolocationCoordinates }) => any;
6
6
  onLoad?: (value: { position: Point; coordinate: GeolocationCoordinates }) => any;
7
7
  }
8
- export const useGeoLocation = (props: UseGeoLocationProps) => {
9
- const { onChange, onLoad } = props;
8
+ export const useGeoLocation = (props?: UseGeoLocationProps) => {
9
+ const { onChange, onLoad } = props ?? {};
10
10
  const loading = ref(false);
11
11
  const readyRef = ref(false);
12
12
  const errorRef = ref<GeolocationPositionError>();
@@ -0,0 +1,27 @@
1
+ import type { Point } from "../types/interface";
2
+ import { vec2lnglat } from "../utils/transform";
3
+ import { Status } from "./useMapLoader";
4
+ import { useMapSupplier } from "./useMapSupplier";
5
+
6
+ export const useAmapGeometry = () => {
7
+ const { status } = useMapSupplier();
8
+ const apiMapDistance = (from: Point, to: Point) => {
9
+ if (status !== Status.SUCCESS) return undefined;
10
+ return AMap.GeometryUtil.distance(from, to);
11
+ };
12
+ return { apiMapDistance };
13
+ };
14
+
15
+ export const useGmapGeometry = () => {
16
+ const { status } = useMapSupplier();
17
+ const apiMapDistance = (from: Point, to: Point) => {
18
+ if (status !== Status.SUCCESS) return undefined;
19
+ return google.maps.geometry.spherical.computeDistanceBetween(vec2lnglat(from), vec2lnglat(to));
20
+ };
21
+ return { apiMapDistance };
22
+ };
23
+
24
+ export const useMapGeometry = () => {
25
+ const { supplier } = useMapSupplier();
26
+ return supplier === "gmap" ? useGmapGeometry() : useAmapGeometry();
27
+ };
@@ -9,7 +9,7 @@ export const DEFAULT_AMAP_PLUGINS: AmapLoaderProps["plugins"] = [
9
9
  "AMap.Geocoder",
10
10
  "AMap.PlaceSearch",
11
11
  "AMap.Driving",
12
- "AMap.Walker",
12
+ "AMap.Walking",
13
13
  ];
14
14
  export const DEFAULT_GMAP_LIBRARIES: LoaderOptions["libraries"] = ["marker", "places", "geometry"];
15
15