@antv/l7-layers 2.23.2 → 2.23.3-beta.1

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 (73) hide show
  1. package/es/{citybuliding → citybuilding}/models/build.js +4 -2
  2. package/es/core/BaseLayer.js +3 -3
  3. package/es/core/LayerPickService.js +3 -1
  4. package/es/core/shape/Path.d.ts +2 -1
  5. package/es/core/shape/Path.js +10 -4
  6. package/es/core/triangulation.js +51 -1
  7. package/es/earth/index.js +2 -3
  8. package/es/geometry/index.js +2 -3
  9. package/es/heatmap/index.js +6 -6
  10. package/es/heatmap/models/heatmap.js +2 -3
  11. package/es/index.d.ts +1 -1
  12. package/es/index.js +1 -1
  13. package/es/line/index.js +2 -3
  14. package/es/plugins/DataMappingPlugin.js +30 -10
  15. package/es/plugins/FeatureScalePlugin.js +21 -20
  16. package/es/plugins/ShaderUniformPlugin.js +62 -29
  17. package/es/plugins/index.d.ts +1 -1
  18. package/es/polygon/index.js +2 -3
  19. package/es/polygon/models/extrude.js +22 -7
  20. package/es/polygon/models/ocean.js +17 -6
  21. package/es/polygon/models/water.js +17 -6
  22. package/es/tile/core/BaseLayer.d.ts +4 -1
  23. package/es/tile/core/BaseLayer.js +19 -11
  24. package/es/tile/service/TileLayerService.d.ts +26 -1
  25. package/es/tile/service/TileLayerService.js +88 -16
  26. package/es/tile/service/TilePickService.js +15 -9
  27. package/es/tile/tile/Tile.d.ts +1 -1
  28. package/es/tile/tile/index.d.ts +1 -1
  29. package/es/tile/tile/util.d.ts +1 -1
  30. package/es/utils/scale.d.ts +87 -0
  31. package/es/utils/scale.js +588 -0
  32. package/lib/{citybuliding → citybuilding}/models/build.js +4 -2
  33. package/lib/core/BaseLayer.js +3 -3
  34. package/lib/core/LayerPickService.js +3 -1
  35. package/lib/core/shape/Path.d.ts +2 -1
  36. package/lib/core/shape/Path.js +10 -4
  37. package/lib/core/triangulation.js +50 -1
  38. package/lib/earth/index.js +2 -3
  39. package/lib/geometry/index.js +2 -3
  40. package/lib/heatmap/index.js +6 -6
  41. package/lib/heatmap/models/heatmap.js +2 -3
  42. package/lib/index.d.ts +1 -1
  43. package/lib/index.js +1 -1
  44. package/lib/line/index.js +2 -3
  45. package/lib/plugins/DataMappingPlugin.js +30 -10
  46. package/lib/plugins/FeatureScalePlugin.js +22 -23
  47. package/lib/plugins/ShaderUniformPlugin.js +62 -29
  48. package/lib/plugins/index.d.ts +1 -1
  49. package/lib/polygon/index.js +2 -3
  50. package/lib/polygon/models/extrude.js +22 -7
  51. package/lib/polygon/models/ocean.js +17 -6
  52. package/lib/polygon/models/water.js +17 -6
  53. package/lib/tile/core/BaseLayer.d.ts +4 -1
  54. package/lib/tile/core/BaseLayer.js +19 -11
  55. package/lib/tile/service/TileLayerService.d.ts +26 -1
  56. package/lib/tile/service/TileLayerService.js +88 -16
  57. package/lib/tile/service/TilePickService.js +15 -9
  58. package/lib/tile/tile/Tile.d.ts +1 -1
  59. package/lib/tile/tile/index.d.ts +1 -1
  60. package/lib/tile/tile/util.d.ts +1 -1
  61. package/lib/utils/scale.d.ts +87 -0
  62. package/lib/utils/scale.js +603 -0
  63. package/package.json +6 -17
  64. /package/es/{citybuliding → citybuilding}/building.d.ts +0 -0
  65. /package/es/{citybuliding → citybuilding}/building.js +0 -0
  66. /package/es/{citybuliding → citybuilding}/models/build.d.ts +0 -0
  67. /package/es/{citybuliding → citybuilding}/shaders/build_frag.glsl +0 -0
  68. /package/es/{citybuliding → citybuilding}/shaders/build_vert.glsl +0 -0
  69. /package/lib/{citybuliding → citybuilding}/building.d.ts +0 -0
  70. /package/lib/{citybuliding → citybuilding}/building.js +0 -0
  71. /package/lib/{citybuliding → citybuilding}/models/build.d.ts +0 -0
  72. /package/lib/{citybuliding → citybuilding}/shaders/build_frag.glsl +0 -0
  73. /package/lib/{citybuliding → citybuilding}/shaders/build_vert.glsl +0 -0
@@ -55,8 +55,10 @@ export default class CityBuildModel extends BaseModel {
55
55
  return commonBufferInfo;
56
56
  }
57
57
  calCityGeo() {
58
- // @ts-ignore
59
- const [minLng, minLat, maxLng, maxLat] = this.layer.getSource().extent;
58
+ // 当启用 enableRelativeCoordinates 时,使用 originalExtent(原始绝对坐标范围)
59
+ const originalExtent = this.layer.getOriginalExtent();
60
+ const extent = originalExtent[0] !== 0 || originalExtent[2] !== 0 ? originalExtent : this.layer.getSource().extent;
61
+ const [minLng, minLat, maxLng, maxLat] = extent;
60
62
  const w = maxLng - minLng;
61
63
  const h = maxLat - minLat;
62
64
  this.cityCenter = [(maxLng + minLng) / 2, (maxLat + minLat) / 2];
@@ -961,12 +961,12 @@ export default class BaseLayer extends EventEmitter {
961
961
  return this.styleAttributeService.getLayerAttributeScale(name);
962
962
  }
963
963
  getLegend(name) {
964
- var _attribute$scale, _scales$, _attribute$scale2;
964
+ var _attribute$scale, _scales$, _scales$2;
965
965
  const attribute = this.styleAttributeService.getLayerStyleAttribute(name);
966
966
  const scales = (attribute === null || attribute === void 0 || (_attribute$scale = attribute.scale) === null || _attribute$scale === void 0 ? void 0 : _attribute$scale.scalers) || [];
967
967
  return {
968
968
  type: (_scales$ = scales[0]) === null || _scales$ === void 0 || (_scales$ = _scales$.option) === null || _scales$ === void 0 ? void 0 : _scales$.type,
969
- field: attribute === null || attribute === void 0 || (_attribute$scale2 = attribute.scale) === null || _attribute$scale2 === void 0 ? void 0 : _attribute$scale2.field,
969
+ field: (_scales$2 = scales[0]) === null || _scales$2 === void 0 ? void 0 : _scales$2.field,
970
970
  items: this.getLegendItems(name)
971
971
  };
972
972
  }
@@ -1210,7 +1210,7 @@ export default class BaseLayer extends EventEmitter {
1210
1210
  * 继承空方法
1211
1211
  * @param time
1212
1212
  */
1213
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1213
+
1214
1214
  setEarthTime(time) {
1215
1215
  console.warn('empty fn');
1216
1216
  }
@@ -39,7 +39,9 @@ export default class BaseLayerPickService {
39
39
  const container = this.layer.getContainer();
40
40
  const pickingService = container.pickingService;
41
41
  const mapService = container.mapService;
42
- const extent = this.layer.getSource().extent;
42
+ // 当启用 enableRelativeCoordinates 时,使用 originalExtent 判断绝对坐标是否在范围内
43
+ const originalExtent = this.layer.getOriginalExtent();
44
+ const extent = originalExtent[0] !== 0 || originalExtent[2] !== 0 ? originalExtent : this.layer.getSource().extent;
43
45
  const isPick = lngLatInExtent(target.lngLat, extent);
44
46
  const layerTarget = {
45
47
  x: target.x,
@@ -18,8 +18,9 @@ export declare enum ShapeType2D {
18
18
  * 生成规则多边形顶点个数
19
19
  * @param pointCount 顶点个数 3 => 三角形
20
20
  * @param start 顶点起始角度 调整图形的方向
21
+ * @param angleOffset 额外的角度偏移,用于调整六边形方向
21
22
  */
22
- export declare function polygonPath(pointCount: number, start?: number): IPath;
23
+ export declare function polygonPath(pointCount: number, start?: number, angleOffset?: number): IPath;
23
24
  export declare function circle(): IPath;
24
25
  export declare function square(): IPath;
25
26
  export declare function triangle(): IPath;
@@ -19,16 +19,17 @@ export let ShapeType2D = /*#__PURE__*/function (ShapeType2D) {
19
19
  * 生成规则多边形顶点个数
20
20
  * @param pointCount 顶点个数 3 => 三角形
21
21
  * @param start 顶点起始角度 调整图形的方向
22
+ * @param angleOffset 额外的角度偏移,用于调整六边形方向
22
23
  */
23
- export function polygonPath(pointCount, start = 0) {
24
+ export function polygonPath(pointCount, start = 0, angleOffset = Math.PI / 4) {
24
25
  const step = Math.PI * 2 / pointCount;
25
26
  const line = [];
26
27
  for (let i = 0; i < pointCount; i++) {
27
28
  line.push(step * i + start * Math.PI / 12);
28
29
  }
29
30
  const path = line.map(t => {
30
- const x = Math.sin(t + Math.PI / 4);
31
- const y = Math.cos(t + Math.PI / 4);
31
+ const x = Math.sin(t + angleOffset);
32
+ const y = Math.cos(t + angleOffset);
32
33
  return [x, y, 0];
33
34
  });
34
35
  // path.push(path[0]);
@@ -44,7 +45,12 @@ export function triangle() {
44
45
  return polygonPath(3);
45
46
  }
46
47
  export function hexagon() {
47
- return polygonPath(6, 1);
48
+ // 生成 pointy-top 六边形(尖角朝上)
49
+ // 使用 angleOffset = 0 并翻转 y 方向,以匹配 d3-hexbin 的方向
50
+ // d3-hexbin 在屏幕坐标系中 y 向下为正,使用 y = -cos(angle)
51
+ // 我们需要翻转 y 坐标以确保蜂窝网格闭合
52
+ const path = polygonPath(6, 0, 0);
53
+ return path.map(p => [p[0], -p[1], p[2]]);
48
54
  }
49
55
  export function pentagon() {
50
56
  return polygonPath(5);
@@ -7,6 +7,56 @@ import ExtrudePolyline from "../utils/extrude_polyline";
7
7
  import { geometryShape } from "./shape/Path";
8
8
  import extrudePolygon, { extrude_PolygonNormal, fillPolygon } from "./shape/extrude";
9
9
  import { getPolygonSurfaceIndices } from "./utils";
10
+
11
+ /**
12
+ * 质心计算缓存
13
+ * 避免对相同坐标的重复计算
14
+ */
15
+
16
+ const centroidCache = {};
17
+ const CENTROID_CACHE_MAX_SIZE = 500;
18
+
19
+ /**
20
+ * 生成坐标的缓存键
21
+ */
22
+ function getCoordinateKey(coordinates) {
23
+ if (typeof coordinates === 'number') {
24
+ return String(coordinates);
25
+ }
26
+ if (Array.isArray(coordinates)) {
27
+ if (typeof coordinates[0] === 'number') {
28
+ return coordinates.slice(0, 2).join(',');
29
+ }
30
+ // 对于嵌套数组,取第一个点
31
+ return getCoordinateKey(coordinates[0]);
32
+ }
33
+ return '';
34
+ }
35
+
36
+ /**
37
+ * 带缓存的质心计算
38
+ */
39
+ function cachedCalculateCentroid(coordinates) {
40
+ const key = getCoordinateKey(coordinates);
41
+ if (key && centroidCache[key]) {
42
+ return centroidCache[key].slice();
43
+ }
44
+ const centroid = calculateCentroid(coordinates);
45
+
46
+ // 限制缓存大小
47
+ const keys = Object.keys(centroidCache);
48
+ if (keys.length >= CENTROID_CACHE_MAX_SIZE) {
49
+ // 删除一半的缓存
50
+ const deleteCount = Math.floor(CENTROID_CACHE_MAX_SIZE / 2);
51
+ for (let i = 0; i < deleteCount; i++) {
52
+ delete centroidCache[keys[i]];
53
+ }
54
+ }
55
+ if (key) {
56
+ centroidCache[key] = centroid.slice();
57
+ }
58
+ return centroid;
59
+ }
10
60
  const GeometryCache = {};
11
61
 
12
62
  /**
@@ -15,7 +65,7 @@ const GeometryCache = {};
15
65
  */
16
66
 
17
67
  export function PointFillTriangulation(feature) {
18
- const coordinates = calculateCentroid(feature.coordinates);
68
+ const coordinates = cachedCalculateCentroid(feature.coordinates);
19
69
  return {
20
70
  vertices: [...coordinates, ...coordinates, ...coordinates, ...coordinates],
21
71
  indices: [0, 1, 2, 2, 3, 0],
package/es/earth/index.js CHANGED
@@ -44,9 +44,8 @@ export default class EarthLayer extends BaseLayer {
44
44
  }
45
45
  }
46
46
  getModelType() {
47
- var _shapeAttribute$scale;
48
- const shapeAttribute = this.styleAttributeService.getLayerStyleAttribute('shape');
49
- let shape = (shapeAttribute === null || shapeAttribute === void 0 || (_shapeAttribute$scale = shapeAttribute.scale) === null || _shapeAttribute$scale === void 0 ? void 0 : _shapeAttribute$scale.field) || 'base';
47
+ var _this$shapeOption;
48
+ let shape = ((_this$shapeOption = this.shapeOption) === null || _this$shapeOption === void 0 ? void 0 : _this$shapeOption.field) || 'base';
50
49
  if (earthLayerTypes.indexOf(shape) < 0) {
51
50
  shape = 'base';
52
51
  }
@@ -38,9 +38,8 @@ export default class GeometryLayer extends BaseLayer {
38
38
  return defaultConfig[type];
39
39
  }
40
40
  getModelType() {
41
- var _shapeAttribute$scale;
42
- const shapeAttribute = this.styleAttributeService.getLayerStyleAttribute('shape');
43
- const shape = shapeAttribute === null || shapeAttribute === void 0 || (_shapeAttribute$scale = shapeAttribute.scale) === null || _shapeAttribute$scale === void 0 ? void 0 : _shapeAttribute$scale.field;
41
+ var _this$shapeOption;
42
+ const shape = (_this$shapeOption = this.shapeOption) === null || _this$shapeOption === void 0 ? void 0 : _this$shapeOption.field;
44
43
  if (shape === 'plane') {
45
44
  return 'plane';
46
45
  } else if (shape === 'sprite') {
@@ -52,22 +52,22 @@ export default class HeatMapLayer extends BaseLayer {
52
52
  }
53
53
  }
54
54
  getModelType() {
55
- var _shapeAttribute$scale;
56
- const shapeAttribute = this.styleAttributeService.getLayerStyleAttribute('shape');
55
+ var _source$data, _this$shapeOption;
57
56
  const {
58
57
  shape3d
59
58
  } = this.getLayerConfig();
60
59
  const source = this.getSource();
61
- const sourceType = source.data.type;
62
- const shape = (shapeAttribute === null || shapeAttribute === void 0 || (_shapeAttribute$scale = shapeAttribute.scale) === null || _shapeAttribute$scale === void 0 ? void 0 : _shapeAttribute$scale.field) || 'heatmap';
60
+ const sourceType = source === null || source === void 0 || (_source$data = source.data) === null || _source$data === void 0 ? void 0 : _source$data.type;
61
+ const shape = ((_this$shapeOption = this.shapeOption) === null || _this$shapeOption === void 0 ? void 0 : _this$shapeOption.field) || 'heatmap';
62
+ const isShape3D = Array.isArray(shape3d) && shape3d.includes(shape);
63
63
  if (shape === 'heatmap' || shape === 'heatmap3d') {
64
64
  return 'heatmap';
65
65
  }
66
66
  if (sourceType === 'hexagon') {
67
- return (shape3d === null || shape3d === void 0 ? void 0 : shape3d.indexOf(shape)) === -1 ? 'hexagon' : 'grid3d';
67
+ return isShape3D ? 'grid3d' : 'hexagon';
68
68
  }
69
69
  if (sourceType === 'grid') {
70
- return (shape3d === null || shape3d === void 0 ? void 0 : shape3d.indexOf(shape)) === -1 ? 'grid' : 'grid3d';
70
+ return isShape3D ? 'grid3d' : 'grid';
71
71
  }
72
72
  return 'heatmap';
73
73
  }
@@ -75,14 +75,13 @@ export default class HeatMapModel extends BaseModel {
75
75
  initModels() {
76
76
  var _this = this;
77
77
  return _asyncToGenerator(function* () {
78
- var _shapeAttr$scale;
78
+ var _this$layer$shapeOpti;
79
79
  const {
80
80
  createFramebuffer,
81
81
  getViewportSize,
82
82
  createTexture2D
83
83
  } = _this.rendererService;
84
- const shapeAttr = _this.styleAttributeService.getLayerStyleAttribute('shape');
85
- const shapeType = (shapeAttr === null || shapeAttr === void 0 || (_shapeAttr$scale = shapeAttr.scale) === null || _shapeAttr$scale === void 0 ? void 0 : _shapeAttr$scale.field) || 'heatmap';
84
+ const shapeType = ((_this$layer$shapeOpti = _this.layer.shapeOption) === null || _this$layer$shapeOpti === void 0 ? void 0 : _this$layer$shapeOpti.field) || 'heatmap';
86
85
  _this.shapeType = shapeType;
87
86
  // 生成热力图密度图
88
87
  _this.intensityModel = yield _this.buildHeatMapIntensity();
package/es/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import CanvasLayer from './canvas';
2
- import CityBuildingLayer from './citybuliding/building';
2
+ import CityBuildingLayer from './citybuilding/building';
3
3
  import BaseLayer from './core/BaseLayer';
4
4
  import BaseModel from './core/BaseModel';
5
5
  import GeometryLayer from './geometry';
package/es/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import CanvasLayer from "./canvas";
2
- import CityBuildingLayer from "./citybuliding/building";
2
+ import CityBuildingLayer from "./citybuilding/building";
3
3
  import BaseLayer from "./core/BaseLayer";
4
4
  import BaseModel from "./core/BaseModel";
5
5
  import GeometryLayer from "./geometry"; // 逐步替换为 Geometry
package/es/line/index.js CHANGED
@@ -60,12 +60,11 @@ export default class LineLayer extends BaseLayer {
60
60
  return defaultConfig[type];
61
61
  }
62
62
  getModelType() {
63
- var _shapeAttribute$scale;
63
+ var _this$shapeOption;
64
64
  if (this.layerType) {
65
65
  return this.layerType;
66
66
  }
67
- const shapeAttribute = this.styleAttributeService.getLayerStyleAttribute('shape');
68
- const shape = shapeAttribute === null || shapeAttribute === void 0 || (_shapeAttribute$scale = shapeAttribute.scale) === null || _shapeAttribute$scale === void 0 ? void 0 : _shapeAttribute$scale.field;
67
+ const shape = (_this$shapeOption = this.shapeOption) === null || _this$shapeOption === void 0 ? void 0 : _this$shapeOption.field;
69
68
  return shape || 'line';
70
69
  }
71
70
  processData(filterData) {
@@ -85,19 +85,39 @@ export default class DataMappingPlugin {
85
85
  const {
86
86
  dataArray
87
87
  } = layer.getSource().data;
88
- let filterData = dataArray;
89
- // 数据过滤完 再执行数据映射
90
- if (filter !== null && filter !== void 0 && filter.scale) {
91
- filterData = dataArray.filter(record => {
92
- return this.applyAttributeMapping(filter, record)[0];
93
- });
88
+
89
+ // 优化:合并过滤和准备阶段为单次遍历
90
+ const usedAttributes = attributes.filter(attribute => attribute.scale !== undefined).filter(attribute => attribute.name !== 'filter');
91
+ const hasFilter = filter === null || filter === void 0 ? void 0 : filter.scale;
92
+
93
+ // 第一阶段:过滤原始数据(需要在 processData 之前)
94
+ let filterData = [];
95
+ if (hasFilter) {
96
+ for (let i = 0; i < dataArray.length; i++) {
97
+ const record = dataArray[i];
98
+ const filterResult = this.applyAttributeMapping(filter, record);
99
+ if (filterResult[0]) {
100
+ filterData.push(record);
101
+ }
102
+ }
103
+ } else {
104
+ filterData = dataArray;
94
105
  }
95
- // Tip: layer 对数据做处理
106
+
107
+ // Tip: layer 对数据做处理(需要处理原始数据格式)
96
108
  // 数据处理 在数据进行 mapping 生成 encodeData 之前对数据进行处理
97
- // 在各个 layer 中继承
109
+ const processedFilterData = layer.processData(filterData);
110
+
111
+ // 第二阶段:数据映射
112
+ const encodeData = this.mapping(layer, usedAttributes, processedFilterData, undefined);
98
113
 
99
- filterData = layer.processData(filterData); // 目前只有简单线需要处理
100
- const encodeData = this.mapping(layer, attributes, filterData, undefined);
114
+ // 重置属性状态
115
+ attributes.forEach(attribute => {
116
+ attribute.needRemapping = false;
117
+ });
118
+
119
+ // 调整数据兼容 SimpleCoordinates
120
+ this.adjustData2SimpleCoordinates(encodeData);
101
121
  layer.setEncodedData(encodeData);
102
122
 
103
123
  // 对外暴露事件
@@ -2,29 +2,28 @@ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
2
  import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
3
3
  import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
4
4
  import { IDebugLog, ILayerStage, ScaleTypes, StyleScaleType } from '@antv/l7-core';
5
- import { lodashUtil } from '@antv/l7-utils';
6
- import { extent } from 'd3-array';
7
- import * as d3interpolate from 'd3-interpolate';
8
- import * as d3 from 'd3-scale';
5
+ import { interpolateRgbBasis, lodashUtil } from '@antv/l7-utils';
9
6
  import identity from "../utils/identityScale";
7
+ import { scaleDiverging, scaleLinear, scaleLog, scaleOrdinal, scalePow, scaleQuantile, scaleQuantize, scaleSequential, scaleThreshold, scaleTime } from "../utils/scale";
10
8
  const {
11
9
  isNil,
12
10
  isString,
13
- uniq
11
+ uniq,
12
+ extent
14
13
  } = lodashUtil;
15
14
  const dateRegex = /^(?:(?!0000)[0-9]{4}([-/.]+)(?:(?:0?[1-9]|1[0-2])\1(?:0?[1-9]|1[0-9]|2[0-8])|(?:0?[13-9]|1[0-2])\1(?:29|30)|(?:0?[13578]|1[02])\1(?:31))|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)([-/.]?)0?2\2(?:29))(\s+([01]|([01][0-9]|2[0-3])):([0-9]|[0-5][0-9]):([0-9]|[0-5][0-9]))?$/;
16
15
  const scaleMap = {
17
- [ScaleTypes.LINEAR]: d3.scaleLinear,
18
- [ScaleTypes.POWER]: d3.scalePow,
19
- [ScaleTypes.LOG]: d3.scaleLog,
16
+ [ScaleTypes.LINEAR]: scaleLinear,
17
+ [ScaleTypes.POWER]: scalePow,
18
+ [ScaleTypes.LOG]: scaleLog,
20
19
  [ScaleTypes.IDENTITY]: identity,
21
- [ScaleTypes.SEQUENTIAL]: d3.scaleSequential,
22
- [ScaleTypes.TIME]: d3.scaleTime,
23
- [ScaleTypes.QUANTILE]: d3.scaleQuantile,
24
- [ScaleTypes.QUANTIZE]: d3.scaleQuantize,
25
- [ScaleTypes.THRESHOLD]: d3.scaleThreshold,
26
- [ScaleTypes.CAT]: d3.scaleOrdinal,
27
- [ScaleTypes.DIVERGING]: d3.scaleDiverging
20
+ [ScaleTypes.SEQUENTIAL]: scaleSequential,
21
+ [ScaleTypes.TIME]: scaleTime,
22
+ [ScaleTypes.QUANTILE]: scaleQuantile,
23
+ [ScaleTypes.QUANTIZE]: scaleQuantize,
24
+ [ScaleTypes.THRESHOLD]: scaleThreshold,
25
+ [ScaleTypes.CAT]: scaleOrdinal,
26
+ [ScaleTypes.DIVERGING]: scaleDiverging
28
27
  };
29
28
  /**
30
29
  * 根据 Source 原始数据为指定字段创建 Scale,保存在 StyleAttribute 上,供下游插件使用
@@ -99,7 +98,6 @@ export default class FeatureScalePlugin {
99
98
  if (attribute.scale) {
100
99
  // 创建Scale
101
100
  const attributeScale = attribute.scale;
102
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
103
101
  const fieldValue = attribute.scale.field;
104
102
  attributeScale.names = this.parseFields(isNil(fieldValue) ? [] : fieldValue);
105
103
  const scales = [];
@@ -141,7 +139,7 @@ export default class FeatureScalePlugin {
141
139
  case ScaleTypes.SEQUENTIAL:
142
140
  scale.scale.interpolator(
143
141
  // @ts-ignore
144
- d3interpolate.interpolateRgbBasis(attributeScale.values));
142
+ interpolateRgbBasis(attributeScale.values));
145
143
  break;
146
144
  }
147
145
  }
@@ -198,16 +196,15 @@ export default class FeatureScalePlugin {
198
196
  if (scaleOption && scaleOption.type) {
199
197
  styleScale.scale = this.createDefaultScale(scaleOption);
200
198
  } else {
201
- styleScale.scale = d3.scaleOrdinal([field]);
199
+ styleScale.scale = scaleOrdinal([field]);
202
200
  styleScale.type = StyleScaleType.CONSTANT;
203
201
  }
204
202
  return styleScale;
205
203
  }
206
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
207
204
  const firstValue = (_find = data.find(d => !isNil(d[field]))) === null || _find === void 0 ? void 0 : _find[field];
208
205
  // 常量 Scale
209
206
  if (this.isNumber(field) || isNil(firstValue) && !scaleOption) {
210
- styleScale.scale = d3.scaleOrdinal([field]);
207
+ styleScale.scale = scaleOrdinal([field]);
211
208
  styleScale.type = StyleScaleType.CONSTANT;
212
209
  } else {
213
210
  // 根据数据类型判断 默认等分位,时间,和枚举类型
@@ -219,6 +216,10 @@ export default class FeatureScalePlugin {
219
216
  if (values === undefined) {
220
217
  type = ScaleTypes.IDENTITY;
221
218
  }
219
+ if (name === 'color' && Array.isArray(values) && values.length && values.every(value => isString(value)) && (type === ScaleTypes.LINEAR || type === ScaleTypes.POWER || type === ScaleTypes.LOG)) {
220
+ // Color ramps should use interpolated scales to avoid numeric-only ranges.
221
+ type = ScaleTypes.SEQUENTIAL;
222
+ }
222
223
  const cfg = this.createScaleConfig(type, field, scaleOption, data);
223
224
  styleScale.scale = this.createDefaultScale(cfg);
224
225
  styleScale.option = cfg;
@@ -32,7 +32,7 @@ export default class ShaderUniformPlugin {
32
32
  let uniformBuffer;
33
33
  if (!this.rendererService.uniformBuffers[0]) {
34
34
  // Create a Uniform Buffer Object(UBO).
35
- // Size calculation: 4 mat4 (64) + 1 vec4 (4) + 4 vec3->vec4 (16) + 3 vec4 packed (12) = 96 floats
35
+ // Total size: 93 floats, round up to 96 for safety
36
36
  uniformBuffer = this.rendererService.createBuffer({
37
37
  data: new Float32Array(96),
38
38
  isUBO: true,
@@ -105,34 +105,67 @@ export default class ShaderUniformPlugin {
105
105
  const u_ViewportSize = [width, height];
106
106
  const u_FocalDistance = this.cameraService.getFocalDistance();
107
107
  const u_RelativeOrigin = offset && offset.length >= 2 ? [offset[0], offset[1]] : [0, 0];
108
- const data = [...u_ViewMatrix,
109
- // 16
110
- ...u_ProjectionMatrix,
111
- // 16
112
- ...u_ViewProjectionMatrix,
113
- // 16
114
- ...u_ModelMatrix,
115
- // 16
116
- ...u_ViewportCenterProjection,
117
- // 4
118
- ...u_PixelsPerDegree,
119
- // 4
120
- u_Zoom, ...u_PixelsPerDegree2,
121
- // 4
122
- u_ZoomScale, ...u_PixelsPerMeter,
123
- // 4
124
- u_CoordinateSystem, ...u_CameraPosition,
125
- // 4
126
- u_DevicePixelRatio,
127
- // 4
128
- ...u_ViewportCenter, ...u_ViewportSize,
129
- // 4
130
- u_FocalDistance,
131
- // 1
132
- ...u_RelativeOrigin,
133
- // 2
134
- 0 // padding
135
- ];
108
+
109
+ // Build UBO data array matching GLSL std140 layout
110
+ // std140 rules:
111
+ // - mat4: 16-byte aligned, size 64 bytes (16 floats)
112
+ // - vec4: 16-byte aligned, size 16 bytes (4 floats)
113
+ // - vec3: 16-byte aligned, size 12 bytes (3 floats) - next member can follow if aligned
114
+ // - vec2: 8-byte aligned, size 8 bytes (2 floats)
115
+ // - float: 4-byte aligned, size 4 bytes (1 float)
116
+ // Key: vec3 only occupies 3 floats, NOT 4. The alignment requirement is for START position.
117
+ const floats = [];
118
+
119
+ // mat4 x 4: each 16 floats, all start at multiples of 4 floats (16-byte aligned)
120
+ floats.push(...u_ViewMatrix); // floats 0-15
121
+ floats.push(...u_ProjectionMatrix); // floats 16-31
122
+ floats.push(...u_ViewProjectionMatrix); // floats 32-47
123
+ floats.push(...u_ModelMatrix); // floats 48-63
124
+
125
+ // vec4: 4 floats, starts at float 64 (64 % 4 = 0 ✓)
126
+ floats.push(...u_ViewportCenterProjection); // floats 64-67
127
+
128
+ // vec3: 3 floats only, starts at float 68 (68 % 4 = 0 ✓)
129
+ floats.push(...u_PixelsPerDegree); // floats 68-70 (NOT 68-71!)
130
+
131
+ // float: starts at float 71, any position is fine for 4-byte alignment
132
+ floats.push(u_Zoom); // float 71
133
+
134
+ // vec3: needs 4-float alignment, 72 % 4 = 0
135
+ floats.push(...u_PixelsPerDegree2); // floats 72-74
136
+
137
+ // float: starts at float 75
138
+ floats.push(u_ZoomScale); // float 75
139
+
140
+ // vec3: needs 4-float alignment, 76 % 4 = 0 ✓
141
+ floats.push(...u_PixelsPerMeter); // floats 76-78
142
+
143
+ // float: starts at float 79
144
+ floats.push(u_CoordinateSystem); // float 79
145
+
146
+ // vec3: needs 4-float alignment, 80 % 4 = 0 ✓
147
+ floats.push(...u_CameraPosition); // floats 80-82
148
+
149
+ // float: starts at float 83
150
+ floats.push(u_DevicePixelRatio); // float 83
151
+
152
+ // vec2: needs 2-float alignment, 84 % 2 = 0 ✓
153
+ floats.push(...u_ViewportCenter); // floats 84-85
154
+
155
+ // vec2: needs 2-float alignment, 86 % 2 = 0 ✓
156
+ floats.push(...u_ViewportSize); // floats 86-87
157
+
158
+ // float: starts at float 88
159
+ floats.push(u_FocalDistance); // float 88
160
+
161
+ // vec2: needs 2-float alignment, 89 % 2 = 1, NOT aligned!
162
+ floats.push(0); // padding float 89
163
+ floats.push(...u_RelativeOrigin); // floats 90-91
164
+
165
+ // float u_Reserved3
166
+ floats.push(0); // float 92
167
+
168
+ const data = floats;
136
169
  return {
137
170
  data,
138
171
  uniforms: {
@@ -12,4 +12,4 @@ import RegisterStyleAttributePlugin from './RegisterStyleAttributePlugin';
12
12
  import ShaderUniformPlugin from './ShaderUniformPlugin';
13
13
  import UpdateModelPlugin from './UpdateModelPlugin';
14
14
  import UpdateStyleAttributePlugin from './UpdateStyleAttributePlugin';
15
- export declare function createPlugins(): (DataMappingPlugin | DataSourcePlugin | FeatureScalePlugin | LayerAnimateStylePlugin | LayerMaskPlugin | LayerModelPlugin | LayerStylePlugin | LightingPlugin | MultiPassRendererPlugin | PixelPickingPlugin | RegisterStyleAttributePlugin | ShaderUniformPlugin | UpdateModelPlugin | UpdateStyleAttributePlugin)[];
15
+ export declare function createPlugins(): (DataSourcePlugin | RegisterStyleAttributePlugin | FeatureScalePlugin | DataMappingPlugin | LayerStylePlugin | LayerMaskPlugin | UpdateStyleAttributePlugin | UpdateModelPlugin | MultiPassRendererPlugin | ShaderUniformPlugin | LayerAnimateStylePlugin | LightingPlugin | PixelPickingPlugin | LayerModelPlugin)[];
@@ -19,9 +19,8 @@ export default class PolygonLayer extends BaseLayer {
19
19
  })();
20
20
  }
21
21
  getModelType() {
22
- var _shapeAttribute$scale;
23
- const shapeAttribute = this.styleAttributeService.getLayerStyleAttribute('shape');
24
- const shape = shapeAttribute === null || shapeAttribute === void 0 || (_shapeAttribute$scale = shapeAttribute.scale) === null || _shapeAttribute$scale === void 0 ? void 0 : _shapeAttribute$scale.field;
22
+ var _this$shapeOption;
23
+ const shape = (_this$shapeOption = this.shapeOption) === null || _this$shapeOption === void 0 ? void 0 : _this$shapeOption.field;
25
24
  if (shape === 'fill' || !shape) {
26
25
  return 'fill';
27
26
  } else if (shape === 'extrude') {
@@ -137,10 +137,6 @@ export default class ExtrudeModel extends BaseModel {
137
137
  this.textures = [];
138
138
  }
139
139
  registerBuiltinAttributes() {
140
- const bounds = this.layer.getSource().extent;
141
- const lngLen = bounds[2] - bounds[0];
142
- const latLen = bounds[3] - bounds[1];
143
-
144
140
  // 注册 Position 属性 64 位地位部分,经纬度数据开启双精度,避免大于 22 层级以上出现数据偏移
145
141
  this.registerPosition64LowAttribute();
146
142
  this.styleAttributeService.registerStyleAttribute({
@@ -157,10 +153,29 @@ export default class ExtrudeModel extends BaseModel {
157
153
  },
158
154
  size: 3,
159
155
  update: (feature, featureIdx, vertex) => {
160
- const lng = vertex[0];
161
- const lat = vertex[1];
156
+ // 当启用 enableRelativeCoordinates 时:
157
+ // - vertex 是相对坐标(相对于 relativeOrigin 的偏移)
158
+ // - 需要将相对坐标转换回绝对坐标后,用 originalExtent 计算 UV
159
+ const originalExtent = this.layer.getOriginalExtent();
160
+ const relativeOrigin = this.layer.getRelativeOrigin();
161
+ const isRelativeCoordinates = originalExtent[0] !== 0 || originalExtent[2] !== 0;
162
+ let lng, lat;
163
+ let minLng, minLat, maxLng, maxLat;
164
+ if (isRelativeCoordinates && relativeOrigin) {
165
+ // 相对坐标模式:转换回绝对坐标
166
+ lng = vertex[0] + relativeOrigin[0];
167
+ lat = vertex[1] + relativeOrigin[1];
168
+ [minLng, minLat, maxLng, maxLat] = originalExtent;
169
+ } else {
170
+ // 绝对坐标模式
171
+ lng = vertex[0];
172
+ lat = vertex[1];
173
+ [minLng, minLat, maxLng, maxLat] = this.layer.getSource().extent;
174
+ }
175
+ const lngLen = maxLng - minLng;
176
+ const latLen = maxLat - minLat;
162
177
  // 临时 兼容高德V2
163
- return [(lng - bounds[0]) / lngLen, (lat - bounds[1]) / latLen, vertex[4]];
178
+ return [(lng - minLng) / lngLen, (lat - minLat) / latLen, vertex[4]];
164
179
  }
165
180
  }
166
181
  });
@@ -85,10 +85,6 @@ export default class OceanModel extends BaseModel {
85
85
  (_this$texture3 = this.texture3) === null || _this$texture3 === void 0 || _this$texture3.destroy();
86
86
  }
87
87
  registerBuiltinAttributes() {
88
- const bbox = this.layer.getSource().extent;
89
- const [minLng, minLat, maxLng, maxLat] = bbox;
90
- const lngLen = maxLng - minLng;
91
- const latLen = maxLat - minLat;
92
88
  this.styleAttributeService.registerStyleAttribute({
93
89
  name: 'oceanUv',
94
90
  type: AttributeType.Attribute,
@@ -96,14 +92,29 @@ export default class OceanModel extends BaseModel {
96
92
  name: 'a_uv',
97
93
  shaderLocation: this.attributeLocation.UV,
98
94
  buffer: {
99
- // give the WebGL driver a hint that this buffer may change
100
95
  usage: gl.STATIC_DRAW,
101
96
  data: [],
102
97
  type: gl.FLOAT
103
98
  },
104
99
  size: 2,
105
100
  update: (feature, featureIdx, vertex) => {
106
- const [lng, lat] = vertex;
101
+ // 当启用 enableRelativeCoordinates 时:需要将相对坐标转换回绝对坐标
102
+ const originalExtent = this.layer.getOriginalExtent();
103
+ const relativeOrigin = this.layer.getRelativeOrigin();
104
+ const isRelativeCoordinates = originalExtent[0] !== 0 || originalExtent[2] !== 0;
105
+ let lng, lat;
106
+ let minLng, minLat, maxLng, maxLat;
107
+ if (isRelativeCoordinates && relativeOrigin) {
108
+ lng = vertex[0] + relativeOrigin[0];
109
+ lat = vertex[1] + relativeOrigin[1];
110
+ [minLng, minLat, maxLng, maxLat] = originalExtent;
111
+ } else {
112
+ lng = vertex[0];
113
+ lat = vertex[1];
114
+ [minLng, minLat, maxLng, maxLat] = this.layer.getSource().extent;
115
+ }
116
+ const lngLen = maxLng - minLng;
117
+ const latLen = maxLat - minLat;
107
118
  return [(lng - minLng) / lngLen, (lat - minLat) / latLen];
108
119
  }
109
120
  }