import * as L from '@mapgis/leaflet'
import MapCoordSys from './MapCoordSys'
import { getMapRotateBounds } from '../support/utils'
const echarts = window.echarts
const EchartsLayerConstuct = L.Layer.extend({
map: null, // 传入的leaflet地图
chart: null,
options: null,
echartsInitOpts: null,
canvas: null,
initialize(map, options) {
this.map = map
this.options = options
this.echartsInitOpts = options.echartsInitOpts
this.layerId = options.layerId || 'echartlayerdefaultid'
this.layerClass = options.classId || 'echartlayerdefaultclass'
this.visible = true
this.initDevicePixelRatio()
this.initOptions(this.options)
this.initEcharts()
this._resizeCanvas()
},
initDevicePixelRatio() {
this.devicePixelRatio = window.devicePixelRatio || 1
},
initOptions(options) {
if (options) {
if (options.leaflet) {
return
}
this.options.leaflet = {
roam: true
}
}
},
initEcharts() {
echarts.registerCoordinateSystem('leaflet', MapCoordSys)
echarts.extendComponentModel({
type: 'leaflet',
getBMap() {
return this.__leaflet
},
defaultOption: {
roam: false
}
})
echarts.registerAction(
{
type: 'LeafletRoma',
event: 'LeafletRoma',
update: 'updateLayout'
},
function () {}
)
},
_visible() {
this.visible = true
this.canvas.style.visibility = 'visible'
},
_unvisible() {
this.visible = false
this.canvas.style.visibility = 'hidden'
},
onAdd(map) {
const vm = this
this.map = map
this.canvas = this._createCanvas()
this.map.getPanes().overlayPane.appendChild(this.canvas)
this.chart = echarts.init(this.canvas, null, this.echartsInitOpts)
echarts.leafletMap = map
const self = this
map.on('resize', function (e) {
self.resize()
})
map.on('zoomstart', function () {
self._unvisible()
})
map.on('rotate', () => {
self.resize()
})
echarts.extendComponentView({
type: 'leaflet',
render(mapModel, ecModel, api) {
let rendering = true
if (!self._echartRenderApi) {
self._echartRenderApi = api
}
if (!self._mapModel) {
self._mapModel = mapModel
}
const leafletMap = echarts.leafletMap
const viewportRoot = api.getZr().painter.getViewportRoot()
const coordSys = mapModel.coordinateSystem
const moveHandler = function () {
if (rendering || !vm.visible) {
return
}
const topleft = leafletMap.getBounds().getNorthWest()
const offset = leafletMap.latLngToLayerPoint(topleft)
const mapOffset = [
parseInt(offset.x, 10) || 0,
parseInt(offset.y, 10) || 0
]
viewportRoot.style.left = `${mapOffset[0]}px`
viewportRoot.style.top = `${mapOffset[1]}px`
coordSys.setMapOffset(mapOffset)
mapModel.__mapOffset = mapOffset
api.dispatchAction({
type: 'LeafletRoma'
})
}
const zoomEndHandler = function () {
self._visible()
if (rendering || !vm.visible) {
return
}
api.dispatchAction({
type: 'LeafletRoma'
})
}
if (this._oldMoveHandler) {
leafletMap.off('move', this._oldMoveHandler)
}
if (this._oldZoomEndHandler) {
leafletMap.off('zoomend', this._oldZoomEndHandler)
}
leafletMap.on('move', moveHandler)
leafletMap.on('zoomend', zoomEndHandler)
this._oldMoveHandler = moveHandler
this._oldZoomEndHandler = zoomEndHandler
rendering = false
}
})
this.chart.setOption(this.options)
},
onRemove() {
this.chart.dispose()
},
_createCanvas() {
const canvas = document.createElement('div')
canvas.id = this.layerId
canvas.style.top = '0px'
canvas.style.left = '0px'
canvas.height = `${this.map.getSize().y}px`
canvas.width = `${this.map.getSize().x}px`
canvas.style.height = `${this.map.getSize().y}px`
canvas.style.width = `${this.map.getSize().x}px`
canvas.style.zIndex = 1000
canvas.setAttribute('id', this.layerId)
canvas.setAttribute('class', this.layerClass)
this.canvas = canvas
return canvas
},
_resizeCanvas() {
window.onresize = this.resize.bind(this)
},
_calcRotateBounds() {
return getMapRotateBounds(this._map)
},
/**
* 显示图层
* @function L.zondy.EchartsLayer.prototype.show
*/
show() {
this._visible()
},
/**
* 隐藏图层
* @function L.zondy.EchartsLayer.prototype.hide
*/
hide() {
this._unvisible()
},
/**
* 重置图层大小
* @function L.zondy.EchartsLayer.prototype.resize
*/
resize() {
const self = this
const size = self._calcRotateBounds().getSize()
self.canvas.style.width = `${size.x}px`
self.canvas.style.height = `${size.y}px`
self.canvas.width = size.x
self.canvas.height = size.y
self.chart.resize()
// 缓存echart api
if (self._echartRenderApi && self._mapModel && self._map._rotate) {
// 以下渲染逻辑和moveHandler一致
const api = self._echartRenderApi
const mapModel = self._mapModel
const viewportRoot = api.getZr().painter.getViewportRoot()
const coordSys = mapModel.coordinateSystem
const topleft = this.map.getBounds().getNorthWest()
const offset = this.map.latLngToLayerPoint(topleft)
const mapOffset = [
parseInt(offset.x, 10) || 0,
parseInt(offset.y, 10) || 0
]
viewportRoot.style.left = `${mapOffset[0]}px`
viewportRoot.style.top = `${mapOffset[1]}px`
coordSys.setMapOffset(mapOffset)
mapModel.__mapOffset = mapOffset
// 触发echarts图层更新
api.dispatchAction({
type: 'LeafletRoma'
})
}
},
/**
* @function L.zondy.EchartsLayer.prototype.update
* @param {*} option echarts.option
* @see https://www.echartsjs.com/zh/tutorial.html#异步数据加载和更新
* @description ECharts 由数据驱动,数据的改变驱动图表展现的改变,因此动态数据的实现也变得异常简单。所有数据的更新都通过 setOption实现,你只需要定时获取数据,setOption 填入数据,而不用考虑数据到底产生了那些变化,ECharts 会找到两组数据之间的差异然后通过合适的动画去表现数据的变化。
*/
update(option) {
this.chart.setOption(option)
},
/**
* 删除图层
* @function module:客户端可视化.EchartsLayer.prototype.remove
*/
remove() {
this.chart.clear()
if (this.canvas.parentElement) {
this.canvas.parentElement.removeChild(this.canvas)
}
this.map = undefined
return this
},
setOpacity(opacity) {
this.canvas.style.opacity = opacity
}
})
const echartsLayer = function (echartsParams, options) {
return new EchartsLayerConstuct(echartsParams, options)
}
export default echartsLayer