From ca20d8e12f01a9fa4344555d35944aa9d231d29a Mon Sep 17 00:00:00 2001 From: lvisei Date: Wed, 23 Feb 2022 19:47:14 +0800 Subject: [PATCH] fix: legend type (#976) * chore: scale quantize demo * fix(layer): color legend scale order * chore: note for type * fix: ignore undefined cat * fix: continuous tick type --- .../core/src/services/layer/ILayerService.ts | 15 +- packages/layers/src/core/BaseLayer.ts | 66 ++-- .../layers/src/plugins/FeatureScalePlugin.ts | 1 + stories/Scale/Scale.stories.tsx | 5 +- stories/Scale/components/Quantize.tsx | 296 ++++++++++++++++++ 5 files changed, 355 insertions(+), 28 deletions(-) create mode 100644 stories/Scale/components/Quantize.tsx diff --git a/packages/core/src/services/layer/ILayerService.ts b/packages/core/src/services/layer/ILayerService.ts index 5377fa61db..185d5b55b4 100644 --- a/packages/core/src/services/layer/ILayerService.ts +++ b/packages/core/src/services/layer/ILayerService.ts @@ -92,6 +92,19 @@ export interface IActiveOption { type ILngLat = [number, number]; +// 分段图例 +export interface ILegendSegmentItem { + value: [number, number]; + [key: string]: any; +} +// 分类图例 +export interface ILegendClassificaItem { + value: number | string; + [key: string]: any; +} +// 图层图例 +export type LegendItems = ILegendSegmentItem[] | ILegendClassificaItem[]; + export interface ILayer { id: string; // 一个场景中同一类型 Layer 可能存在多个 type: string; // 代表 Layer 的类型 @@ -188,7 +201,7 @@ export interface ILayer { style(options: unknown): ILayer; hide(): ILayer; show(): ILayer; - getLegendItems(name: string): any; + getLegendItems(name: string): LegendItems; setIndex(index: number): ILayer; isVisible(): boolean; setMaxZoom(min: number): ILayer; diff --git a/packages/layers/src/core/BaseLayer.ts b/packages/layers/src/core/BaseLayer.ts index cf9bedded3..03aed17c94 100644 --- a/packages/layers/src/core/BaseLayer.ts +++ b/packages/layers/src/core/BaseLayer.ts @@ -19,6 +19,8 @@ import { ILayerModelInitializationOptions, ILayerPlugin, ILayerService, + ILegendClassificaItem, + ILegendSegmentItem, IMapService, IModel, IModelInitializationOptions, @@ -36,6 +38,7 @@ import { IStyleAttributeService, IStyleAttributeUpdateOptions, lazyInject, + LegendItems, ScaleAttributeType, ScaleTypeName, ScaleTypes, @@ -47,7 +50,7 @@ import Source from '@antv/l7-source'; import { encodePickingColor } from '@antv/l7-utils'; import { EventEmitter } from 'eventemitter3'; import { Container } from 'inversify'; -import { isFunction, isObject } from 'lodash'; +import { isFunction, isObject, isUndefined } from 'lodash'; import { normalizePasses } from '../plugins/MultiPassRendererPlugin'; import { BlendTypes } from '../utils/blend'; import { handleStyleDataMapping } from '../utils/dataMappingStyle'; @@ -895,41 +898,52 @@ export default class BaseLayer extends EventEmitter return this.styleAttributeService.getLayerAttributeScale(name); } - public getLegendItems(name: string): any { + public getLegendItems(name: string): LegendItems { const scale = this.styleAttributeService.getLayerAttributeScale(name); - if (scale) { - if (scale.ticks) { - // 连续分段类型 - const items = scale.ticks().map((item: any) => { + + // 函数自定义映射,没有 scale 返回为空数组 + if (!scale) { + return []; + } + + if (scale.invertExtent) { + // 分段类型 Quantize、Quantile、Threshold + const items: ILegendSegmentItem[] = scale.range().map((item: number) => { + return { + value: scale.invertExtent(item), + [name]: item, + }; + }); + + return items; + } else if (scale.ticks) { + // 连续类型 Continuous (Linear, Power, Log, Identity, Time) + const items: ILegendClassificaItem[] = scale + .ticks() + .map((item: string) => { return { value: item, [name]: scale(item), }; }); - return items; - } else if (scale.invertExtent) { - // 连续类型 - const items = scale.range().map((item: any) => { + + return items; + } else if (scale?.domain) { + // 枚举类型 Cat + const items: ILegendClassificaItem[] = scale + .domain() + .filter((item: string | number | undefined) => !isUndefined(item)) + .map((item: string | number) => { return { - value: scale.invertExtent(item), - [name]: item, + value: item, + [name]: scale(item) as string, }; }); - return items; - } else if (scale?.domain) { - // 枚举类型 - const items = scale.domain().map((item: string | number) => { - return { - // @ts-ignore - value: item || '无', - color: scale(item), - }; - }); - return items; - } - } else { - return []; + + return items; } + + return []; } public pick({ x, y }: { x: number; y: number }) { diff --git a/packages/layers/src/plugins/FeatureScalePlugin.ts b/packages/layers/src/plugins/FeatureScalePlugin.ts index a02785cd3e..1e91e3ddc8 100644 --- a/packages/layers/src/plugins/FeatureScalePlugin.ts +++ b/packages/layers/src/plugins/FeatureScalePlugin.ts @@ -126,6 +126,7 @@ export default class FeatureScalePlugin implements ILayerPlugin { ) { const tick = scale.scale.ticks(attributeScale.values.length); if (type === 'color') { + // TODO: 这里改变了值域,获取图例的时候有问题 scale.scale.domain(tick); } } diff --git a/stories/Scale/Scale.stories.tsx b/stories/Scale/Scale.stories.tsx index 38691fcc30..77af2c7ec7 100644 --- a/stories/Scale/Scale.stories.tsx +++ b/stories/Scale/Scale.stories.tsx @@ -1,5 +1,8 @@ import { storiesOf } from '@storybook/react'; import * as React from 'react'; +import Quantize from './components/Quantize'; import PointScale from './components/Point'; + storiesOf('数据映射', module) - .add('枚举类型', () => ) \ No newline at end of file + .add('枚举类型', () => ) + .add('颜色范围等分', () => ); diff --git a/stories/Scale/components/Quantize.tsx b/stories/Scale/components/Quantize.tsx new file mode 100644 index 0000000000..5036fd4542 --- /dev/null +++ b/stories/Scale/components/Quantize.tsx @@ -0,0 +1,296 @@ +import { PolygonLayer, Scene, Popup } from '@antv/l7'; +import { GaodeMap } from '@antv/l7-maps'; +import * as React from 'react'; + +const list = [ + { + value: 1.0, + province_adcode: '110000', + province_adName: '北京市', + province: '北京市', + }, + { + value: 2.0, + province_adcode: '120000', + province_adName: '天津市', + province: '天津市', + }, + { + value: 3.0, + province_adcode: '130000', + province_adName: '河北省', + province: '河北省', + }, + { + value: 4.0, + province_adcode: '140000', + province_adName: '山西省', + province: '山西省', + }, + { + value: 5.0, + province_adcode: '150000', + province_adName: '内蒙古自治区', + province: '内蒙古自治区', + }, + { + value: 6.0, + province_adcode: '210000', + province_adName: '辽宁省', + province: '辽宁省', + }, + { + value: 7.0, + province_adcode: '220000', + province_adName: '吉林省', + province: '吉林省', + }, + { + value: 8.0, + province_adcode: '230000', + province_adName: '黑龙江省', + province: '黑龙江省', + }, + { + value: 9.0, + province_adcode: '310000', + province_adName: '上海市', + province: '上海市', + }, + { + value: 10.0, + province_adcode: '320000', + province_adName: '江苏省', + province: '江苏省', + }, + { + value: 11.0, + province_adcode: '330000', + province_adName: '浙江省', + province: '浙江省', + }, + { + value: 12.0, + province_adcode: '340000', + province_adName: '安徽省', + province: '安徽省', + }, + { + value: 13.0, + province_adcode: '350000', + province_adName: '福建省', + province: '福建省', + }, + { + value: 14.0, + province_adcode: '360000', + province_adName: '江西省', + province: '江西省', + }, + { + value: 15.0, + province_adcode: '370000', + province_adName: '山东省', + province: '山东省', + }, + { + value: 16.0, + province_adcode: '410000', + province_adName: '河南省', + province: '河南省', + }, + { + value: 17.0, + province_adcode: '420000', + province_adName: '湖北省', + province: '湖北省', + }, + { + value: 18.0, + province_adcode: '430000', + province_adName: '湖南省', + province: '湖南省', + }, + { + value: 19.0, + province_adcode: '440000', + province_adName: '广东省', + province: '广东省', + }, + { + value: 20.0, + province_adcode: '450000', + province_adName: '广西壮族自治区', + province: '广西壮族自治区', + }, + { + value: 21.0, + province_adcode: '460000', + province_adName: '海南省', + province: '海南省', + }, + { + value: 22.0, + province_adcode: '500000', + province_adName: '重庆市', + province: '重庆市', + }, + { + value: 23.0, + province_adcode: '510000', + province_adName: '四川省', + province: '四川省', + }, + { + value: 24.0, + province_adcode: '520000', + province_adName: '贵州省', + province: '贵州省', + }, + { + value: 25.0, + province_adcode: '530000', + province_adName: '云南省', + province: '云南省', + }, + { + value: 26.0, + province_adcode: '540000', + province_adName: '西藏自治区', + province: '西藏自治区', + }, + { + value: 27.0, + province_adcode: '610000', + province_adName: '陕西省', + province: '陕西省', + }, + { + value: 28.0, + province_adcode: '630000', + province_adName: '青海省', + province: '青海省', + }, + { + value: 29.0, + province_adcode: '640000', + province_adName: '宁夏回族自治区', + province: '宁夏回族自治区', + }, + { + value: 30.0, + province_adcode: '650000', + province_adName: '新疆维吾尔自治区', + province: '新疆维吾尔自治区', + }, + { + value: 31.0, + province_adcode: '710000', + province_adName: '台湾省', + province: '台湾省', + }, + { + value: 32.0, + province_adcode: '810000', + province_adName: '香港特别行政区', + province: '香港特别行政区', + }, + { + value: 33.0, + province_adcode: '820000', + province_adName: '澳门特别行政区', + province: '澳门特别行政区', + }, +]; + +export default class Quantize extends React.Component { + private scene: Scene; + + public componentWillUnmount() { + this.scene.destroy(); + } + + public async componentDidMount() { + const scene = new Scene({ + id: 'map', + pickBufferScale: 1.0, + map: new GaodeMap({ + style: 'light', + center: [-121.24357, 37.58264], + pitch: 0, + zoom: 6.45, + }), + }); + scene.on('loaded', () => { + fetch( + 'https://gw.alipayobjects.com/os/alisis/geo-data-v0.1.1/choropleth-data/country/100000_country_province.json', + ) + .then((res) => res.json()) + .then((data) => { + const chinaPolygonLayer = new PolygonLayer({ + autoFit: true, + }) + .source(data, { + transforms: [ + { + type: 'join', + sourceField: 'province_adName', + targetField: 'name', // data 对应字段名 绑定到的地理数据 + data: list, + }, + ], + }) + .scale({ + value: { + type: 'quantize', + // nice: false, + }, + }) + .color('value', [ + '#35E0CC', + '#31C4DC', + '#44A2E4', + '#3976E2', + '#204CCF', + ]) + .shape('fill'); + + chinaPolygonLayer.on('add', (type) => { + console.log( + 'getLegendItems: ', + chinaPolygonLayer.getLegendItems('color'), + ); + }); + + chinaPolygonLayer.on('mousemove', (e) => { + const popup = new Popup({ + offsets: [0, 0], + closeButton: false, + }) + .setLnglat(e.lngLat) + .setHTML(e.feature.properties.name + e.feature.properties.value); + scene.addPopup(popup); + }); + + scene.addLayer(chinaPolygonLayer); + }); + + this.scene = scene; + }); + } + + public render() { + return ( +
+ ); + } +}