@hzab/map-combine 0.4.2-alpha.1 → 0.4.2-alpha.11

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.
@@ -1,185 +1,199 @@
1
- import { AMap } from "./AMap";
2
- import { Polyline } from "../basic/Polyline";
3
-
4
- export function drawPolyline(map: AMap, polyline: Polyline<unknown>) {
5
- const { event, viewer, LbsAMap } = map;
6
-
7
- let status = 0;
8
- let skip = 0;
9
- let target = null;
10
- let aMapPolylineEditor = null;
11
-
12
- const _event = {
13
- cursor: polyline.cursor,
14
- silent: polyline.silent,
15
- onPointerIn() {
16
- status == 2 && polyline.event.trigger("pointer-in");
17
- },
18
- onPointerOut() {
19
- status == 2 && polyline.event.trigger("pointer-out");
20
- },
21
- onLClick() {
22
- status == 2 && polyline.event.trigger("left-click");
23
- },
24
- onRClick(e) {
25
- event.canvas = [e.pixel.x, e.pixel.y];
26
- if (polyline.menu) {
27
- map.menu.show(polyline.menu);
28
- }
29
- status == 2 && polyline.event.trigger("right-click");
30
- },
31
- onDbClick() {
32
- polyline.editable &&
33
- status == 2 &&
34
- setTimeout(() => {
35
- aMapPolylineEditor.setTarget(target);
36
- aMapPolylineEditor.open();
37
- polyline.event.trigger("start-edit");
38
- });
39
- },
40
- };
41
-
42
- const bindEvent = (graphical) => {
43
- graphical.on("click", _event.onLClick);
44
- graphical.on("rightclick", _event.onRClick);
45
- graphical.on("dblclick", _event.onDbClick);
46
- graphical.on("mouseover", _event.onPointerIn);
47
- graphical.on("mouseout", _event.onPointerOut);
48
- };
49
-
50
- aMapPolylineEditor = new LbsAMap.PolylineEditor(viewer, undefined, {
51
- createOptions: {
52
- strokeColor: polyline.stroke,
53
- strokeWeight: polyline.lineWidth,
54
- strokeStyle: polyline.dash ? "dashed" : "solid",
55
- strokeDasharray: [10, 10],
56
- },
57
- editOptions: {
58
- strokeColor: polyline.stroke,
59
- strokeWeight: polyline.lineWidth,
60
- strokeStyle: polyline.dash ? "dashed" : "solid",
61
- strokeDasharray: [10, 10],
62
- },
63
- });
64
-
65
- aMapPolylineEditor.on("add", (e) => {
66
- status = 3;
67
- target = e.target;
68
- bindEvent(target);
69
- // polygon.event.trigger("data-loaded");
70
- });
71
-
72
- if (polyline.coordinates) {
73
- status = 2;
74
- target = new LbsAMap.Polyline({
75
- path: polyline.coordinates,
76
- strokeColor: polyline.stroke,
77
- strokeWeight: polyline.lineWidth,
78
- strokeStyle: polyline.dash ? "dashed" : "solid",
79
- strokeDasharray: [10, 10],
80
- });
81
- viewer.add(target);
82
- bindEvent(target);
83
- } else {
84
- aMapPolylineEditor.close();
85
- aMapPolylineEditor.setTarget();
86
- aMapPolylineEditor.open();
87
- }
88
- const onUpdate = (e: Set<string>) => {
89
- if (skip) {
90
- skip--;
91
- return;
92
- }
93
-
94
- e.forEach((key) => {
95
- switch (key) {
96
- case "show":
97
- if (polyline.show) {
98
- target.show();
99
- } else {
100
- target.hide();
101
- }
102
- break;
103
- case "editable":
104
- break;
105
- case "coordinates":
106
- if (polyline.coordinates) {
107
- target.setPath(polyline.coordinates);
108
- target.setzIndex(polyline.coordinates[2]);
109
- target.show();
110
- status = 2;
111
- } else {
112
- target.hide();
113
- status = 0;
114
- }
115
- break;
116
-
117
- case "lineWidth":
118
- target.setOptions({
119
- strokeWeight: polyline.lineWidth,
120
- });
121
- break;
122
- case "stroke":
123
- target.setOptions({
124
- strokeColor: polyline.stroke,
125
- });
126
- break;
127
- case "dash":
128
- target.setOptions({
129
- strokeStyle: polyline.dash ? "dashed" : "solid",
130
- });
131
- break;
132
- default:
133
- throw new Error(`${key} 还不支持修改`);
134
- }
135
- });
136
- };
137
- const onDbClick = () => {
138
- switch (status) {
139
- case 1:
140
- status = 2;
141
- skip++;
142
- polyline.coordinates = target.getPath().map((item) => [item.lng, item.lat]);
143
- polyline.event.trigger("data-loaded");
144
- polyline.event.trigger("pointer-in");
145
- break;
146
- case 3:
147
- polyline.event.trigger("stop-edit");
148
- aMapPolylineEditor.setTarget();
149
- aMapPolylineEditor.close();
150
- break;
151
- }
152
- };
153
- const onStartEdit = () => {
154
- switch (status) {
155
- case 2:
156
- status = 3;
157
- break;
158
- }
159
- };
160
-
161
- const onStopEdit = () => {
162
- if (status == 3) {
163
- status = 2;
164
- skip++;
165
- polyline.coordinates = target.getPath().map((item) => [item.lng, item.lat]);
166
- }
167
- };
168
-
169
- const onDestroy = () => {
170
- viewer.remove(target);
171
- aMapPolylineEditor.close();
172
- aMapPolylineEditor.setTarget();
173
- event.off("double-click", onDbClick);
174
- polyline.event.off("update", onUpdate);
175
- polyline.event.off("start-edit", onStartEdit);
176
- polyline.event.off("stop-edit", onStopEdit);
177
- polyline.event.off("destroy", onDestroy);
178
- };
179
-
180
- event.on("double-click", onDbClick);
181
- polyline.event.on("update", onUpdate);
182
- polyline.event.on("start-edit", onStartEdit);
183
- polyline.event.on("stop-edit", onStopEdit);
184
- polyline.event.on("destroy", onDestroy);
185
- }
1
+ import { AMap } from "./AMap";
2
+ import { Polyline } from "../basic/Polyline";
3
+
4
+ import { parseHexColor } from "../utils/color";
5
+
6
+ export function drawPolyline(map: AMap, polyline: Polyline<unknown>) {
7
+ const { event, viewer, LbsAMap } = map;
8
+ const { color: strokeColor, opacity: strokeOpacity } = parseHexColor(polyline.stroke);
9
+
10
+ let status = 0;
11
+ let skip = 0;
12
+ let target = null;
13
+ let aMapPolylineEditor = null;
14
+
15
+ const _event = {
16
+ cursor: polyline.cursor,
17
+ silent: polyline.silent,
18
+ onPointerIn() {
19
+ status == 2 && polyline.event.trigger("pointer-in");
20
+ },
21
+ onPointerOut() {
22
+ status == 2 && polyline.event.trigger("pointer-out");
23
+ },
24
+ onLClick() {
25
+ status == 2 && polyline.event.trigger("left-click");
26
+ },
27
+ onRClick(e) {
28
+ event.canvas = [e.pixel.x, e.pixel.y];
29
+ if (polyline.menu) {
30
+ map.menu.show(polyline.menu);
31
+ }
32
+ status == 2 && polyline.event.trigger("right-click");
33
+ },
34
+ onDbClick() {
35
+ polyline.editable &&
36
+ status == 2 &&
37
+ setTimeout(() => {
38
+ aMapPolylineEditor.setTarget(target);
39
+ aMapPolylineEditor.open();
40
+ polyline.event.trigger("start-edit");
41
+ });
42
+ },
43
+ };
44
+
45
+ const bindEvent = (graphical) => {
46
+ graphical.on("click", _event.onLClick);
47
+ graphical.on("rightclick", _event.onRClick);
48
+ graphical.on("dblclick", _event.onDbClick);
49
+ graphical.on("mouseover", _event.onPointerIn);
50
+ graphical.on("mouseout", _event.onPointerOut);
51
+ };
52
+
53
+ aMapPolylineEditor = new LbsAMap.PolylineEditor(viewer, undefined, {
54
+ createOptions: {
55
+ strokeColor: strokeColor,
56
+ strokeOpacity: strokeOpacity,
57
+ strokeWeight: polyline.lineWidth,
58
+ strokeStyle: polyline.dash ? "dashed" : "solid",
59
+ strokeDasharray: [10, 10],
60
+ },
61
+ editOptions: {
62
+ strokeColor: strokeColor,
63
+ strokeOpacity: strokeOpacity,
64
+ strokeWeight: polyline.lineWidth,
65
+ strokeStyle: polyline.dash ? "dashed" : "solid",
66
+ strokeDasharray: [10, 10],
67
+ },
68
+ });
69
+
70
+ aMapPolylineEditor.on("add", (e) => {
71
+ status = 3;
72
+ target = e.target;
73
+ bindEvent(target);
74
+ // polygon.event.trigger("data-loaded");
75
+ });
76
+
77
+ if (polyline.coordinates) {
78
+ status = 2;
79
+ target = new LbsAMap.Polyline({
80
+ path: polyline.coordinates,
81
+ strokeColor: strokeColor,
82
+ strokeOpacity: strokeOpacity,
83
+ strokeWeight: polyline.lineWidth,
84
+ strokeStyle: polyline.dash ? "dashed" : "solid",
85
+ strokeDasharray: [10, 10],
86
+ zIndex: polyline.coordinates[0]?.[2] ?? polyline.height,
87
+ bubble: true,
88
+ extData: {
89
+ userdata: polyline.userdata,
90
+ cursor: polyline.cursor,
91
+ silent: polyline.silent,
92
+ target: polyline,
93
+ },
94
+ });
95
+ viewer.add(target);
96
+ bindEvent(target);
97
+ } else {
98
+ aMapPolylineEditor.close();
99
+ aMapPolylineEditor.setTarget();
100
+ aMapPolylineEditor.open();
101
+ }
102
+ const onUpdate = (e: Set<string>) => {
103
+ if (skip) {
104
+ skip--;
105
+ return;
106
+ }
107
+
108
+ e.forEach((key) => {
109
+ switch (key) {
110
+ case "show":
111
+ if (polyline.show) {
112
+ target.show();
113
+ } else {
114
+ target.hide();
115
+ }
116
+ break;
117
+ case "editable":
118
+ break;
119
+ case "coordinates":
120
+ if (polyline.coordinates) {
121
+ target.setPath(polyline.coordinates);
122
+ target.setzIndex(polyline.coordinates[0]?.[2] ?? polyline.height);
123
+ target.show();
124
+ status = 2;
125
+ } else {
126
+ target.hide();
127
+ status = 0;
128
+ }
129
+ break;
130
+
131
+ case "lineWidth":
132
+ target.setOptions({
133
+ strokeWeight: polyline.lineWidth,
134
+ });
135
+ break;
136
+ case "stroke":
137
+ target.setOptions({
138
+ strokeColor: polyline.stroke,
139
+ });
140
+ break;
141
+ case "dash":
142
+ target.setOptions({
143
+ strokeStyle: polyline.dash ? "dashed" : "solid",
144
+ });
145
+ break;
146
+ default:
147
+ throw new Error(`${key} 还不支持修改`);
148
+ }
149
+ });
150
+ };
151
+ const onDbClick = () => {
152
+ switch (status) {
153
+ case 1:
154
+ status = 2;
155
+ skip++;
156
+ polyline.coordinates = target.getPath().map((item) => [item.lng, item.lat]);
157
+ polyline.event.trigger("data-loaded");
158
+ polyline.event.trigger("pointer-in");
159
+ break;
160
+ case 3:
161
+ polyline.event.trigger("stop-edit");
162
+ aMapPolylineEditor.setTarget();
163
+ aMapPolylineEditor.close();
164
+ break;
165
+ }
166
+ };
167
+ const onStartEdit = () => {
168
+ switch (status) {
169
+ case 2:
170
+ status = 3;
171
+ break;
172
+ }
173
+ };
174
+
175
+ const onStopEdit = () => {
176
+ if (status == 3) {
177
+ status = 2;
178
+ skip++;
179
+ polyline.coordinates = target.getPath().map((item) => [item.lng, item.lat]);
180
+ }
181
+ };
182
+
183
+ const onDestroy = () => {
184
+ viewer.remove(target);
185
+ aMapPolylineEditor.close();
186
+ aMapPolylineEditor.setTarget();
187
+ event.off("double-click", onDbClick);
188
+ polyline.event.off("update", onUpdate);
189
+ polyline.event.off("start-edit", onStartEdit);
190
+ polyline.event.off("stop-edit", onStopEdit);
191
+ polyline.event.off("destroy", onDestroy);
192
+ };
193
+
194
+ event.on("double-click", onDbClick);
195
+ polyline.event.on("update", onUpdate);
196
+ polyline.event.on("start-edit", onStartEdit);
197
+ polyline.event.on("stop-edit", onStopEdit);
198
+ polyline.event.on("destroy", onDestroy);
199
+ }
@@ -36,11 +36,11 @@ export abstract class BasicBusiness<T extends BasicBusinessOption> {
36
36
  constructor(map: MapCombine, option: T) {
37
37
  this._map = map;
38
38
  this._option = option;
39
- // const oldElement = map.bussinesses.get(this.name);
40
- // if (oldElement) {
41
- // oldElement.destroy();
42
- // }
43
- // map.bussinesses.set(this.name, this);
39
+ const oldElement = map.bussinesses.get(this.name);
40
+ if (oldElement) {
41
+ oldElement.destroy();
42
+ }
43
+ map.bussinesses.set(this.name, this);
44
44
  }
45
45
 
46
46
  /** 地图展示时触发一次 */
@@ -0,0 +1,49 @@
1
+ import { BasicElement, type BasicElementOption } from "./BasicElement";
2
+
3
+ export interface BasicModelOption extends BasicElementOption {
4
+ name?: string;
5
+ /** 经度 */
6
+ lon: number;
7
+ /** 纬度 */
8
+ lat: number;
9
+ /** 海拔 */
10
+ alt: number;
11
+ /** 模型地址 */
12
+ model: string;
13
+ /** 缩放 */
14
+ scale: number;
15
+ /** 朝向 */
16
+ heading: number;
17
+ /** 俯角 */
18
+ pitch: number;
19
+ /** 倾角 */
20
+ roll: number;
21
+ /** 最小尺寸 */
22
+ minSize: number;
23
+ }
24
+
25
+ export abstract class BasicModel extends BasicElement<BasicModelOption> {
26
+ constructor(option: Partial<BasicModelOption> = {}) {
27
+ super(
28
+ Object.assign(
29
+ {
30
+ show: true,
31
+ cursor: "pointer",
32
+ silent: false,
33
+ lon: 120,
34
+ lat: 30,
35
+ alt: 0,
36
+ scale: 1,
37
+ model: BasicModel.defualtModel,
38
+ heading: 0,
39
+ pitch: 0,
40
+ roll: 0,
41
+ minSize: 16,
42
+ },
43
+ option,
44
+ ),
45
+ );
46
+ }
47
+
48
+ static defualtModel = "./public/xiaoche.glb";
49
+ }
@@ -7,6 +7,7 @@ import { Polygon, PolygonOption } from "./Polygon";
7
7
  import { Polyline, PolylineOption } from "./Polyline";
8
8
  import { ReactPoint, ReactPointOption, drawReactPoint } from "./ReactPoint";
9
9
  import { Tile3D, Tile3DOption } from "./Tile3D";
10
+ import { BasicModel, BasicModelOption } from "./BasicModel";
10
11
  import { type BasicBusiness, type BasicBusinessOption } from "./BasicBusiness";
11
12
 
12
13
  import { getBounds } from "../utils/points-viewer";
@@ -72,6 +73,9 @@ export abstract class MapCombine {
72
73
 
73
74
  abstract createTile3D(option?: Partial<Tile3DOption>): Tile3D;
74
75
 
76
+ /** 创建模型 */
77
+ createModel?(option?: Partial<BasicModelOption>): BasicModel;
78
+
75
79
  abstract canvasTgeography(p: number[]): number[];
76
80
 
77
81
  abstract geographyTcanvas(p: number[]): number[];
@@ -16,7 +16,8 @@ export abstract class MapElement<T extends MapElementOption = MapElementOption>
16
16
  this.map = map;
17
17
  this._option = option;
18
18
  if (map.elements.has(option.name)) {
19
- throw new Error(`已存在同名元素 ${option.name}`);
19
+ console.error(new Error(`已存在同名元素 ${option.name}`));
20
+ return;
20
21
  }
21
22
  map.elements.set(option.name, this);
22
23
  }
@@ -5,6 +5,11 @@ export class MapEvent extends Eventful<{
5
5
  "pointer-move": () => void;
6
6
  "pointer-up": () => void;
7
7
  "left-click": () => void;
8
+ /**
9
+ * 获取当前点击位置的所有元素
10
+ * @returns
11
+ */
12
+ "drill-pick": (elements) => void;
8
13
  "right-click": () => void;
9
14
  "double-click": () => void;
10
15
  "view-change": () => void;
@@ -10,6 +10,7 @@ export interface PointOption<K> extends MapElementOption {
10
10
  src: string;
11
11
  center: number[];
12
12
  size: number[];
13
+ /** 角度制 */
13
14
  rotation: number;
14
15
  editable: boolean;
15
16
  userdata: K;
@@ -1,24 +1,27 @@
1
1
  import { ReactElement } from "react";
2
- import { throttle } from "lodash";
3
2
 
4
3
  import { LATTOONE, LONTOONE } from "../utils/static";
5
4
  import { getUUID, setValue } from "../utils";
6
5
  import { MapCombine } from "../basic/MapCombine";
7
6
  import { ReactPoint } from "./ReactPoint";
8
7
 
8
+ export interface PointOption {
9
+ coordinates: number[];
10
+ props?: any;
11
+ }
9
12
  export interface PointAggregationOption {
10
13
  /** 组件名,唯一标识 */
11
14
  name: string;
12
15
  /** 组件是否显示 */
13
16
  show: boolean;
14
17
  /** 数据点 */
15
- datas: any[];
18
+ datas: PointOption[];
16
19
  /** 小于该值的等级下会聚合 */
17
20
  maxZoomLevel?: number;
18
21
  /** 值越大聚合点的间距越小 */
19
22
  density?: number;
20
23
  /** 点的展示元素 */
21
- element(datas: any[], p: number[]): ReactElement;
24
+ element(datas: PointOption[], p: number[]): ReactElement;
22
25
  /** 坐标处理回调 */
23
26
  location(lonlat: number[]): number[];
24
27
  }
@@ -28,10 +31,12 @@ class TileNode {
28
31
  private _element: any;
29
32
  marker: ReactPoint | undefined;
30
33
  private _map: MapCombine;
31
- constructor(map: MapCombine, location: number[], element: ReactElement) {
34
+ option;
35
+ constructor(map: MapCombine, location: number[], element: ReactElement, option = {}) {
32
36
  this._map = map;
33
37
  this._location = location;
34
38
  this._element = element;
39
+ this.option = option;
35
40
  }
36
41
  test(east: number, south: number, west: number, north: number) {
37
42
  if (
@@ -42,6 +47,7 @@ class TileNode {
42
47
  ) {
43
48
  if (!this.marker) {
44
49
  const option = {
50
+ ...this.option,
45
51
  show: true,
46
52
  name: getUUID(),
47
53
  element: () => this._element,
@@ -94,6 +100,8 @@ export class PointAggregation {
94
100
  this._onAfterViewChange = this.onAfterViewChange.bind(this);
95
101
  this.onAfterViewChange();
96
102
  event.on("view-moveEnd", this._onAfterViewChange);
103
+ // 初始化没有渲染,移动之后才渲染点位
104
+ this._update();
97
105
  }
98
106
 
99
107
  private _turnon(zoom: number) {
@@ -106,10 +114,12 @@ export class PointAggregation {
106
114
  const grid = new Map();
107
115
  const max = Math.pow(2, zoom) * (_option.density ?? 1);
108
116
  _option.datas.forEach((data) => {
109
- const location = typeof _option.location === "function" ? _option.location(data) : data;
117
+ const location =
118
+ typeof _option.location === "function" ? _option.location(data.coordinates) : data.coordinates;
110
119
  const x = Math.floor(LONTOONE.forward(location[0]) * max * 2);
111
120
  const y = Math.floor(LATTOONE.forward(location[1]) * max);
112
121
  const k = `${x}_${y}`;
122
+ // 对数据进行分组
113
123
  const group = grid.get(k);
114
124
  if (group) {
115
125
  group.push(data);
@@ -118,10 +128,11 @@ export class PointAggregation {
118
128
  }
119
129
  });
120
130
  // 处理聚合点坐标
121
- grid.forEach((e) => {
122
- const { lon, lat } = e.reduce(
131
+ grid.forEach((group) => {
132
+ const { lon, lat } = group?.reduce(
123
133
  (a, b) => {
124
- const loaction = typeof _option.location === "function" ? _option.location(b) : b;
134
+ const { coordinates } = b;
135
+ const loaction = typeof _option.location === "function" ? _option.location(coordinates) : coordinates;
125
136
  a.lon += loaction[0];
126
137
  a.lat += loaction[1];
127
138
  return a;
@@ -131,8 +142,8 @@ export class PointAggregation {
131
142
  cache.push(
132
143
  new TileNode(
133
144
  this._map,
134
- [lon / e.length, lat / e.length],
135
- _option.element(e, [lon / e.length, lat / e.length]),
145
+ [lon / group.length, lat / group.length],
146
+ _option.element(group, [lon / group.length, lat / group.length]),
136
147
  ),
137
148
  );
138
149
  });
@@ -140,7 +151,7 @@ export class PointAggregation {
140
151
  } else {
141
152
  const cache: TileNode[] = [];
142
153
  _option.datas.forEach((e) => {
143
- const location = _option.location(e);
154
+ const location = _option.location(e.coordinates);
144
155
  cache.push(new TileNode(this._map, location, _option.element([e], location)));
145
156
  });
146
157
  _cache.set(zoom, cache);
@@ -1,3 +1,6 @@
1
+ /**
2
+ * WARM: 后续将废弃该功能,使用 ReactPoint 替换!!!
3
+ */
1
4
  import { ReactElement } from "react";
2
5
  import ReactDOM from "react-dom";
3
6
  import { MapCombine } from "./MapCombine";