Skip to content

Commit 305b351

Browse files
committed
fix: 修正 WebMapV3 线符号方向处理
- 按地图版本翻转旧版线符号 - 统一 WebMap 线图案方向 - 补充 Sprite 回调和图片翻转测试 AI-GEN: 90% gpt5.6-luna
1 parent 14a28f5 commit 305b351

4 files changed

Lines changed: 104 additions & 3 deletions

File tree

‎src/common/mapping/WebMapV3.js‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* This program are made available under the terms of the Apache License, Version 2.0
33
* which accompanies this distribution and is available at http://www.apache.org/licenses/LICENSE-2.0.html.*/
44
import { FetchRequest } from '../util/FetchRequest';
5-
import { getLayerCatalogRenderLayers, getLayerInfosFromCatalogs, getMainLayerFromCatalog, isSameRasterLayer, mergeFeatures, transformUrl } from './utils/util';
5+
import { getLayerCatalogRenderLayers, getLayerInfosFromCatalogs, getMainLayerFromCatalog, isSameRasterLayer, mergeFeatures, transformUrl, flipImageVertically } from './utils/util';
66
import { SourceListModelV3 } from './utils/SourceListModelV3';
77
import cloneDeep from 'lodash.clonedeep';
88

@@ -289,6 +289,9 @@ export function createWebMapV3Extending(SuperClass, { MapManager, mapRepo, crsMa
289289
// 初始化 map
290290
const mapOptions = {
291291
...this.mapOptions,
292+
// 统一线图案方向,避免 Mapbox GL 默认方向与 WebMap 符号方向约定不一致;旧版资源翻转由 _getSpriteLoad 按地图版本处理。
293+
linePatternOrientation: 'west-to-east',
294+
onSpriteLoad: this._getSpriteLoad(),
292295
transformRequest: this._getTransformRequest(),
293296
container: this.options.target,
294297
crs: this._baseProjection,
@@ -315,6 +318,23 @@ export function createWebMapV3Extending(SuperClass, { MapManager, mapRepo, crsMa
315318
});
316319
}
317320

321+
_getSpriteLoad() {
322+
const version = this._mapInfo && this._mapInfo.version;
323+
const [major, minor, patch] = typeof version === 'string' ? version.split('.').map(Number) : [];
324+
// 3.3.7 及以前的地图线符号需要垂直翻转;新版本由地图数据自身保证方向。
325+
if (major > 3 || (major === 3 && minor > 3) || (major === 3 && minor === 3 && patch > 7)) {
326+
return;
327+
}
328+
return (id, imageData, width, height) => {
329+
// 翻转所有 line- 开头的图案
330+
if (id && id.startsWith('line-')) {
331+
return flipImageVertically(imageData, width, height);
332+
}
333+
334+
return null;
335+
};
336+
}
337+
318338
_getTransformRequest() {
319339
if (this.mapOptions.transformRequest) {
320340
return this.mapOptions.transformRequest;

‎src/common/mapping/utils/util.js‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,4 +216,19 @@ export function getLayerCatalogRenderLayers(parts, catalogId, layersOnMap) {
216216
export function getMainLayerFromCatalog(layerParts, catalogId, layersOnMap) {
217217
const renderLayers = getLayerCatalogRenderLayers(layerParts, catalogId, layersOnMap);
218218
return layersOnMap.find(item => item.id === renderLayers[0]);
219-
}
219+
}
220+
221+
// 垂直翻转 RGBA 图片,保持像素顺序并避免逐通道复制。
222+
export function flipImageVertically(imageData, width, height) {
223+
const sourceData = imageData.data || imageData;
224+
const flipped = new Uint8Array(sourceData.length);
225+
const rowSize = width * 4;
226+
227+
for (let row = 0; row < height; row++) {
228+
const sourceRowStart = row * rowSize;
229+
const targetRowStart = (height - row - 1) * rowSize;
230+
flipped.set(sourceData.subarray(sourceRowStart, sourceRowStart + rowSize), targetRowStart);
231+
}
232+
233+
return flipped;
234+
}

‎test/common/mapping/WebMapV3Spec.js‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,52 @@ describe('WebMapV3 - addLocalIdeographFontFamily', () => {
125125
inst._createMap();
126126
expect(capturedOptions).toBeDefined();
127127
expect(capturedOptions.localIdeographFontFamily).toBe('sans-serif,PingFang SC Regular');
128+
expect(capturedOptions.linePatternOrientation).toBe('west-to-east');
129+
expect(capturedOptions.onSpriteLoad).toEqual(jasmine.any(Function));
130+
});
131+
});
132+
133+
describe('_getSpriteLoad', () => {
134+
it('should flip line sprites for maps at version 3.3.7', () => {
135+
instance._mapInfo = { version: '3.3.7' };
136+
const onSpriteLoad = instance._getSpriteLoad();
137+
const imageData = new Uint8Array([
138+
1, 2, 3, 4,
139+
5, 6, 7, 8
140+
]);
141+
142+
expect(onSpriteLoad('line-pattern', imageData, 1, 2)).toEqual(new Uint8Array([
143+
5, 6, 7, 8,
144+
1, 2, 3, 4
145+
]));
146+
expect(onSpriteLoad('point-pattern', imageData, 1, 2)).toBeNull();
147+
});
148+
149+
it('should not add a sprite callback for maps newer than version 3.3.7', () => {
150+
instance._mapInfo = { version: '3.3.8' };
151+
152+
expect(instance._getSpriteLoad()).toBeUndefined();
153+
});
154+
155+
it('should compare version components numerically', () => {
156+
instance._mapInfo = { version: '3.3.10' };
157+
158+
expect(instance._getSpriteLoad()).toBeUndefined();
159+
});
160+
161+
it('should disable the callback for higher major and minor versions', () => {
162+
['4.0.0', '3.4.0'].forEach(version => {
163+
instance._mapInfo = { version };
164+
expect(instance._getSpriteLoad()).toBeUndefined();
165+
});
166+
});
167+
168+
it('should keep the callback when the map version is missing', () => {
169+
instance._mapInfo = {};
170+
const onSpriteLoad = instance._getSpriteLoad();
171+
172+
expect(onSpriteLoad).toEqual(jasmine.any(Function));
173+
expect(onSpriteLoad(null, new Uint8Array(4), 1, 1)).toBeNull();
128174
});
129175
});
130176
});

‎test/common/mapping/utils/UtilSpec.js‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,26 @@
1-
import { isSameRasterLayer } from '../../../../src/common/mapping/utils/util';
1+
import { flipImageVertically, isSameRasterLayer } from '../../../../src/common/mapping/utils/util';
22

33
describe('util', () => {
4+
describe('flipImageVertically', () => {
5+
it('flips RGBA rows in a typed array', () => {
6+
const pixels = new Uint8Array([
7+
1, 2, 3, 4, 5, 6, 7, 8,
8+
9, 10, 11, 12, 13, 14, 15, 16
9+
]);
10+
11+
expect(flipImageVertically(pixels, 2, 2)).toEqual(new Uint8Array([
12+
9, 10, 11, 12, 13, 14, 15, 16,
13+
1, 2, 3, 4, 5, 6, 7, 8
14+
]));
15+
});
16+
17+
it('accepts ImageData-like objects and a single-row image', () => {
18+
const pixels = new Uint8ClampedArray([1, 2, 3, 4, 5, 6, 7, 8]);
19+
const result = flipImageVertically({ data: pixels }, 2, 1);
20+
21+
expect(result).toEqual(new Uint8Array(pixels));
22+
});
23+
});
424
it('isSameRasterLayer', (done) => {
525
let res = isSameRasterLayer(
626
{ type: 'raster', tiles: ['http:17.0.0.1:8190/iserver/rest/maps/China'] },

0 commit comments

Comments
 (0)