refactor(图表): 地图自定义区域支持轮播

This commit is contained in:
wisonic 2024-11-28 18:52:51 +08:00
parent 341cb62097
commit 71f315d30e
4 changed files with 130 additions and 42 deletions

View File

@ -14,4 +14,5 @@ interface CustomGeoArea {
type CustomGeoSubArea = CustomGeoArea & {
geoAreaId: string
scope: string
scopeArr?: string[]
}

View File

@ -63,15 +63,48 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
chart.container = container
let geoJson = {} as FeatureCollection
let customSubArea: CustomGeoSubArea[] = []
if (areaId.startsWith('custom_') || scope) {
let data = chart.data?.data
if (areaId.startsWith('custom_')) {
customSubArea = (await getCustomGeoArea(areaId)).data || []
customSubArea.forEach(a => (a.scopeArr = a.scope?.split(',') || []))
geoJson = cloneDeep(await getGeoJsonFile('156'))
if (scope) {
geoJson.features = geoJson.features.filter(f => scope.includes('156' + f.properties.adcode))
}
const areaNameMap = geoJson.features.reduce((p, n) => {
p['156' + n.properties.adcode] = n.properties.name
return p
}, {})
const { areaMapping } = parseJson(chart.senior)
const areaMap = customSubArea.reduce((p, n) => {
const mappedName = areaMapping?.[areaId]?.[n.name]
if (mappedName) {
n.name = mappedName
}
p[n.name] = n
n.scopeArr = n.scope?.split(',') || []
return p
}, {})
const fakeData = []
data?.forEach(d => {
const area = areaMap[d.name]
if (area) {
area.scopeArr.forEach(adcode => {
fakeData.push({
...d,
name: areaNameMap[adcode],
field: areaNameMap[adcode],
scope: area.scopeArr,
areaName: d.name
})
})
}
})
data = fakeData
} else {
geoJson = cloneDeep(await getGeoJsonFile(areaId))
if (scope) {
geoJson = cloneDeep(await getGeoJsonFile('156'))
geoJson.features = geoJson.features.filter(f => scope.includes('156' + f.properties.adcode))
} else {
geoJson = cloneDeep(await getGeoJsonFile(areaId))
}
}
let options: ChoroplethOptions = {
preserveDrawingBuffer: true,
@ -83,7 +116,7 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
type: 'geojson'
},
source: {
data: chart.data?.data || [],
data: data || [],
joinBy: {
sourceField: 'name',
geoField: 'name',
@ -164,7 +197,7 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
})
dotLayer.once('loaded', () => {
chart.container = container
configCarouselTooltip(chart, view, chart.data?.data || [], null)
configCarouselTooltip(chart, view, data || [], null, customSubArea, drawOption)
})
})
return view
@ -239,6 +272,8 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
features: areaJsonArr
}
const center = centroid(areaJson)
// 轮播用
area.centroid = [center.geometry.coordinates[0], center.geometry.coordinates[1]]
dotData.push({
name: area.name,
size: d.value,

View File

@ -235,7 +235,7 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
})
})
chart.container = container
configCarouselTooltip(chart, view, data, null)
configCarouselTooltip(chart, view, data, null, customSubArea, drawOption)
})
return view
}
@ -455,31 +455,38 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
const customAttr = parseJson(chart.customAttr)
const { label } = customAttr
const data = chart.data.data
const areaMap = data.reduce((obj, value) => {
const areaMap = data?.reduce((obj, value) => {
obj[value['field']] = value
return obj
}, {})
const geoJsonMap = geoJson.features.reduce((p, n) => {
if (n.properties['adcode']) {
p['156' + n.properties['adcode']] = n
}
return p
}, {})
customSubArea.forEach(area => {
const areaJsonArr = []
area.scopeArr?.forEach(adcode => {
const json = geoJsonMap[adcode]
json && areaJsonArr.push(json)
})
if (areaJsonArr.length) {
const areaJson: FeatureCollection = {
type: 'FeatureCollection',
features: areaJsonArr
}
const center = centroid(areaJson)
// 轮播用
area.centroid = [center.geometry.coordinates[0], center.geometry.coordinates[1]]
}
})
//处理label
options.label = false
if (label.show) {
const geoJsonMap = geoJson.features.reduce((p, n) => {
if (n.properties['adcode']) {
p['156' + n.properties['adcode']] = n
}
return p
}, {})
const labelLocation = []
customSubArea.forEach(area => {
const areaJsonArr = []
area.scopeArr?.forEach(adcode => {
const json = geoJsonMap[adcode]
json && areaJsonArr.push(json)
})
if (areaJsonArr.length) {
const areaJson: FeatureCollection = {
type: 'FeatureCollection',
features: areaJsonArr
}
if (area.centroid) {
const content = []
if (label.showDimension) {
content.push(area.name)
@ -488,11 +495,10 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
areaMap[area.name] &&
content.push(valueFormatter(areaMap[area.name].value, label.quotaLabelFormatter))
}
const center = centroid(areaJson)
labelLocation.push({
name: content.join('\n\n'),
x: center.geometry.coordinates[0],
y: center.geometry.coordinates[1]
x: area.centroid[0],
y: area.centroid[1]
})
}
})

View File

@ -6,13 +6,17 @@ import { parseJson } from '@/views/chart/components/js/util'
import { Scene } from '@antv/l7-scene'
import { deepCopy } from '@/utils/utils'
export const configCarouselTooltip = (chart, view, data, scene) => {
export const configCarouselTooltip = (chart, view, data, scene, customSubArea, drawOption?) => {
if (['bubble-map', 'map'].includes(chart.type)) {
data = view.source.data.dataArray
?.filter(i => i.dimensionList?.length > 0)
.reduce((acc, current) => {
const existingItem = acc.find(obj => {
return obj.name === current.name || (obj.adcode && obj.adcode === current.adcode)
if (drawOption?.areaId?.startsWith('custom_')) {
return obj.areaName === current.areaName
} else {
return obj.name === current.name || (obj.adcode && obj.adcode === current.adcode)
}
})
if (!existingItem) {
acc.push(current)
@ -22,9 +26,9 @@ export const configCarouselTooltip = (chart, view, data, scene) => {
}
if (carouselManagerInstances[chart.container]) {
const instances = carouselManagerInstances[chart.container]
instances.update(scene, chart, view, data)
instances.update(scene, chart, view, data, customSubArea, drawOption)
} else {
new CarouselManager(scene, chart, view, data)
new CarouselManager(scene, chart, view, data, customSubArea, drawOption)
}
}
export const carouselManagerInstances: { [key: string]: CarouselManager } = {}
@ -81,18 +85,30 @@ export class CarouselManager {
*/
private popup: Popup
/**
* 自定义区域列表
* @private
*/
private customSubArea: CustomGeoSubArea[]
/**
* 渲染参数
* @private
*/
private drawOption: L7PlotDrawOptions
// 保存事件监听函数的引用
private onMouseEnterHandler: () => void
private onMouseLeaveHandler: () => void
private onVisibilityChangeHandler: () => void
constructor(scene, chart, view, data: any[]) {
constructor(scene, chart, view, data: any[], customSubArea, drawOption?) {
// 绑定事件处理函数
this.onMouseEnterHandler = this.pauseCarouselPopups.bind(this)
this.onMouseLeaveHandler = this.resumeCarouselPopups.bind(this)
this.onVisibilityChangeHandler = this.handleVisibilityChange.bind(this)
this.clearExistingTimers = this.clearExistingTimers.bind(this)
this.init(scene, chart, view, data)
this.init(scene, chart, view, data, customSubArea, drawOption)
}
/**
@ -101,9 +117,10 @@ export class CarouselManager {
* @param chart
* @param view
* @param data
* @param customSubArea
*/
public update(scene, chart, view, data: any[]) {
this.init(scene, chart, view, data)
public update(scene, chart, view, data: any[], customSubArea, drawOption?) {
this.init(scene, chart, view, data, customSubArea, drawOption)
}
/**
@ -114,13 +131,15 @@ export class CarouselManager {
* @param data
* @private
*/
private init(scene, chart, view, data: any[]) {
private init(scene, chart, view, data: any[], customSubArea, drawOption?) {
this.view = view
this.chart = chart
this.scene = scene
this.data = data
this.popup = null
this.currentIndex = 0
this.customSubArea = customSubArea
this.drawOption = drawOption
this.clearPreviousInstance(this.chart.container)
if (
this.chart.customAttr?.tooltip?.show &&
@ -336,6 +355,23 @@ export class CarouselManager {
}
private getActiveData(index): any {
if (this.drawOption?.areaId?.startsWith('custom_')) {
const result = {
type: 'FeatureCollection',
features: []
}
const area = this.customSubArea.find(a => a.name === this.data[index].areaName)
const areaMap = this.view.currentDistrictData.features.reduce((p, n) => {
p['156' + n.properties.adcode] = n
return p
}, {})
area?.scopeArr?.forEach(s => {
if (areaMap[s]) {
result.features.push(areaMap[s])
}
})
return result
}
return {
type: 'FeatureCollection',
features: [
@ -352,11 +388,21 @@ export class CarouselManager {
* @private
*/
private getPopupData(index: number): any {
return {
data: this.data[index],
centroid: this.view.currentDistrictData.features.find(
i => i.properties.name === this.data[index].name
)?.properties.centroid
if (this.drawOption?.areaId?.startsWith('custom_')) {
const data = this.data[index]
const area = this.customSubArea?.find(a => a.name === data.areaName)
data.name = data.areaName
return {
data,
centroid: area.centroid
}
} else {
return {
data: this.data[index],
centroid: this.view.currentDistrictData.features.find(
i => i.properties.name === this.data[index].name
)?.properties.centroid
}
}
}