@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.
@@ -28,10 +28,16 @@ export function drawPoint(map: MineMap, point: Point<unknown>) {
28
28
  };
29
29
 
30
30
  const marker = new minemap.Marker({
31
+ id: point.name,
31
32
  draggable: point.editable,
32
33
  rotation: 0,
33
34
  offset: [-size[0] * center[0], -size[1] * center[1]],
34
35
  element: img,
36
+ extData: {
37
+ name: point.name,
38
+ target: point,
39
+ userdata: point.userdata,
40
+ },
35
41
  });
36
42
 
37
43
  if (point.coordinates) {
@@ -69,7 +75,7 @@ export function drawPoint(map: MineMap, point: Point<unknown>) {
69
75
  break;
70
76
  case "coordinates":
71
77
  if (point.coordinates) {
72
- marker.setLngLat(point.coordinates).setAltitude(point.coordinates[2] ?? 0);
78
+ marker.setLngLat(point.coordinates).setAltitude(point.coordinates[2] ?? point.height);
73
79
  switch (status) {
74
80
  case 0:
75
81
  point.show && marker.addTo(map.viewer);
@@ -50,6 +50,7 @@ function getPolygonOption(polygon: Polygon<unknown>) {
50
50
  "fill-color": color,
51
51
  "fill-opacity": opacity,
52
52
  },
53
+ zIndex: polygon.coordinates[0]?.[2] ?? polygon.height,
53
54
  };
54
55
  }
55
56
 
@@ -148,11 +149,15 @@ function main(map: MineMap, polygon: Polygon<unknown>) {
148
149
  type: "Feature",
149
150
  geometry: {
150
151
  type: "Polygon",
151
- coordinates: [[...coordinates, coordinates[0]]],
152
+ coordinates: [[...coordinates, coordinates[0]].map((it) => [it[0], it[1], it[2] ?? polygon.height])],
152
153
  },
153
154
  properties: {
154
155
  id: polygon.name,
155
156
  },
157
+ extData: {
158
+ name: polygon.name,
159
+ userdata: polygon.userdata,
160
+ },
156
161
  };
157
162
  } else {
158
163
  data.features = [];
@@ -56,6 +56,7 @@ function getLayerOption(polyline: Polyline<unknown>) {
56
56
  "line-color": polyline.stroke,
57
57
  "line-width": polyline.lineWidth,
58
58
  },
59
+ zIndex: polyline.coordinates[0]?.[2] ?? polyline.height,
59
60
  };
60
61
  }
61
62
 
@@ -130,10 +131,14 @@ function main(map: MineMap, polyline: Polyline<unknown>) {
130
131
  type: "Feature",
131
132
  geometry: {
132
133
  type: "LineString",
133
- coordinates: coordinates,
134
+ coordinates: coordinates?.map((it) => [it[0], it[1], it[2] ?? polyline.height]),
134
135
  },
135
136
  properties: {
136
137
  id: polyline.name,
138
+ extData: {
139
+ name: polyline.name,
140
+ userdata: polyline.userdata,
141
+ },
137
142
  },
138
143
  };
139
144
  } else {
@@ -1,87 +1,109 @@
1
- import { OpenlayerMap } from "./OpenlayerMap";
2
-
3
- export function bindEvent(map: OpenlayerMap) {
4
- const { event, viewer, container } = map;
5
- let target: any;
6
- let moving = false;
7
-
8
- const frame = () => {
9
- if (map.isAlive) {
10
- requestAnimationFrame(frame);
11
- event.trigger("view-preRender");
12
- }
13
- };
14
- frame();
15
-
16
- viewer.on("moveend", (e) => {
17
- event.trigger("view-moveEnd");
18
- });
19
-
20
- viewer.on("pointermove", (e) => {
21
- event.canvas = e.pixel;
22
- event.geography = map.canvasTgeography(event.canvas);
23
- let _target: any;
24
- if (moving) {
25
- event.trigger("pointer-move");
26
- return;
27
- }
28
- const res = viewer.getFeaturesAtPixel(event.canvas)[0];
29
- _target = res ? res.get("event") : undefined;
30
- if (_target?.silent) {
31
- _target = undefined;
32
- }
33
- if (_target !== target) {
34
- target?.onPointerOut?.();
35
- _target?.onPointerIn?.();
36
- target = _target;
37
- }
38
- event.trigger("pointer-move");
39
- });
40
-
41
- container.addEventListener("mousedown", () => {
42
- if (target) {
43
- moving = true;
44
- target.onPointerDown?.();
45
- }
46
- event.trigger("pointer-down");
47
- });
48
-
49
- container.addEventListener("mouseup", () => {
50
- if (target) {
51
- moving = false;
52
- target.onPointerUp?.();
53
- }
54
- event.trigger("pointer-up");
55
- });
56
-
57
- container.addEventListener("contextmenu", (e) => {
58
- e.preventDefault();
59
- if (target) {
60
- target.onRClick?.();
61
- }
62
- });
63
-
64
- viewer.on("click", () => {
65
- if (target) {
66
- target.onLClick?.();
67
- }
68
- event.trigger("left-click");
69
- });
70
-
71
- viewer.on("dblclick", () => {
72
- if (target) {
73
- target.onDbClick?.();
74
- }
75
- map.event.trigger("double-click");
76
- });
77
-
78
- let key = 0;
79
-
80
- viewer.on("precompose", () => {
81
- const _key = map.center.reduce((a, b) => a + b, map.zoom);
82
- if (key != _key) {
83
- key = _key;
84
- event.trigger("view-change");
85
- }
86
- });
87
- }
1
+ import { OpenlayerMap } from "./OpenlayerMap";
2
+
3
+ export function bindEvent(map: OpenlayerMap) {
4
+ const { event, viewer, container } = map;
5
+ let target: any;
6
+ let moving = false;
7
+
8
+ const frame = () => {
9
+ if (map.isAlive) {
10
+ requestAnimationFrame(frame);
11
+ event.trigger("view-preRender");
12
+ map.bussinesses.forEach((e) => e.show && e.onFrame?.());
13
+ }
14
+ };
15
+ frame();
16
+
17
+ viewer.on("moveend", (e) => {
18
+ event.trigger("view-moveEnd");
19
+ });
20
+
21
+ viewer.on("pointermove", (e) => {
22
+ event.canvas = e.pixel;
23
+ event.geography = map.canvasTgeography(event.canvas);
24
+ let _target: any;
25
+ if (moving) {
26
+ event.trigger("pointer-move");
27
+ return;
28
+ }
29
+ const res = viewer.getFeaturesAtPixel(event.canvas)[0];
30
+ _target = res ? res.get("event") : undefined;
31
+ if (_target?.silent) {
32
+ _target = undefined;
33
+ }
34
+ if (_target !== target) {
35
+ target?.onPointerOut?.();
36
+ _target?.onPointerIn?.();
37
+ target = _target;
38
+ }
39
+ event.trigger("pointer-move");
40
+ });
41
+
42
+ container.addEventListener("mousedown", () => {
43
+ if (target) {
44
+ moving = true;
45
+ target.onPointerDown?.();
46
+ }
47
+ event.trigger("pointer-down");
48
+ });
49
+
50
+ container.addEventListener("mouseup", () => {
51
+ if (target) {
52
+ moving = false;
53
+ target.onPointerUp?.();
54
+ }
55
+ event.trigger("pointer-up");
56
+ });
57
+
58
+ container.addEventListener("contextmenu", (e) => {
59
+ e.preventDefault();
60
+ if (target) {
61
+ target.onRClick?.();
62
+ }
63
+ });
64
+
65
+ viewer.on("click", () => {
66
+ if (target) {
67
+ target.onLClick?.();
68
+ }
69
+ event.trigger("left-click");
70
+ });
71
+
72
+ // 监听地图的单击事件
73
+ viewer.on("singleclick", function (e) {
74
+ // 使用 forEachFeatureAtPixel 查询该像素位置下的所有要素
75
+ const pickedObjects = [];
76
+ viewer.forEachFeatureAtPixel(e.pixel, function (feature, layer) {
77
+ // 这个回调函数会为每一个被点击到的要素执行
78
+ pickedObjects.push(feature);
79
+ // 返回 true 可以提前终止遍历
80
+ // return true;
81
+ });
82
+
83
+ if (pickedObjects.length > 0) {
84
+ event.trigger("drill-pick", {
85
+ event: e,
86
+ pickedTargets: pickedObjects.map((it) => it?.values_?.userData?.target),
87
+ sourceObjects: pickedObjects,
88
+ position: map.canvasTgeography(e.pixel),
89
+ });
90
+ }
91
+ });
92
+
93
+ viewer.on("dblclick", () => {
94
+ if (target) {
95
+ target.onDbClick?.();
96
+ }
97
+ map.event.trigger("double-click");
98
+ });
99
+
100
+ let key = 0;
101
+
102
+ viewer.on("precompose", () => {
103
+ const _key = map.center.reduce((a, b) => a + b, map.zoom);
104
+ if (key != _key) {
105
+ key = _key;
106
+ event.trigger("view-change");
107
+ }
108
+ });
109
+ }
@@ -26,7 +26,12 @@ export function drawPoint(map: OpenlayerMap, point: Point<unknown>) {
26
26
  visible: point.show,
27
27
  });
28
28
  viewer.addLayer(layer);
29
- const feature = new Feature();
29
+ const feature = new Feature({
30
+ userData: {
31
+ name: point.name,
32
+ target: point,
33
+ },
34
+ });
30
35
  const geometry = new OlPoint([0, 0]);
31
36
  const style = new Style({
32
37
  image: new Icon({
@@ -26,7 +26,12 @@ export function drawPolygon(map: OpenlayerMap, polygon: Polygon<unknown>) {
26
26
  let status = 0;
27
27
  let skip = 0;
28
28
 
29
- const feature = new Feature();
29
+ const feature = new Feature({
30
+ userData: {
31
+ name: polygon.name,
32
+ target: polygon,
33
+ },
34
+ });
30
35
  const geometry = new OlPolygon([
31
36
  [
32
37
  [0, 0],
@@ -25,7 +25,12 @@ export function drawPolyline(map: OpenlayerMap, polyline: Polyline<unknown>) {
25
25
  let status = 0;
26
26
  let skip = 0;
27
27
 
28
- const feature = new Feature();
28
+ const feature = new Feature({
29
+ userData: {
30
+ name: polyline.name,
31
+ target: polyline,
32
+ },
33
+ });
29
34
  const geometry = new LineString([
30
35
  [0, 0],
31
36
  [0, 0],
@@ -64,6 +69,8 @@ export function drawPolyline(map: OpenlayerMap, polyline: Polyline<unknown>) {
64
69
  });
65
70
 
66
71
  const _event = {
72
+ name: polyline.name,
73
+ target: polyline,
67
74
  cursor: polyline.cursor,
68
75
  silent: polyline.silent,
69
76
  onPointerIn() {
@@ -0,0 +1,49 @@
1
+ /**
2
+ * 解析十六进制颜色字符串,拆分为颜色值和透明度
3
+ * @param {string} hexColor - 十六进制颜色字符串,支持格式:#RGB, #RRGGBB, #RRGGBBAA, #RGBA
4
+ * @param {number} defaultOpacity - 默认透明度(0-1),当颜色没有透明度时使用
5
+ * @returns {Object} { color: string, opacity: number }
6
+ * @throws {Error} 如果颜色格式无效
7
+ */
8
+ export function parseHexColor(hexColor, defaultOpacity = 1) {
9
+ // 移除开头的 # 号(如果有)
10
+ let hex = hexColor.replace(/^#/, "");
11
+
12
+ // 验证是否为有效的十六进制字符串
13
+ if (!/^[0-9a-fA-F]+$/.test(hex)) {
14
+ throw new Error(`无效的颜色格式: "${hexColor}"`);
15
+ }
16
+
17
+ let color = "";
18
+ let opacity = defaultOpacity;
19
+
20
+ switch (hex.length) {
21
+ case 3: // #RGB
22
+ color = `#${hex[0]}${hex[0]}${hex[1]}${hex[1]}${hex[2]}${hex[2]}`;
23
+ opacity = defaultOpacity;
24
+ break;
25
+
26
+ case 4: // #RGBA
27
+ color = `#${hex[0]}${hex[0]}${hex[1]}${hex[1]}${hex[2]}${hex[2]}`;
28
+ opacity = parseInt(hex[3] + hex[3], 16) / 255;
29
+ break;
30
+
31
+ case 6: // #RRGGBB
32
+ color = `#${hex}`;
33
+ opacity = defaultOpacity;
34
+ break;
35
+
36
+ case 8: // #RRGGBBAA
37
+ color = `#${hex.slice(0, 6)}`;
38
+ opacity = parseInt(hex.slice(6, 8), 16) / 255;
39
+ break;
40
+
41
+ default:
42
+ throw new Error(`不支持的十六进制颜色长度: "${hexColor}",长度必须为 3、4、6 或 8`);
43
+ }
44
+
45
+ // 确保透明度在 0-1 范围内
46
+ opacity = Math.max(0, Math.min(1, opacity));
47
+
48
+ return { color, opacity };
49
+ }
@@ -12,6 +12,9 @@ export function setValue<T>(obj: any, key: string, val: T, onChange: () => void)
12
12
  }
13
13
  }
14
14
 
15
+ /**
16
+ * 建立两个一维区间之间的线性映射关系,提供正向变换和逆向变换
17
+ */
15
18
  export class OneDimensional {
16
19
  k: number;
17
20
  b: number;
@@ -43,5 +43,31 @@ export const getBounds = function (points, opt) {
43
43
  minLat -= avoid[1] * latPixelRatio;
44
44
  maxLat += avoid[0] * latPixelRatio;
45
45
 
46
- return [minLon, minLat, maxLon, maxLat];
46
+ // 根据 maxZoom 计算最小矩形范围
47
+ const minRange = getMinRangeFromZoom(opt.maxZoom);
48
+ const centerLon = (minLon + maxLon) / 2;
49
+ const centerLat = (minLat + maxLat) / 2;
50
+
51
+ // 确保矩形范围不小于最小值 解决点位距离过近导致异常缩放问题
52
+ let finalWest = Math.min(minLon, centerLon - minRange / 2);
53
+ let finalEast = Math.max(maxLon, centerLon + minRange / 2);
54
+ let finalSouth = Math.min(minLat, centerLat - minRange / 2);
55
+ let finalNorth = Math.max(maxLat, centerLat + minRange / 2);
56
+
57
+ return [finalWest, finalSouth, finalEast, finalNorth];
47
58
  };
59
+
60
+ /**
61
+ * 根据 maxZoom 计算出一个“最小”的经纬度跨度
62
+ * @param zoom
63
+ * @returns
64
+ */
65
+ export function getMinRangeFromZoom(zoom) {
66
+ // 每个瓦片覆盖的经度范围
67
+ const lonPerTile = 360 / Math.pow(2, zoom);
68
+ // 每个瓦片覆盖的纬度范围(近似)
69
+ const latPerTile = 180 / Math.pow(2, zoom);
70
+
71
+ // 返回一个足够小的范围,比如一个瓦片范围的一半
72
+ return Math.max(lonPerTile, latPerTile) / 2;
73
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * 通用函数:提取所有坐标并扁平化为普通数组
3
+ * @param geojsonFeature
4
+ * @param geomType
5
+ * @returns
6
+ */
7
+ export function extractCoordinatesToArr(coords, geomType) {
8
+ if (geomType === "Polygon") {
9
+ // 多边形:三维数组 [环1[点1,点2...], 环2[...]] -> 转为二维数组
10
+ return coords.map(
11
+ (ring) => ring.map((coord) => [coord[0], coord[1]]), // 提取经度、纬度
12
+ );
13
+ } else if (geomType === "MultiPolygon") {
14
+ // 多部件多边形:四维数组 -> 转为三维数组
15
+ return coords.map((polygon) => polygon.map((ring) => ring.map((coord) => [coord[0], coord[1]])));
16
+ } else if (geomType === "Point") {
17
+ // 点:返回一维数组
18
+ return [coords[0], coords[1]];
19
+ } else if (geomType === "LineString") {
20
+ // 线:返回二维数组
21
+ return coords.map((coord) => [coord[0], coord[1]]);
22
+ }
23
+
24
+ return coords;
25
+ }
26
+
27
+ /**
28
+ * 通用函数:提取所有坐标并扁平化为普通数组
29
+ * @param geojsonFeature
30
+ * @returns
31
+ */
32
+ export function extractGeojsonCoordinatesToArr(geojsonFeature) {
33
+ const coords = geojsonFeature.geometry.coordinates;
34
+ const geomType = geojsonFeature.geometry.type;
35
+ if (geomType === "Polygon") {
36
+ // 多边形:三维数组 [环1[点1,点2...], 环2[...]] -> 转为二维数组
37
+ return coords.map(
38
+ (ring) => ring.map((coord) => [coord[0], coord[1]]), // 提取经度、纬度
39
+ );
40
+ } else if (geomType === "MultiPolygon") {
41
+ // 多部件多边形:四维数组 -> 转为三维数组
42
+ return coords.map((polygon) => polygon.map((ring) => ring.map((coord) => [coord[0], coord[1]])));
43
+ } else if (geomType === "Point") {
44
+ // 点:返回一维数组
45
+ return [coords[0], coords[1]];
46
+ } else if (geomType === "LineString") {
47
+ // 线:返回二维数组
48
+ return coords.map((coord) => [coord[0], coord[1]]);
49
+ }
50
+
51
+ return coords;
52
+ }
@@ -0,0 +1,12 @@
1
+ export enum HtmlPosition {
2
+ "auto",
3
+ "bottomright",
4
+ "bottom",
5
+ "bottomleft",
6
+ "right",
7
+ "top",
8
+ "left",
9
+ "topright",
10
+ "topleft" = 9,
11
+ "center",
12
+ }