Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wip] feat: 客流聚合图层新增展示客流点名称文本的能力 #305

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { FlowLayer } from '../../../../src/composite-layers/flow-layer';
import { DataProvider } from '../../../../src/composite-layers/flow-layer/data';
import { FlowDataProviderState, FlowLayerOptions, FlowSource } from '../../../../src/composite-layers/flow-layer/types';
import {
DefaultScaleType,
getColorAttribute,
getSizeAttribute,
} from '../../../../src/composite-layers/flow-layer/utils';

const flowSource: FlowSource = {
data: [
Expand Down Expand Up @@ -62,9 +67,9 @@ const layerOptions: FlowLayerOptions = {
circleOpacity: 0.5,
circleStrokeWidth: 2,
circleStrokeColor: '#f00',
lineWidth: 3,
lineColor: '#00f',
lineOpacity: 0.7,
locationNameColor: '#0f0',
locationNameSize: 12,
};

describe('flow layer', () => {
Expand All @@ -83,10 +88,44 @@ describe('flow layer', () => {
expect(dataProvider.getFilterFlows(flowSource, dataProviderState).length).toBe(4);
});

it('style', () => {
it('circle style', () => {
layer.update({});
expect(layer.circleLayer?.options['style'].opacity).toBe(0.5);
expect(layer.circleLayer?.options['style'].strokeWidth).toBe(2);
expect(layer.circleLayer?.options['style'].stroke).toBe('#f00');
});

test('line style', () => {
layer.update({});
return new Promise((done) => {
requestAnimationFrame(() => {
expect(layer.lineLayer?.options['style'].opacity).toBe(0.7);
done(void 0);
});
});
});

test('unit style', () => {
expect(getSizeAttribute(10, [0, 100])).toEqual(10);
expect(getSizeAttribute({ field: 'weight', value: [0, 10] }, [0, 100])).toEqual({
field: 'weight',
value: [0, 10],
scale: {
field: 'size',
type: DefaultScaleType,
domain: [0, 100],
},
});

expect(getColorAttribute('#f00', [0, 100])).toEqual('#f00');
expect(getColorAttribute({ field: 'weight', value: ['#f00', '#0f0'] }, [0, 100])).toEqual({
field: 'weight',
value: ['#f00', '#0f0'],
scale: {
field: 'color',
type: DefaultScaleType,
domain: [0, 100],
},
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,9 @@ export const DEFAULT_OPTIONS: FlowLayerOptions = {
lineStrokeWidth: 1,
fadeOpacityEnabled: true,
fadeOpacityAmount: 0,
showLocationName: false,
locationNameSize: 12,
locationNameColor: '#fff',
locationNameStroke: '#000',
locationNameStrokeWidth: 1,
};
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,18 @@ export function transformSource(source: FlowSource): OriginData {
const locationMap: Map<string, OriginLocation> = new Map();
const flows: OriginFlow[] = [];
const { data, parser } = source;
const { type, x: xField, y: yField, x1: x1Field, y1: y1Field, weight: weightField } = parser;
const {
type,
x: xField,
y: yField,
x1: x1Field,
y1: y1Field,
weight: weightField,
name: nameField,
name1: name1Field,
} = parser;

const makeSureLocation = (lng: number, lat: number, weight: number) => {
const makeSureLocation = ({ lng, lat, weight, name }: Omit<OriginLocation, 'id'>) => {
const id = `${lng}-${lat}`;
let location = locationMap.get(id);
if (!location) {
Expand All @@ -37,6 +46,7 @@ export function transformSource(source: FlowSource): OriginData {
lng: lng,
lat: lat,
weight,
name,
};
locationMap.set(id, location);
}
Expand All @@ -50,9 +60,11 @@ export function transformSource(source: FlowSource): OriginData {
const lng2 = +get(item, x1Field, 0);
const lat2 = +get(item, y1Field, 0);
const weight = +get(item, weightField, 0);
const name1 = nameField && get(item, nameField, undefined);
const name2 = name1Field && get(item, name1Field, undefined);

const location1 = makeSureLocation(lng1, lat1, weight);
const location2 = makeSureLocation(lng2, lat2, weight);
const location1 = makeSureLocation({ lng: lng1, lat: lat1, weight, name: name1 });
const location2 = makeSureLocation({ lng: lng2, lat: lat2, weight, name: name2 });
flows.push({
id: getFlowId(),
fromId: location1.id,
Expand Down
81 changes: 78 additions & 3 deletions packages/composite-layers/src/composite-layers/flow-layer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { LineLayer } from '../../core-layers/line-layer';
import { LineLayerOptions } from '../../core-layers/line-layer/types';
import { PointLayer } from '../../core-layers/point-layer';
import { PointLayerOptions } from '../../core-layers/point-layer/types';
import { TextLayer } from '../../core-layers/text-layer';
import { TextLayerOptions } from '../../core-layers/text-layer/types';
import { CompositeLayer } from '../../core/composite-layer';
import { OriginMouseLayerEventList } from '../../core/constants';
import { ICoreLayer, Scene } from '../../types';
Expand Down Expand Up @@ -43,6 +45,10 @@ export class FlowLayer extends CompositeLayer<FlowLayerOptions> {
return this.subLayers?.getLayer('lineLayer');
}

public get locationNameLayer() {
return this.subLayers?.getLayer('locationNameLayer');
}

/**
* 获取默认配置
*/
Expand All @@ -63,12 +69,18 @@ export class FlowLayer extends CompositeLayer<FlowLayerOptions> {
source: EMPTY_LINE_LAYER_SOURCE,
});

const locationNameLayer = new TextLayer({
id: 'locationNameLayer',
name: 'locationNameLayer',
source: EMPTY_CIRCLE_LAYER_SOURCE,
});

OriginMouseLayerEventList.forEach((eventName) => {
circleLayer.on(eventName, (e) => this.emit(`circleLayer:${eventName}`, e));
lineLayer.on(eventName, (e) => this.emit(`lineLayer:${eventName}`, e));
});

return [lineLayer, circleLayer];
return [lineLayer, circleLayer, locationNameLayer];
}

public addTo(scene: Scene) {
Expand All @@ -88,6 +100,9 @@ export class FlowLayer extends CompositeLayer<FlowLayerOptions> {
protected updateSubLayers() {
this.updateClusterState();
this.circleLayer?.update(this.getCircleLayerOptions());
this.getLocationNameLayerOptions().then((options) => {
this.locationNameLayer?.update(options);
});
// 保证 lineLayer 获取到的 scale 方法是最新的
requestAnimationFrame(() => {
this.lineLayer?.update(this.getLineLayerOptions());
Expand All @@ -98,9 +113,9 @@ export class FlowLayer extends CompositeLayer<FlowLayerOptions> {
() => {
this.updateSubLayers();
},
100,
400,
{
maxWait: 500,
maxWait: 400,
}
);

Expand Down Expand Up @@ -231,4 +246,64 @@ export class FlowLayer extends CompositeLayer<FlowLayerOptions> {

return options;
}

protected async getLocationNameLayerOptions(): Promise<TextLayerOptions> {
const {
minZoom,
maxZoom,
zIndex,
visible,
blend,
pickingBuffer,
showLocationName,
getClusterLocationName,
locationNameColor: fill,
locationNameSize: fontSize,
locationNameStroke: stroke,
locationNameStrokeWidth: strokeWidth,
locationNameStrokeOpacity: strokeOpacity,
locationNameOffset: textOffset,
} = this.options;

const originSource = Object.assign(
{},
showLocationName ? this.circleLayer?.options['source'] ?? EMPTY_CIRCLE_LAYER_SOURCE : EMPTY_CIRCLE_LAYER_SOURCE
);

if (getClusterLocationName) {
originSource.data = await Promise.all(
originSource.data.map(async (location, locationIndex) => {
if (!location.name) {
try {
location.name = await getClusterLocationName(location, locationIndex);
} catch (e) {
location.name = '';
}
}
return location;
})
);
}

const options: TextLayerOptions = {
source: originSource,
field: 'name',
minZoom,
maxZoom,
zIndex,
visible,
blend,
pickingBuffer,
style: {
fill,
fontSize,
stroke,
strokeOpacity,
strokeWidth,
textOffset,
},
};

return options;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { LineLayerOptions, LineLayerStyleOptions } from '../../../core-layers/line-layer/types';
import { PointLayerOptions, PointLayerStyleOptions } from '../../../core-layers/point-layer/types';
import { TextLayerStyleOptions } from '../../../core-layers/text-layer/types';
import { CompositeLayerOptions } from '../../../core/composite-layer';

export type GetClusterName = (clusterLocation: ClusterLocation, index: number) => Promise<string> | string;

export type ClusterOptions = {
/**
* 客流点聚合类型
Expand Down Expand Up @@ -88,6 +91,11 @@ export type OriginLocation = {
* 权重
*/
weight: number;

/**
* 结点名称
*/
name?: string;
};

export type OriginFlow = {
Expand Down Expand Up @@ -161,6 +169,8 @@ export type FlowParser = {
x1: string;
y1: string;
weight: string;
name?: string;
name1?: string;
};

export type FlowSource = {
Expand Down Expand Up @@ -244,4 +254,44 @@ export interface FlowLayerOptions extends CompositeLayerOptions, Partial<Cluster
* 半透明的权重
*/
fadeOpacityAmount?: number;

/**
* 是否展示点名称
*/
showLocationName?: boolean;

/**
* 获取聚合点名称的方法
*/
getClusterLocationName?: GetClusterName;

/**
* 点名称字体大小
*/
locationNameSize?: TextLayerStyleOptions['fontSize'];

/**
* 点名称字体填充颜色
*/
locationNameColor?: TextLayerStyleOptions['fill'];

/**
* 点名称字体边框颜色
*/
locationNameStroke?: TextLayerStyleOptions['stroke'];

/**
* 点名称字体边框宽度
*/
locationNameStrokeWidth?: TextLayerStyleOptions['strokeWidth'];

/**
* 点名称字体边框透明度
*/
locationNameStrokeOpacity?: TextLayerStyleOptions['strokeOpacity'];

/**
* 点名称字体偏移
*/
locationNameOffset?: TextLayerStyleOptions['textOffset'];
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { PointLayer } from '../../../core-layers/point-layer';
import { ColorAttr, SizeAttr } from '../../../types';
import { buildIndex } from '../data/build-index';

const DefaultScaleType = ScaleTypes.LINEAR;
export const DefaultScaleType = ScaleTypes.LINEAR;

export function getSizeAttribute(sizeAttr: SizeAttr, weightRange: [number, number]): SizeAttr {
if (sizeAttr instanceof Object && !(sizeAttr instanceof Function) && !Array.isArray(sizeAttr)) {
Expand Down
Loading
Loading