Skip to content

Commit

Permalink
[fix]点选支持l7图层,3d填充面
Browse files Browse the repository at this point in the history
  • Loading branch information
luoxiao-supermap committed Nov 20, 2024
1 parent 465cb75 commit 3aefe29
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 17 deletions.
113 changes: 100 additions & 13 deletions src/mapboxgl/layer-highlight/LayerHighlightViewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ interface HighlightStyle {
circle: InstanceType<typeof CircleStyle>;
line: InstanceType<typeof LineStyle>;
fill: InstanceType<typeof FillStyle>;
fillExtrusion?: any;
strokeLine?: InstanceType<typeof LineStyle>;
stokeLine?: InstanceType<typeof LineStyle>;
}
Expand Down Expand Up @@ -97,6 +98,8 @@ interface CreateRelatedDatasParams {
isMultiple?: boolean;
}

type mapboxEnhanceLayer = mapboxglTypes.Layer & { l7layer?: any };

const HIGHLIGHT_COLOR = '#01ffff';

const PAINT_BASIC_ATTRS: BasicStyleAttrs = {
Expand Down Expand Up @@ -141,6 +144,15 @@ const LAYER_DEFAULT_STYLE = {
visibility: 'visible'
}
},
'fill-extrusion': {
paint: {
'fill-extrusion-color': HIGHLIGHT_COLOR,
'fill-extrusion-opacity': 0.6
},
layout: {
visibility: 'visible'
}
},
symbol: {
layout: {
'icon-size': 5
Expand Down Expand Up @@ -192,8 +204,9 @@ export default class HighlightLayer extends mapboxgl.Evented {
};
}

setMap({ map }: MapLoadInfo) {
setMap({ map, webmap }: MapLoadInfo) {
this.map = map;
this.webmap = webmap;
this.registerMapClick();
this.setTargetLayers(this.highlightOptions.layerIds);
}
Expand Down Expand Up @@ -273,8 +286,54 @@ export default class HighlightLayer extends mapboxgl.Evented {
this.map.off('mouseleave', layerId, this.handleMapMouseLeave);
});
}
highlightL7Layer({ layer, features, filter }) {
const { type, id, paint } = layer;
const nextPaint = Object.assign({}, paint);
let styleType = type;
const highlightLayerStyle: HighlightStyle = JSON.parse(JSON.stringify(this.highlightOptions.style));
switch (type) {
case 'line-extrusion':
styleType = 'line';
break;
case 'radar':
case 'point-extrusion':
styleType = 'circle';
break;
default:
styleType = highlightLayerStyle[type] ? type : 'fill';
break;
}
const paintKeys = Object.keys(paint);
const { paint: paintStyle } = highlightLayerStyle[styleType];
for (const key in paintStyle) {
const matchKey = paintKeys.find(item => item.replace(`${type}-`, '') === key.replace(`${styleType}-`, ''));
if (matchKey) {
nextPaint[matchKey] = key.match(/-(radius|width)/)
? Math.max(paintStyle[key], nextPaint[matchKey])
: paintStyle[key];
}
}
this.webmap.copyLayer(id, { id: `${id}-${this.highlightOptions.name}-SM-highlighted`, filter, paint: nextPaint });
this.setL7Filter(layer, features);
}

setL7Filter(layer, features) {
layer.setSelectedDatas(features);
const layerFilter = this.map.getFilter(layer.id);
this.map.setFilter(layer.id, layerFilter);
}

addHighlightLayers(layer: mapboxEnhanceLayer, filter: any, features) {
const { l7layer } = layer;
if (l7layer) {
this.highlightL7Layer({ layer, features, filter });
return;
} else {
this.addNormalHighlightLayers(layer, filter);
}
}

addHighlightLayers(layer: mapboxglTypes.Layer, filter: any) {
addNormalHighlightLayers(layer: mapboxglTypes.Layer, filter: any) {
let type = layer.type as unknown as StyleTypes[number];
let paint = layer.paint;
const id = layer.id;
Expand All @@ -288,7 +347,7 @@ export default class HighlightLayer extends mapboxgl.Evented {
types.push('strokeLine');
}
const layerHighlightStyle = this.createLayerHighlightStyle(types, id);
if (['circle', 'line', 'fill'].includes(type)) {
if (['circle', 'line', 'fill', 'fill-extrusion'].includes(type)) {
const layerStyle = layerHighlightStyle[type];
const highlightLayer = Object.assign({}, layer, {
id: this.createHightlightLayerId(id),
Expand Down Expand Up @@ -330,6 +389,13 @@ export default class HighlightLayer extends mapboxgl.Evented {
if (!this.map) {
return;
}
this.highlightOptions.layerIds.forEach(layerId =>{
const layer = this.map.getLayer(layerId);
// @ts-ignore
if (layer?.l7layer) {
this.setL7Filter(layer, []);
}
})
const layersToRemove = this.getHighlightLayerIds(this.highlightOptions.layerIds);
layersToRemove.forEach(layerId => {
if (this.map.getLayer(layerId)) {
Expand Down Expand Up @@ -399,15 +465,28 @@ export default class HighlightLayer extends mapboxgl.Evented {
fields = this.highlightOptions.featureFieldsMap?.[targetId]
}: CreateFilterExpParams) {
// 高亮过滤(所有字段)
const filterKeys = ['smx', 'smy', 'lon', 'lat', 'longitude', 'latitude', 'x', 'y', 'usestyle', 'featureinfo'];
const filterKeys = ['smx', 'smy', 'lon', 'lat', 'longitude', 'latitude', 'x', 'y', 'usestyle', 'featureinfo', '_id', 'id', 'smgeometry'];
const isBasicType = (item: any) => {
return typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean';
};
const UNIQUE_FIELD = ['SMID', 'SMPID'];
const properties = feature.properties || {};
let uniqueId;
for (const name of UNIQUE_FIELD) {
for (const attr in properties) {
if (attr.toUpperCase() === name) {
uniqueId = attr;
break;
}
}
}
const filter: any[] = ['all'];
const featureKeys: string[] = fields || feature._vectorTileFeature?._keys || Object.keys(feature.properties);
const keys: string[] = fields || feature._vectorTileFeature?._keys || Object.keys(feature.properties);
const featureKeys = uniqueId ? [uniqueId] : keys;

return featureKeys.reduce((exp, key) => {
if (filterKeys.indexOf(key.toLowerCase()) === -1 && isBasicType(feature.properties[key])) {
exp.push(['==', key, feature.properties[key]]);
exp.push(['==', ['get', key], feature.properties[key]]);
}
return exp;
}, filter);
Expand All @@ -433,6 +512,13 @@ export default class HighlightLayer extends mapboxgl.Evented {
}
});
});
// 3d填充面的样式用普通面的配置项
highlightStyle['fill-extrusion'] = {
paint: {
'fill-extrusion-color': highlightStyle.fill.paint['fill-color'],
'fill-extrusion-opacity': highlightStyle.fill.paint['fill-opacity'],
}
};
return highlightStyle;
}

Expand All @@ -450,7 +536,12 @@ export default class HighlightLayer extends mapboxgl.Evented {
return layerIds.reduce((idList, layerId) => {
const highlightLayerId = this.createHightlightLayerId(layerId);
const highlightStrokeLayerId = this.createHighlightStrokeLayerId(layerId);
idList.push(highlightLayerId, highlightStrokeLayerId);
if (this.map.getLayer(highlightLayerId)) {
idList.push(highlightLayerId);
}
if (this.map.getLayer(highlightStrokeLayerId)) {
idList.push(highlightStrokeLayerId);
}
return idList;
}, []);
}
Expand Down Expand Up @@ -510,7 +601,7 @@ export default class HighlightLayer extends mapboxgl.Evented {
};
const filterExps = this.createFilterExps(params);
popupDatas = this.createPopupDatas(params);
this.addHighlightLayers(activeTargetLayer, filterExps);
this.addHighlightLayers(activeTargetLayer as mapboxEnhanceLayer, filterExps, this.resultFeatures);
}
const emitData: MapSelectionChangedEmit = {
features,
Expand Down Expand Up @@ -565,11 +656,7 @@ export default class HighlightLayer extends mapboxgl.Evented {
return features.reduce(
(filterExps: any[], feature) => {
const filterExp = this.createFilterExp({ feature, targetId });
if (isMultiple) {
filterExps.push(filterExp);
} else {
filterExps = filterExp;
}
filterExps.push(filterExp);
return filterExps;
},
['any']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,17 @@ describe('LayerHighlightViewModel', () => {
let map;
const uniqueName = 'Test';
const mockLayerName = 'China';
const copyLayerSpy = jest.fn();
let viewModel;

beforeEach(() => {
map = new Map({
style: { center: [0, 0], zoom: 1, layers: [], sources: {} }
});

viewModel = new LayerHighlightViewModel({ name: uniqueName, style: highlightStyle });
viewModel.setMap({ map });
const webmap = { copyLayer: copyLayerSpy };
viewModel.setMap({ map, webmap });
});

afterEach(() => {
Expand All @@ -71,15 +74,85 @@ describe('LayerHighlightViewModel', () => {
done();
});

it('map click l7 animate marker', done => {
const setSelectedDatas = jest.fn();
jest.spyOn(map, 'queryRenderedFeatures').mockImplementation(() => [
{
type: 'Feature',
properties: {
smpid: 7,
type: '分类5',
_id: 177554
},
layer: { paint: {}, l7layer: {}, setSelectedDatas },
geometry: {
type: 'Point',
coordinates: [122.20916748046851, 31.332525032307764]
}
}
]);
const viewModel = new LayerHighlightViewModel({ name: uniqueName, style: highlightStyle, layerIds: ['动画点'] });
const webmap = { copyLayer: copyLayerSpy };
viewModel.setMap({ map, webmap });

viewModel.once('mapselectionchanged', ({ features }) => {
expect(features.length).toBeGreaterThan(0);
expect(copyLayerSpy).toBeCalled()
expect(setSelectedDatas).toBeCalled()
viewModel.removeHighlightLayers();
expect(setSelectedDatas).toBeCalled()
viewModel.unregisterMapClick();
done();
});
expect(viewModel.featureFields).toBeUndefined();
const featureFieldsMap = { [mockLayerName]: ['type'] };
viewModel.setFeatureFieldsMap(featureFieldsMap);
expect(viewModel.highlightOptions.featureFieldsMap).toEqual(featureFieldsMap);
viewModel.map.fire('click', { target: map, point: { x: 10, y: 5 } });
});
it('map click ms fill extrusion', done => {
jest.spyOn(map, 'queryRenderedFeatures').mockImplementation(() => [
{
type: 'Feature',
properties: {
type: '分类5',
_id: 177554
},
layer: {id:'3d填充面', type: 'fill-extrusion', paint: {} },
geometry: {
type: 'Polygon',
coordinates: [[[122.20916748046851, 31.332525032307764]]]
}
}
]);
const viewModel = new LayerHighlightViewModel({ name: uniqueName, style: highlightStyle, layerIds: ['3d填充面'] });
const webmap = { copyLayer: copyLayerSpy };
viewModel.setMap({ map, webmap });

viewModel.once('mapselectionchanged', () => {
const layers = map.getStyle().layers;
expect(layers.length).toBe(1);
expect(layers[0].id).toBe(`3d填充面-${uniqueName}-SM-highlighted`);
expect(layers[0].paint).toEqual({"fill-extrusion-color": "#01ffff", "fill-extrusion-opacity": 0.6});
viewModel.unregisterMapClick();
done();
});
expect(viewModel.featureFields).toBeUndefined();
const featureFieldsMap = { '3d填充面': ['type'] };
viewModel.setFeatureFieldsMap(featureFieldsMap);
expect(viewModel.highlightOptions.featureFieldsMap).toEqual(featureFieldsMap);
viewModel.map.fire('click', { target: map, point: { x: 10, y: 5 } });
});

it('map click target layer by specified featureFields', done => {
viewModel.once('mapselectionchanged', ({ features }) => {
expect(features.length).toBeGreaterThan(0);
const layers = map.getStyle().layers;
expect(layers.length).toBe(2);
expect(layers[0].id).toBe(`${mockLayerName}-${uniqueName}-SM-highlighted`);
expect(layers[1].id).toBe(`${mockLayerName}-${uniqueName}-SM-highlighted-StrokeLine`);
expect(layers[0].filter[0]).toBe('all');
expect(layers[1].filter[0]).toBe('all');
expect(layers[0].filter[0]).toBe('any');
expect(layers[1].filter[0]).toBe('any');
expect(viewModel.highlightOptions.layerIds).toEqual([mockLayerName]);
viewModel.removeHighlightLayers();
expect(map.getStyle().layers.length).toBe(0);
Expand Down Expand Up @@ -170,7 +243,7 @@ describe('LayerHighlightViewModel', () => {
expect(keyboardEvents.keyup).not.toBeUndefined();
keyboardEvents.keydown({ ctrlKey: 'Control' });
});

it('map click same feature by geometry', done => {
viewModel.setTargetLayers(['layer1']);
const keyboardEvents = {};
Expand Down

0 comments on commit 3aefe29

Please sign in to comment.