Skip to content

Commit f7eb838

Browse files
committed
fix: 修复 L7 线图层纹理方向
- 按地图版本翻转旧版 L7 线纹理 - 统一 WebMap L7 线图案方向 - 补充版本判断、纹理翻转及方向配置测试 AI-GEN: 90% gpt-6
1 parent f3b4fd3 commit f7eb838

10 files changed

Lines changed: 214 additions & 16 deletions

File tree

‎src/common/index.common.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -754,4 +754,4 @@ export { CartoCSS, ThemeStyle };
754754
export { ElasticSearch };
755755
export { Lang };
756756
export { KnowledgeGraph } from './overlay/KnowledgeGraph';
757-
export { createSpriteLoadHandler } from './mapping/WebMapV3';
757+
export { createSpriteLoadHandler, isMapVersionGreaterThan, flipImageVertically } from './mapping/WebMapV3';

‎src/common/mapping/WebMapV3.js‎

Lines changed: 4 additions & 3 deletions
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, flipImageVertically } from './utils/util';
5+
import { getLayerCatalogRenderLayers, getLayerInfosFromCatalogs, getMainLayerFromCatalog, isSameRasterLayer, mergeFeatures, transformUrl, flipImageVertically, isMapVersionGreaterThan } from './utils/util';
66
import { SourceListModelV3 } from './utils/SourceListModelV3';
77
import cloneDeep from 'lodash.clonedeep';
88

@@ -161,15 +161,16 @@ export const LEGEND_STYLE_TYPES = {
161161
STYLE: 'style'
162162
};
163163

164+
export { isMapVersionGreaterThan, flipImageVertically };
165+
164166
/**
165167
* 按地图版本创建 Sprite 加载处理函数,供 WebMap 和外部 WebApp 共用。
166168
* @param {string} mapVersion 地图版本号。
167169
* @returns {Function|undefined} 旧版地图返回线符号处理函数,新版地图不需要额外处理。
168170
*/
169171
export function createSpriteLoadHandler(mapVersion) {
170-
const [major, minor, patch] = typeof mapVersion === 'string' ? mapVersion.split('.').map(Number) : [];
171172
// 3.3.7 及以前的地图线符号需要垂直翻转;新版本由地图数据自身保证方向。
172-
if (major > 3 || (major === 3 && minor > 3) || (major === 3 && minor === 3 && patch > 7)) {
173+
if (isMapVersionGreaterThan(mapVersion, '3.3.7')) {
173174
return;
174175
}
175176
return (id, imageData, width, height) => {

‎src/common/mapping/index.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ export * from './WebMapService';
33
export * from './utils/epsg-define';
44
export * from './WebMapBase';
55
export * from './utils/SourceListModelV2';
6-
export { createSpriteLoadHandler } from './WebMapV3';
6+
export { createSpriteLoadHandler, isMapVersionGreaterThan, flipImageVertically } from './WebMapV3';

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

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { FetchRequest } from '../../util/FetchRequest';
22
import center from '@turf/center';
33
import * as G2 from '@antv/g2';
4-
import { isNumber } from './util';
4+
import { flipImageVertically, isMapVersionGreaterThan, isNumber } from './util';
55
import Color from './Color';
66
import debounce from 'lodash.debounce';
77
import { getEpsgCodeInfo, getProjection, registerProjection, transformCoodinates } from './epsg-define';
@@ -220,7 +220,7 @@ export function getL7Filter(filter, featureFilter) {
220220
}
221221

222222
export function L7LayerUtil(config) {
223-
const { featureFilter, expression, spec, L7Layer, L7, proj4, webMapService } = config;
223+
const { featureFilter, expression, spec, L7Layer, L7, proj4, webMapService, linePatternOrientation = 'east-to-west' } = config;
224224

225225
/**
226226
* @param {string} url
@@ -1653,14 +1653,31 @@ export function L7LayerUtil(config) {
16531653
* @param sprite
16541654
* @param scene
16551655
*/
1656-
async function addTextures({ layers, sprite, spriteJson, scene, options }) {
1656+
async function addTextures({ layers, sprite, spriteJson, scene, options, mapVersion }) {
16571657
const timestamp = +new Date();
16581658
for (let index = 0; index < layers.length; index++) {
16591659
const l = layers[index];
16601660
const texture = (l.texture || {}).values;
16611661
const iconInfo = spriteJson[texture];
16621662
if (iconInfo) {
1663-
const image = await changeSpriteIconToImgData(sprite, { ...iconInfo, id: texture }, options);
1663+
let image = await changeSpriteIconToImgData(sprite, { ...iconInfo, id: texture }, options);
1664+
if (
1665+
image &&
1666+
l.type === MSLayerType.line &&
1667+
typeof mapVersion === 'string' &&
1668+
!isMapVersionGreaterThan(mapVersion, '3.3.7')
1669+
) {
1670+
// 3.3.7 及以前的 L7 线纹理需垂直翻转,才能与地图线符号方向保持一致。
1671+
const canvas = document.createElement('canvas');
1672+
canvas.width = image.width;
1673+
canvas.height = image.height;
1674+
const context = canvas.getContext('2d');
1675+
if (context) {
1676+
const flippedImage = context.createImageData(image.width, image.height);
1677+
flippedImage.data.set(flipImageVertically(image, image.width, image.height));
1678+
image = flippedImage;
1679+
}
1680+
}
16641681
const style = l.style || {};
16651682
const color = style.textureColor,
16661683
rotate = style.textureRotate;
@@ -1983,7 +2000,8 @@ export function L7LayerUtil(config) {
19832000
options: {
19842001
...l.options,
19852002
layerID: (l.options || {}).name,
1986-
featureId: promoteId
2003+
featureId: promoteId,
2004+
linePatternOrientation
19872005
}
19882006
});
19892007
// getL7Layer返回原生antv l7 layer的实例
@@ -2033,7 +2051,7 @@ export function L7LayerUtil(config) {
20332051
return {
20342052
async addL7Layers({ map, webMapInfo, l7Layers, spriteDatas, options }) {
20352053
// 添加L7图层
2036-
const { layers, sources, sprite } = webMapInfo;
2054+
const { layers, sources, sprite, version: mapVersion } = webMapInfo;
20372055
const formateL7Layers = await restoreL7Layers({
20382056
layers: l7Layers,
20392057
sources,
@@ -2049,7 +2067,8 @@ export function L7LayerUtil(config) {
20492067
spriteJson: spriteDatas,
20502068
sprite,
20512069
scene,
2052-
options
2070+
options,
2071+
mapVersion
20532072
});
20542073
} catch (error) {
20552074
console.error(error);

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,24 @@ export function getMainLayerFromCatalog(layerParts, catalogId, layersOnMap) {
218218
return layersOnMap.find(item => item.id === renderLayers[0]);
219219
}
220220

221+
// 按数字组件比较地图版本,避免 3.3.10 被误判为低于 3.3.7。
222+
export function isMapVersionGreaterThan(mapVersion, referenceVersion) {
223+
if (typeof mapVersion !== 'string' || typeof referenceVersion !== 'string') {
224+
return false;
225+
}
226+
const mapVersionParts = mapVersion.split('.').map(Number);
227+
const referenceVersionParts = referenceVersion.split('.').map(Number);
228+
const partCount = Math.max(mapVersionParts.length, referenceVersionParts.length);
229+
for (let index = 0; index < partCount; index++) {
230+
const mapPart = mapVersionParts[index] || 0;
231+
const referencePart = referenceVersionParts[index] || 0;
232+
if (mapPart !== referencePart) {
233+
return mapPart > referencePart;
234+
}
235+
}
236+
return false;
237+
}
238+
221239
// 垂直翻转 RGBA 图片,保持像素顺序并避免逐通道复制。
222240
export function flipImageVertically(imageData, width, height) {
223241
const sourceData = imageData.data || imageData;

‎src/mapboxgl/mapping/WebMap.js‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,9 @@ export class WebMap extends createWebMapBaseExtending(mapboxgl.Evented, { mapRep
123123
L7Layer,
124124
L7,
125125
proj4: this._crsManager.getProj4(),
126-
webMapService: this.webMapService
126+
webMapService: this.webMapService,
127+
// 统一线图案方向,避免 Mapbox GL 默认方向与 WebMap 符号方向约定不一致;
128+
linePatternOrientation: 'west-to-east'
127129
});
128130
switch (type) {
129131
case 'MapStyle':

‎test/common/mapping/WebMapV3Spec.js‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { createWebMapV3Extending } from '../../../src/common/mapping/WebMapV3';
2-
import { createSpriteLoadHandler } from '../../../src/common/mapping';
3-
import { createSpriteLoadHandler as createPublicSpriteLoadHandler } from '../../../src/common/index.common';
2+
import { createSpriteLoadHandler, flipImageVertically, isMapVersionGreaterThan } from '../../../src/common/mapping';
3+
import {
4+
createSpriteLoadHandler as createPublicSpriteLoadHandler,
5+
flipImageVertically as flipPublicImageVertically,
6+
isMapVersionGreaterThan as isPublicMapVersionGreaterThan
7+
} from '../../../src/common/index.common';
48
import { createWebMapBaseExtending } from '../../../src/common/mapping/WebMapBase';
59
import { Events } from '../../../src/common/commontypes';
610

@@ -137,6 +141,8 @@ describe('WebMapV3 - addLocalIdeographFontFamily', () => {
137141
expect(createSpriteLoadHandler('3.3.7')).toEqual(jasmine.any(Function));
138142
expect(createSpriteLoadHandler('3.3.8')).toBeUndefined();
139143
expect(createPublicSpriteLoadHandler).toBe(createSpriteLoadHandler);
144+
expect(flipImageVertically).toBe(flipPublicImageVertically);
145+
expect(isMapVersionGreaterThan).toBe(isPublicMapVersionGreaterThan);
140146
});
141147

142148
it('should flip line sprites for maps at version 3.3.7', () => {

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

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,126 @@ describe('L7LayerUtil', () => {
7676
options
7777
};
7878

79+
async function addLineTextureForVersion(mapVersion, textureLayerUtil = l7LayerUtil) {
80+
const sourcePixels = new Uint8ClampedArray([
81+
1, 2, 3, 4, 5, 6, 7, 8,
82+
9, 10, 11, 12, 13, 14, 15, 16
83+
]);
84+
let uploadedPixels;
85+
const context = {
86+
drawImage: jasmine.createSpy('drawImage'),
87+
getImageData: () => ({ width: 2, height: 2, data: sourcePixels.slice() }),
88+
createImageData: (width, height) => ({ width, height, data: new Uint8ClampedArray(width * height * 4) }),
89+
putImageData: (imageData) => {
90+
uploadedPixels = Array.from(imageData.data);
91+
}
92+
};
93+
spyOn(window, 'XMLHttpRequest').and.callFake(() => ({
94+
open: jasmine.createSpy('open'),
95+
setRequestHeader: jasmine.createSpy('setRequestHeader'),
96+
send: function () {
97+
this.readyState = 4;
98+
this.status = 200;
99+
this.response = {};
100+
this.onreadystatechange();
101+
}
102+
}));
103+
spyOn(window.URL, 'createObjectURL').and.returnValue('blob:test-sprite');
104+
spyOn(window, 'Image').and.callFake(function () {
105+
return {
106+
width: 2,
107+
height: 2,
108+
set src(value) {
109+
this.source = value;
110+
setTimeout(() => this.onload && this.onload(), 0);
111+
}
112+
};
113+
});
114+
spyOn(HTMLCanvasElement.prototype, 'getContext').and.returnValue(context);
115+
spyOn(HTMLCanvasElement.prototype, 'toDataURL').and.returnValue('data:image/png;base64,test');
116+
117+
const line = {
118+
id: 'line-texture',
119+
type: 'line-extrusion',
120+
source: 'line-source',
121+
layout: {},
122+
paint: {
123+
'line-extrusion-pattern': 'line-pattern',
124+
'line-extrusion-width': 1
125+
}
126+
};
127+
const scene = new mockL7.Scene();
128+
const map = {
129+
getL7Scene: () => Promise.resolve(scene),
130+
getLayer: () => false,
131+
addLayer: jasmine.createSpy('addLayer')
132+
};
133+
await textureLayerUtil.addL7Layers({
134+
map,
135+
webMapInfo: {
136+
version: mapVersion,
137+
sprite: '/sprite',
138+
layers: [line],
139+
sources: {
140+
'line-source': {
141+
type: 'geojson',
142+
data: { type: 'FeatureCollection', features: [] }
143+
}
144+
}
145+
},
146+
l7Layers: [line],
147+
spriteDatas: {
148+
'line-pattern': { x: 0, y: 0, width: 2, height: 2 }
149+
},
150+
options: {
151+
withCredentials: false,
152+
emitterEvent: jasmine.createSpy('emitterEvent')
153+
}
154+
});
155+
return { uploadedPixels, layer: map.addLayer.calls.first().args[0] };
156+
}
157+
79158
afterEach(() => {
80159
layerMaplist = {};
81160
});
82161

162+
it('vertically flips L7 line textures through version 3.3.7', async () => {
163+
const westToEastL7LayerUtil = L7LayerUtil({
164+
featureFilter,
165+
expression,
166+
spec,
167+
L7Layer,
168+
L7,
169+
webMapService: mockWebMapService,
170+
linePatternOrientation: 'west-to-east'
171+
});
172+
const { uploadedPixels, layer } = await addLineTextureForVersion('3.3.7', westToEastL7LayerUtil);
173+
174+
expect(uploadedPixels).toEqual([
175+
9, 10, 11, 12, 13, 14, 15, 16,
176+
1, 2, 3, 4, 5, 6, 7, 8
177+
]);
178+
expect(layer.getLayer().linePatternOrientation).toBe('west-to-east');
179+
});
180+
181+
it('keeps newer L7 line textures unchanged', async () => {
182+
const { uploadedPixels } = await addLineTextureForVersion('3.3.8');
183+
const originalPixels = [
184+
1, 2, 3, 4, 5, 6, 7, 8,
185+
9, 10, 11, 12, 13, 14, 15, 16
186+
];
187+
188+
expect(uploadedPixels).toEqual(originalPixels);
189+
});
190+
191+
it('keeps unversioned L7 line textures unchanged', async () => {
192+
const { uploadedPixels } = await addLineTextureForVersion(undefined);
193+
expect(uploadedPixels).toEqual([
194+
1, 2, 3, 4, 5, 6, 7, 8,
195+
9, 10, 11, 12, 13, 14, 15, 16
196+
]);
197+
});
198+
83199
it('add od layer', (done) => {
84200
spyOn(FetchRequest, 'get').and.callFake((url, _, nextOptions) => {
85201
expect(nextOptions.withCredentials).toBe(options.withCredentials);

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

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

37
describe('util', () => {
48
describe('flipImageVertically', () => {
@@ -21,6 +25,23 @@ describe('util', () => {
2125
expect(result).toEqual(new Uint8Array(pixels));
2226
});
2327
});
28+
29+
describe('isMapVersionGreaterThan', () => {
30+
it('compares numeric version components', () => {
31+
expect(isMapVersionGreaterThan('3.3.8', '3.3.7')).toBe(true);
32+
expect(isMapVersionGreaterThan('3.3.10', '3.3.7')).toBe(true);
33+
expect(isMapVersionGreaterThan('3.4.0', '3.3.7')).toBe(true);
34+
expect(isMapVersionGreaterThan('4.0.0', '3.3.7')).toBe(true);
35+
expect(isMapVersionGreaterThan('3.3.7', '3.3.7')).toBe(false);
36+
expect(isMapVersionGreaterThan('3.3.6', '3.3.7')).toBe(false);
37+
});
38+
39+
it('returns false when either version is absent or not a string', () => {
40+
expect(isMapVersionGreaterThan(undefined, '3.3.7')).toBe(false);
41+
expect(isMapVersionGreaterThan('3.3.8', undefined)).toBe(false);
42+
});
43+
});
44+
2445
it('isSameRasterLayer', (done) => {
2546
let res = isSameRasterLayer(
2647
{ type: 'raster', tiles: ['http:17.0.0.1:8190/iserver/rest/maps/China'] },

‎test/mapboxgl/mapping/WebMapV3Spec.js‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { FetchRequest } from '../../../src/common/util/FetchRequest';
33
import { createWebMapV3Extending } from '../../../src/common/mapping/WebMapV3';
44
import { createMapClassExtending } from '../../../src/common/mapping/MapBase';
55
import { L7LayerUtil } from '../../../src/common/mapping/utils/L7LayerUtil';
6+
import * as L7LayerUtilModule from '../../../src/common/mapping/utils/L7LayerUtil';
67
import { WebMap } from '../../../src/mapboxgl/mapping/WebMap';
78
import { createSpriteLoadHandler } from '../../../src/mapboxgl';
89
import * as MapManagerUtil from '../../../src/mapboxgl/mapping/webmap/MapManager';
@@ -19,6 +20,20 @@ describe('mapboxgl-webmap3.0', () => {
1920
it('exports the Sprite load handler from the package entry point', () => {
2021
expect(createSpriteLoadHandler('3.3.7')).toEqual(jasmine.any(Function));
2122
});
23+
24+
it('sets the WebMap line pattern orientation for L7 layers', () => {
25+
const webMap = Object.create(WebMap.prototype);
26+
webMap._crsManager = { getProj4: () => proj4 };
27+
webMap.webMapService = mockWebMapService;
28+
spyOn(L7LayerUtilModule, 'L7LayerUtil').and.callThrough();
29+
30+
webMap._createWebMapFactory('WebMap3');
31+
32+
expect(L7LayerUtilModule.L7LayerUtil).toHaveBeenCalledWith(
33+
jasmine.objectContaining({ linePatternOrientation: 'west-to-east' })
34+
);
35+
});
36+
2237
var originalTimeout, testDiv;
2338
var server = 'http://localhost:8190/iportal/';
2439
var id = 617580084;

0 commit comments

Comments
 (0)