@heycar/heycars-map 0.3.5 → 0.3.6
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/dist/business-components/BusinessRecomendPlaceMap/BusinessRecomendPlaceMap.d.ts +0 -1
- package/dist/business-components/PickupPoints/PickupPoints.d.ts +2 -1
- package/dist/hooks/useMapLngLatToVw.d.ts +10 -0
- package/dist/hooks/useMapRecomendPlace.d.ts +3 -0
- package/dist/hooks/usePlacesLabelDirection.d.ts +9 -0
- package/dist/hooks/useWaitTimer.d.ts +12 -0
- package/dist/index.cjs +53 -53
- package/dist/index.js +1184 -1089
- package/dist/style.css +1 -1
- package/dist/utils/transform.d.ts +2 -0
- package/package.json +1 -1
- package/src/Demo/DemoBusinessRecomendPlace.tsx +8 -4
- package/src/business-components/AbsoluteAddressBox/AbsoluteAddressBox.tsx +1 -1
- package/src/business-components/BusinessRecomendPlaceMap/BusinessRecomendPlaceMap.tsx +17 -9
- package/src/business-components/PickupPoints/PickupPoints.tsx +24 -11
- package/src/business-components/PlaceCircle/PlaceCircle.css.ts +7 -2
- package/src/hooks/useGeoLocation.ts +3 -2
- package/src/hooks/useMapDrag.ts +0 -1
- package/src/hooks/useMapFitView.ts +0 -1
- package/src/hooks/useMapLngLatToVw.ts +31 -0
- package/src/hooks/useMapRecomendPlace.ts +17 -2
- package/src/hooks/usePlacesLabelDirection.ts +61 -0
- package/src/hooks/useWaitTimer.ts +25 -0
- package/src/hooks/useWalkingRoute.ts +0 -1
- package/src/utils/transform.ts +8 -0
- package/todo.md +1 -0
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.n8tgem0{pointer-events:none;position:absolute;bottom:50%;left:0;right:0;margin-left:auto;margin-right:auto;display:flex;flex-direction:column;align-items:center;z-index:1}.n8tgem1{pointer-events:auto;padding:2.67vw 4.27vw;background:linear-gradient(90deg,#79AFFF 0%,#5C8DFF 32%,#507FFF 75%,#4471FF 100%);border-radius:3.2vw;display:flex;align-items:center}.n8tgem2{padding-right:2.67vw;max-width:41.33vw}.n8tgem3{display:-webkit-box;font-size:3.47vw;font-family:PingFangSC-Semibold,PingFang SC;font-weight:600;color:#fff;line-height:4.8vw;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.n8tgem4{margin-top:.53vw;font-size:2.93vw;font-family:PingFangSC-Regular,PingFang SC;font-weight:400;color:#fff;line-height:4.27vw;opacity:.8}.n8tgem5{width:1.758vw;height:2.93vw}.n8tgem6{width:.8vw;height:4vw;background:#4C80FF;border-radius:0vw 0vw 26.67vw 26.67vw}.n8tgem7{width:6.9355vw;height:10.67vw}.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}._1d8ur7t0,._7anfuo0{position:relative}._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}._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.
|
|
1
|
+
.n8tgem0{pointer-events:none;position:absolute;bottom:50%;left:0;right:0;margin-left:auto;margin-right:auto;display:flex;flex-direction:column;align-items:center;z-index:1}.n8tgem1{pointer-events:auto;padding:2.67vw 4.27vw;background:linear-gradient(90deg,#79AFFF 0%,#5C8DFF 32%,#507FFF 75%,#4471FF 100%);border-radius:3.2vw;display:flex;align-items:center}.n8tgem2{padding-right:2.67vw;max-width:41.33vw}.n8tgem3{display:-webkit-box;font-size:3.47vw;font-family:PingFangSC-Semibold,PingFang SC;font-weight:600;color:#fff;line-height:4.8vw;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.n8tgem4{margin-top:.53vw;font-size:2.93vw;font-family:PingFangSC-Regular,PingFang SC;font-weight:400;color:#fff;line-height:4.27vw;opacity:.8}.n8tgem5{width:1.758vw;height:2.93vw}.n8tgem6{width:.8vw;height:4vw;background:#4C80FF;border-radius:0vw 0vw 26.67vw 26.67vw}.n8tgem7{width:6.9355vw;height:10.67vw}.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}._1d8ur7t0,._7anfuo0{position:relative}._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}._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{display:-webkit-box;font-size:3.2vw;font-family:PingFangSC-Semibold,PingFang SC;font-weight:600;color:#243e66;line-height:4.53vw;width:max-content;max-width:32vw;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}._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}
|
|
@@ -13,3 +13,5 @@ export declare const language2vectorMapForeign: (lang: "en" | "zh") => VectorMap
|
|
|
13
13
|
export declare const place2point: (place: Place) => Point;
|
|
14
14
|
export declare const pipeAsync: <P extends any[]>(fn?: ((...args: P) => any) | undefined) => (...args: P) => void;
|
|
15
15
|
export declare const geocoderResult2cityName: (value: google.maps.GeocoderResult) => string | undefined;
|
|
16
|
+
export declare const isPlaceEqual: (p1: Place, p2?: Place) => boolean;
|
|
17
|
+
export declare const isPointEqual: (p1: Point, p2?: Point) => boolean;
|
package/package.json
CHANGED
|
@@ -42,8 +42,13 @@ export const DemoBusinessRecomendPlace = defineSetup(function DemoBusinessRecome
|
|
|
42
42
|
const { lat, lng } = place;
|
|
43
43
|
console.log("getRecomendPlace context?.source = ", context?.source);
|
|
44
44
|
return [
|
|
45
|
-
{
|
|
46
|
-
|
|
45
|
+
{
|
|
46
|
+
lat: lat + 0.1001,
|
|
47
|
+
lng: lng + 0.0001,
|
|
48
|
+
name: "Blessing Koko Dayc are Blessing Koko which is a very long name",
|
|
49
|
+
},
|
|
50
|
+
{ lat: lat + 0.0002, lng: lng + 0.0003, name: "place name 2" },
|
|
51
|
+
{ lat: lat + 0.0003, lng: lng + 0.0002, name: "place name 3" },
|
|
47
52
|
];
|
|
48
53
|
};
|
|
49
54
|
const {
|
|
@@ -64,10 +69,9 @@ export const DemoBusinessRecomendPlace = defineSetup(function DemoBusinessRecome
|
|
|
64
69
|
<SomeAutoComplete cityName="Shinjuku-ku"></SomeAutoComplete>
|
|
65
70
|
<BusinessRecomendPlaceMap
|
|
66
71
|
class={css.demo}
|
|
67
|
-
geoErrorTitle={"定位获取失败\n请手动设置上车点"}
|
|
68
72
|
geoLoadingTitle={"正在读取GPS位置信息..."}
|
|
69
73
|
unavailableTitle={"当前区域暂未开通服务"}
|
|
70
|
-
noRecomendDescription={"
|
|
74
|
+
noRecomendDescription={""}
|
|
71
75
|
recomendDescription={"最佳上车地点"}
|
|
72
76
|
geoDefaultPosition={[139.728287, 35.661007]}
|
|
73
77
|
getRecomendPlace={getRecomendPlace}
|
|
@@ -39,7 +39,7 @@ export const AbsoluteAddressBox = defineSetup(function AbsoluteAddressBox(
|
|
|
39
39
|
<div class={css.absoluteAddressBox} onClick={handleClick}>
|
|
40
40
|
<div class={css.boxTextLayout}>
|
|
41
41
|
<MultilineTitle class={css.boxTitle} value={title} />
|
|
42
|
-
{description && <div class={css.boxDescription}>{description}</div>}
|
|
42
|
+
{!!description && <div class={css.boxDescription}>{description}</div>}
|
|
43
43
|
</div>
|
|
44
44
|
<img class={css.arrowRight} src={imgArrowRight} />
|
|
45
45
|
</div>
|
|
@@ -8,13 +8,16 @@ import { MapLogProps, useMapLog } from "../../hooks/useMapLog";
|
|
|
8
8
|
import type { UseMapPlaceProps } from "../../hooks/useMapPlace";
|
|
9
9
|
import { useMapRecomendPlace, UseMapRecomendPlaceProps } from "../../hooks/useMapRecomendPlace";
|
|
10
10
|
import { useMapSupplier } from "../../hooks/useMapSupplier";
|
|
11
|
+
import { useWaitTimer } from "../../hooks/useWaitTimer";
|
|
11
12
|
import { defineLagecySetup } from "../../types/helper";
|
|
12
13
|
import type { Place, Point } from "../../types/interface";
|
|
14
|
+
import { isPlaceEqual } from "../../utils/transform";
|
|
13
15
|
import { AbsoluteAddressBox, AbsoluteAddressBoxProps } from "../AbsoluteAddressBox";
|
|
14
16
|
import { PassengerCircle } from "../PassengerCircle";
|
|
15
17
|
import { PickupPoints } from "../PickupPoints";
|
|
16
18
|
|
|
17
19
|
const RECOMMEND_PLACE_LIMIT = 30;
|
|
20
|
+
const MAP_DRAG_END_WAIT_ANIMATION = 500;
|
|
18
21
|
|
|
19
22
|
export interface CenterPlaceSource {
|
|
20
23
|
source: "default" | "geo" | "drag" | "recomend" | "api";
|
|
@@ -24,7 +27,6 @@ export interface BusinessRecomendPlaceMapProps
|
|
|
24
27
|
Pick<UseMapRecomendPlaceProps<CenterPlaceSource>, "getRecomendPlace">,
|
|
25
28
|
MapLogProps {
|
|
26
29
|
geoLoadingTitle: string;
|
|
27
|
-
geoErrorTitle: string;
|
|
28
30
|
unavailableTitle: string;
|
|
29
31
|
recomendDescription: string;
|
|
30
32
|
noRecomendDescription: string;
|
|
@@ -46,6 +48,7 @@ export const BusinessRecomendPlaceMap = defineLagecySetup(
|
|
|
46
48
|
const { geoDefaultPosition, getRecomendPlace, mapContext } = props;
|
|
47
49
|
const { mapRef, setMap } = useHeycarMap();
|
|
48
50
|
const { readyPromise } = useMapSupplier();
|
|
51
|
+
const { timerStart, timerStop } = useWaitTimer({ interval: MAP_DRAG_END_WAIT_ANIMATION });
|
|
49
52
|
const centerPlace = reactive<Place>({
|
|
50
53
|
lng: geoDefaultPosition?.[0] ?? 0,
|
|
51
54
|
lat: geoDefaultPosition?.[1] ?? 0,
|
|
@@ -99,6 +102,7 @@ export const BusinessRecomendPlaceMap = defineLagecySetup(
|
|
|
99
102
|
mapRef,
|
|
100
103
|
onChange: (point) => {
|
|
101
104
|
centerSource.source = "drag";
|
|
105
|
+
timerStart();
|
|
102
106
|
updatePlace(point);
|
|
103
107
|
emit("changeByDrag", point);
|
|
104
108
|
},
|
|
@@ -110,6 +114,7 @@ export const BusinessRecomendPlaceMap = defineLagecySetup(
|
|
|
110
114
|
updateRecomandPlace,
|
|
111
115
|
placeCandidates,
|
|
112
116
|
availableRef,
|
|
117
|
+
isElectedRef,
|
|
113
118
|
} = useMapRecomendPlace({
|
|
114
119
|
pointRef: centerPoint,
|
|
115
120
|
context: centerSource,
|
|
@@ -133,7 +138,8 @@ export const BusinessRecomendPlaceMap = defineLagecySetup(
|
|
|
133
138
|
}
|
|
134
139
|
emit("changePlace", place);
|
|
135
140
|
},
|
|
136
|
-
onChange: (place) => {
|
|
141
|
+
onChange: async (place) => {
|
|
142
|
+
await timerStop.promise;
|
|
137
143
|
centerSource.source = "recomend";
|
|
138
144
|
Object.assign(centerPlace, { ...place });
|
|
139
145
|
emit("changeRecomandPlace", place);
|
|
@@ -151,21 +157,24 @@ export const BusinessRecomendPlaceMap = defineLagecySetup(
|
|
|
151
157
|
return () => {
|
|
152
158
|
const title = geoLoading.value
|
|
153
159
|
? props.geoLoadingTitle
|
|
154
|
-
: geoError.value
|
|
155
|
-
? props.geoErrorTitle
|
|
156
160
|
: availableRef.value
|
|
157
161
|
? centerPlace.name
|
|
158
162
|
: props.unavailableTitle;
|
|
159
163
|
const description =
|
|
160
|
-
!availableRef.value ||
|
|
164
|
+
!availableRef.value || geoLoading.value
|
|
161
165
|
? undefined
|
|
162
|
-
:
|
|
166
|
+
: isElectedRef.value
|
|
163
167
|
? props.recomendDescription
|
|
164
168
|
: props.noRecomendDescription;
|
|
165
169
|
return (
|
|
166
170
|
<HeycarMap center={centerPoint.value} zoom={18} mapRef={setMap} log={props.log}>
|
|
167
|
-
<PassengerCircle position={geoPosition.value} />
|
|
168
|
-
<PickupPoints
|
|
171
|
+
{!geoError.value && <PassengerCircle position={geoPosition.value} />}
|
|
172
|
+
<PickupPoints
|
|
173
|
+
places={placeCandidates.value}
|
|
174
|
+
renderLabel={(place) => (isPlaceEqual(place, centerPlace) ? undefined : place.name)}
|
|
175
|
+
onClick={setCenterByPlace}
|
|
176
|
+
log={props.log}
|
|
177
|
+
/>
|
|
169
178
|
<AbsoluteAddressBox
|
|
170
179
|
title={title}
|
|
171
180
|
description={description}
|
|
@@ -179,7 +188,6 @@ export const BusinessRecomendPlaceMap = defineLagecySetup(
|
|
|
179
188
|
}
|
|
180
189
|
).props([
|
|
181
190
|
"log",
|
|
182
|
-
"geoErrorTitle",
|
|
183
191
|
"geoLoadingTitle",
|
|
184
192
|
"unavailableTitle",
|
|
185
193
|
"recomendDescription",
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { reactive, toRef } from "vue-demi";
|
|
1
2
|
import { MapLogProps, useMapLog } from "../../hooks/useMapLog";
|
|
3
|
+
import { usePointsLabelDirection } from "../../hooks/usePlacesLabelDirection";
|
|
2
4
|
import { defineSetup } from "../../types/helper";
|
|
3
5
|
import type { Place } from "../../types/interface";
|
|
4
6
|
import { place2point } from "../../utils/transform";
|
|
@@ -6,20 +8,31 @@ import { PlaceCircle } from "../PlaceCircle";
|
|
|
6
8
|
|
|
7
9
|
export interface PickupPointsProps extends MapLogProps {
|
|
8
10
|
places: Place[];
|
|
11
|
+
renderLabel?: (place: Place) => string | undefined;
|
|
9
12
|
onClick?: (value: Place) => any;
|
|
10
13
|
}
|
|
11
14
|
export const PickupPoints = defineSetup(function PickupPoints(props: PickupPointsProps, { emit }) {
|
|
12
15
|
useMapLog(props, "PickupPoints");
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
<PlaceCircle
|
|
17
|
-
position={place2point(place)}
|
|
18
|
-
label={place.name}
|
|
19
|
-
textAlign="left"
|
|
20
|
-
onClick={() => emit("click", place)}
|
|
21
|
-
/>
|
|
22
|
-
))}
|
|
23
|
-
</div>
|
|
16
|
+
const { renderLabel } = props;
|
|
17
|
+
const directions = usePointsLabelDirection(
|
|
18
|
+
reactive({ places: toRef(props, "places"), heightLimit: 9, widthLimit: 32 })
|
|
24
19
|
);
|
|
20
|
+
return () => {
|
|
21
|
+
return (
|
|
22
|
+
<div>
|
|
23
|
+
{props.places.map((place, idx) => {
|
|
24
|
+
const direction = directions.value[idx];
|
|
25
|
+
const label = renderLabel ? renderLabel(place) : place.name;
|
|
26
|
+
return (
|
|
27
|
+
<PlaceCircle
|
|
28
|
+
position={place2point(place)}
|
|
29
|
+
label={label}
|
|
30
|
+
textAlign={direction}
|
|
31
|
+
onClick={() => emit("click", place)}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
})}
|
|
35
|
+
</div>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
25
38
|
});
|
|
@@ -62,10 +62,15 @@ export const placeIcon = recipe({
|
|
|
62
62
|
});
|
|
63
63
|
|
|
64
64
|
export const label = style({
|
|
65
|
-
|
|
65
|
+
display: "-webkit-box",
|
|
66
|
+
fontSize: "3.2vw",
|
|
66
67
|
fontFamily: "PingFangSC-Semibold, PingFang SC",
|
|
67
68
|
fontWeight: 600,
|
|
68
69
|
color: "#243E66",
|
|
69
70
|
lineHeight: "4.53vw",
|
|
70
|
-
|
|
71
|
+
width: "max-content",
|
|
72
|
+
maxWidth: "32vw",
|
|
73
|
+
WebkitLineClamp: 2,
|
|
74
|
+
WebkitBoxOrient: "vertical",
|
|
75
|
+
overflow: "hidden",
|
|
71
76
|
});
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { ref, watch } from "vue-demi";
|
|
2
2
|
import type { Point } from "../types/interface";
|
|
3
3
|
|
|
4
|
+
const GEO_TIMEOUT = 5000;
|
|
5
|
+
|
|
4
6
|
export interface UseGeoLocationProps {
|
|
5
7
|
geoDefaultPosition?: Point;
|
|
6
8
|
onChange?: (value: { position: Point; coordinate: GeolocationCoordinates }) => any;
|
|
@@ -52,8 +54,7 @@ export const useGeoLocation = (props?: UseGeoLocationProps) => {
|
|
|
52
54
|
onError?.(error);
|
|
53
55
|
console.log("errorRef = ", errorRef);
|
|
54
56
|
},
|
|
55
|
-
|
|
56
|
-
{ timeout: 3000, maximumAge: 0, enableHighAccuracy: false }
|
|
57
|
+
{ timeout: GEO_TIMEOUT, maximumAge: 0, enableHighAccuracy: false }
|
|
57
58
|
);
|
|
58
59
|
onCleanup(() => navigator.geolocation.clearWatch(watchId));
|
|
59
60
|
},
|
package/src/hooks/useMapDrag.ts
CHANGED
|
@@ -23,7 +23,6 @@ export const useAmapDrag = (props: UseMapDragProps<AMap.Map>) => {
|
|
|
23
23
|
});
|
|
24
24
|
};
|
|
25
25
|
const emitDragEnd: SetupContextEmitHandler<Pick<AmapProps, "onDragEnd">> = (_, { target }) => {
|
|
26
|
-
console.log("on DragEnd ------");
|
|
27
26
|
isDragging.value = false;
|
|
28
27
|
const { lng, lat } = target.getCenter();
|
|
29
28
|
centerRef.value = [lng, lat];
|
|
@@ -32,7 +32,6 @@ export const useAmapFitView = (props: UseMapFitViewProps<AMap.Map>) => {
|
|
|
32
32
|
if (!map) return;
|
|
33
33
|
const vw = window.innerWidth / 100;
|
|
34
34
|
const [top, right, bottom, left] = props.padding ?? [0, 0, 0, 0];
|
|
35
|
-
console.log([...overlayGroup]);
|
|
36
35
|
map.setFitView([...overlayGroup], false, [top * vw, bottom * vw, left * vw, right * vw]);
|
|
37
36
|
};
|
|
38
37
|
const registerFitVeiw: RegisterOverlay<AmapOverlay> = {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Point } from "../types/interface";
|
|
2
|
+
import { useAmap, useGmap } from "./useMap";
|
|
3
|
+
import { useMapSupplier } from "./useMapSupplier";
|
|
4
|
+
|
|
5
|
+
export const useAmapLngLatToVw = () => {
|
|
6
|
+
const amap = useAmap();
|
|
7
|
+
const apiMapLngLatToVw = (point: Point) => {
|
|
8
|
+
return amap?.value?.lngLatToContainer(point).toArray() as [number, number];
|
|
9
|
+
};
|
|
10
|
+
return { apiMapLngLatToVw };
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const useGmapLngLatToVw = () => {
|
|
14
|
+
const gmap = useGmap();
|
|
15
|
+
const apiMapLngLatToVw = (point: Point) => {
|
|
16
|
+
const [lng, lat] = point;
|
|
17
|
+
const projection = gmap?.value?.getProjection();
|
|
18
|
+
const worldCoordinate = projection?.fromLatLngToPoint({ lng, lat });
|
|
19
|
+
const x = worldCoordinate?.x ?? 0;
|
|
20
|
+
const y = worldCoordinate?.y ?? 0;
|
|
21
|
+
const zoom = gmap?.value?.getZoom() ?? 0;
|
|
22
|
+
const scale = 2 ** zoom;
|
|
23
|
+
return [x * scale, y * scale] as [number, number];
|
|
24
|
+
};
|
|
25
|
+
return { apiMapLngLatToVw };
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const useMapLngLatToVw = () => {
|
|
29
|
+
const { supplier } = useMapSupplier();
|
|
30
|
+
return supplier === "gmap" ? useGmapLngLatToVw() : useAmapLngLatToVw();
|
|
31
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { reactive, ref, Ref, watch } from "vue-demi";
|
|
1
|
+
import { computed, reactive, ref, Ref, watch } from "vue-demi";
|
|
2
2
|
import type { Place, Point } from "../types/interface";
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
import { isPointEqual, place2point } from "../utils/transform";
|
|
4
5
|
import { useAmapPlace, useGmapPlace, UseMapPlaceProps } from "./useMapPlace";
|
|
5
6
|
import { useMapSupplier } from "./useMapSupplier";
|
|
6
7
|
import { useUpdate } from "./useUdate";
|
|
@@ -52,6 +53,12 @@ export const useAmapRecomendPlace = <C>(props: UseMapRecomendPlaceProps<C>) => {
|
|
|
52
53
|
onChangeCity,
|
|
53
54
|
});
|
|
54
55
|
const recomendPlace = reactive<Place>({ ...place });
|
|
56
|
+
const isElectedRef = computed(() => {
|
|
57
|
+
const point = pointRef.value;
|
|
58
|
+
return placeCandidatesRef.value.some((candidate) =>
|
|
59
|
+
isPointEqual(place2point(candidate), point)
|
|
60
|
+
);
|
|
61
|
+
});
|
|
55
62
|
watch(
|
|
56
63
|
() => recomendPlaceKey.value,
|
|
57
64
|
async () => {
|
|
@@ -77,6 +84,7 @@ export const useAmapRecomendPlace = <C>(props: UseMapRecomendPlaceProps<C>) => {
|
|
|
77
84
|
recomendPlace,
|
|
78
85
|
placeCandidates: placeCandidatesRef,
|
|
79
86
|
availableRef,
|
|
87
|
+
isElectedRef,
|
|
80
88
|
updateRecomandPlace,
|
|
81
89
|
updatePlace,
|
|
82
90
|
setPlace,
|
|
@@ -97,6 +105,12 @@ export const useGmapRecomendPlace = <C>(props: UseMapRecomendPlaceProps<C>) => {
|
|
|
97
105
|
onChangeCity,
|
|
98
106
|
});
|
|
99
107
|
const recomendPlace = reactive<Place>({ ...place });
|
|
108
|
+
const isElectedRef = computed(() => {
|
|
109
|
+
const point = pointRef.value;
|
|
110
|
+
return placeCandidatesRef.value.some((candidate) =>
|
|
111
|
+
isPointEqual(place2point(candidate), point)
|
|
112
|
+
);
|
|
113
|
+
});
|
|
100
114
|
watch(
|
|
101
115
|
() => recomendPlaceKey.value,
|
|
102
116
|
async () => {
|
|
@@ -122,6 +136,7 @@ export const useGmapRecomendPlace = <C>(props: UseMapRecomendPlaceProps<C>) => {
|
|
|
122
136
|
recomendPlace,
|
|
123
137
|
placeCandidates: placeCandidatesRef,
|
|
124
138
|
availableRef,
|
|
139
|
+
isElectedRef,
|
|
125
140
|
updateRecomandPlace,
|
|
126
141
|
updatePlace,
|
|
127
142
|
setPlace,
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ref } from "vue-demi";
|
|
2
|
+
import type { Place, Point } from "../types/interface";
|
|
3
|
+
import { watchEffectForDeepOption } from "../utils/compare";
|
|
4
|
+
import { place2point } from "../utils/transform";
|
|
5
|
+
import { useMapLngLatToVw } from "./useMapLngLatToVw";
|
|
6
|
+
|
|
7
|
+
type LabelDirection = "left" | "right";
|
|
8
|
+
const reverse = (direction: LabelDirection) => (direction === "left" ? "right" : "left");
|
|
9
|
+
|
|
10
|
+
export interface UsePointsLabelDirectionProps {
|
|
11
|
+
places: Place[];
|
|
12
|
+
widthLimit: number;
|
|
13
|
+
heightLimit: number;
|
|
14
|
+
}
|
|
15
|
+
export const usePointsLabelDirection = (props: UsePointsLabelDirectionProps) => {
|
|
16
|
+
const { widthLimit, heightLimit } = props;
|
|
17
|
+
const { apiMapLngLatToVw } = useMapLngLatToVw();
|
|
18
|
+
const diffVw = (from: Point, to: Point) => {
|
|
19
|
+
const vw = 100 / window.innerWidth;
|
|
20
|
+
const [x1, y1] = apiMapLngLatToVw(from);
|
|
21
|
+
const [x2, y2] = apiMapLngLatToVw(to);
|
|
22
|
+
return [(x2 - x1) * vw, (y2 - y1) * vw];
|
|
23
|
+
};
|
|
24
|
+
const directionsRef = ref<LabelDirection[]>(Array(props.places.length).fill("right"));
|
|
25
|
+
watchEffectForDeepOption(
|
|
26
|
+
() => props.places.map(place2point),
|
|
27
|
+
(points) => {
|
|
28
|
+
const sortedPoints = points
|
|
29
|
+
.map((point, index) => ({ point, index }))
|
|
30
|
+
.sort(({ point: [, lat1] }, { point: [, lat2] }) =>
|
|
31
|
+
lat1 < lat2 ? 1 : lat1 > lat2 ? -1 : 0
|
|
32
|
+
);
|
|
33
|
+
const len = points.length;
|
|
34
|
+
const result: LabelDirection[] = Array(len);
|
|
35
|
+
let prevDirection: LabelDirection = "right";
|
|
36
|
+
let isLimited = false;
|
|
37
|
+
for (let idx = 0; idx < len; idx++) {
|
|
38
|
+
const { index } = sortedPoints[idx];
|
|
39
|
+
if (idx === len - 1) {
|
|
40
|
+
result[index] = isLimited ? reverse(prevDirection) : "right";
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (idx === 0) {
|
|
44
|
+
const [dx, dy] = diffVw(sortedPoints[idx].point, sortedPoints[idx + 1].point);
|
|
45
|
+
isLimited = dx > -widthLimit && dx < widthLimit && dy > -heightLimit && dy < heightLimit;
|
|
46
|
+
const direction: LabelDirection = !isLimited ? "right" : dx > 0 ? "left" : "right";
|
|
47
|
+
result[index] = direction;
|
|
48
|
+
prevDirection = direction;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const [dx, dy] = diffVw(sortedPoints[idx].point, sortedPoints[idx + 1].point);
|
|
52
|
+
const direction: LabelDirection = isLimited ? reverse(prevDirection) : "right";
|
|
53
|
+
result[index] = direction;
|
|
54
|
+
prevDirection = direction;
|
|
55
|
+
isLimited = dx > -widthLimit && dx < widthLimit && dy > -heightLimit && dy < heightLimit;
|
|
56
|
+
}
|
|
57
|
+
directionsRef.value = result;
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
return directionsRef;
|
|
61
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
interface TimerStop {
|
|
2
|
+
promise: Promise<void>;
|
|
3
|
+
resolve?: () => void;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface UseWaitTimerProps {
|
|
7
|
+
interval: number;
|
|
8
|
+
}
|
|
9
|
+
export const useWaitTimer = (props: UseWaitTimerProps) => {
|
|
10
|
+
const { interval } = props;
|
|
11
|
+
let timer: number | undefined = undefined;
|
|
12
|
+
const timerStop: TimerStop = {
|
|
13
|
+
promise: Promise.resolve(),
|
|
14
|
+
resolve: undefined,
|
|
15
|
+
};
|
|
16
|
+
const timerStart = () => {
|
|
17
|
+
if (timer) clearTimeout(timer);
|
|
18
|
+
timerStop.resolve?.();
|
|
19
|
+
timerStop.promise = new Promise((resolve) => {
|
|
20
|
+
timerStop.resolve = resolve;
|
|
21
|
+
timer = setTimeout(resolve, interval);
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
return { timerStart, timerStop };
|
|
25
|
+
};
|
|
@@ -23,7 +23,6 @@ export const useAWalkingRoute = (props: UseWalkingRouteProps) => {
|
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
25
|
const firstRoute = walkingResult.routes[0];
|
|
26
|
-
console.log("firstRoute = ", firstRoute);
|
|
27
26
|
for (const step of firstRoute.steps) {
|
|
28
27
|
const stepPath = step.path.map<Point>(({ lng, lat }) => [lng, lat]);
|
|
29
28
|
path = path.concat(stepPath);
|
package/src/utils/transform.ts
CHANGED
|
@@ -58,3 +58,11 @@ export const geocoderResult2cityName = (value: google.maps.GeocoderResult): stri
|
|
|
58
58
|
if (countryIdx > 0) return address_components[countryIdx - 1].long_name;
|
|
59
59
|
return undefined;
|
|
60
60
|
};
|
|
61
|
+
|
|
62
|
+
export const isPlaceEqual = (p1: Place, p2?: Place) => {
|
|
63
|
+
return p1.lng === p2?.lng && p1.lat === p2?.lat;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const isPointEqual = (p1: Point, p2?: Point) => {
|
|
67
|
+
return p1[0] === p2?.[0] && p1[1] === p2?.[1];
|
|
68
|
+
};
|
package/todo.md
CHANGED