日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

在Leaflet地图上集成Echarts

發布時間:2025/3/21 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 在Leaflet地图上集成Echarts 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

需求背景:

現在我要在地圖上加上Echarts的散點圖還有線集,看起來就很牛B的那種。上效果圖:

需求分析:

我先看了看Echarts官網上有提供加載地圖的例子,主要包括三種方式:

? ? ? ? 1.加載js格式的地圖文件;

? ? ? ? 2.加載json格式的地圖文件;

? ? ? ? 3.通過配置項bmap,就是百度地圖;? 參考地址:https://blog.csdn.net/wml00000/article/details/84566180

上面的我是用不了的,我用的是Leaflet地圖框架,找了找已經有人實現了擴展(Echarts-Leaflet擴展地址在這:https://github.com/gnijuohz/echarts-leaflet),他是模仿著Echarts里面的bmap擴展了一個配置項leaflet,給我的感覺是在Echarts上集成了Leaflet,當然用是沒有問題的,就是覺得有點別扭,我想要的是Leaflet上集成Echarts,是以Leaflet為主,所以就放棄了這種方式。個人來講,如果不是項目原因,還是比較推薦他的擴展的。

另外,還找到一個插件leaflet-echarts3(https://github.com/wandergis/leaflet-echarts3),這個是基于Leaflet進行擴展的,但是作者沒有公布源代碼,只有一個壓縮后的js文件,里面同時包含了leaflet源碼、Echarts源碼以及擴展代碼,這樣我想進行版本升級都不行。所以我就悄悄地把他里面的核心代碼抽了出來。

具體操作:

? ? ? ?1.下載最新Echarts源代碼,http://echarts.baidu.com/download.html? 下最大的那個2.86MB;

? ? ? ?2.通過 _theme進行定位,定位到function Echarts(){ }里面的??this._theme = theme$$1;? ?4.2.0版本大概在第26582行,添加一行代碼:? ?this._geo = Geo;?

? ? ? 3.對Leaflet? Layer 類進行擴展,新建js文件 leaflet-echarts.js,? 加入下面代碼:

L.OverlayEcharts = (L.version < "1.0" ? L.Class : L.Layer).extend({includes: L.version < "1.0" ? L.Mixin.Events : [],_echartsContainer: null,_map: null,_echart: null,_echartsOption: null,initialize: function(echartsOption) {this._echartsOption = echartsOption;},onAdd: function(map) {this._map = map;this._initEchartsContainer();map.on("moveend", this._redraw, this);//當地圖中心改變后觸發this._redraw();},onRemove: function(map) {this._echartsContainer && map.getPanes().overlayPane.removeChild(this._echartsContainer);this._echart.dispose();map.off("moveend", this._redraw, this);},// addTo: function(map) {// console.log(this);// return map.addLayer(this),// this// },_initEchartsContainer: function() {var size = this._map.getSize(),echartsContainer = document.createElement("div");console.log("=====>mapsize"+size);echartsContainer.style.position = "absolute";echartsContainer.style.height = size.y + "px";echartsContainer.style.width = size.x + "px";echartsContainer.style.zIndex = 999;this._echartsContainer = echartsContainer;this._map.getPanes().overlayPane.appendChild(this._echartsContainer);//在map容器的overlayPane上疊加Echarts容器},_resetCanvasPosition: function() {var bound = this._map.getBounds(),origin = this._map.latLngToLayerPoint(bound.getNorthWest());console.log(origin);//最開始為[0,0],縮放不會改變,平移會改變\L.DomUtil.setPosition(this._echartsContainer, origin);//設置Echarts容器的位置,以便與當前地圖匹配},_redraw: function() {return this._resetCanvasPosition(),this._echartsContainer.innerHTML = "",this.initECharts(),this.setOption(this._echartsOption),this},clear: function() {this._echartsContainer.innerHTML = "",this.echartsOption = {}},redraw: function() {console.log("=======>redraw");this._redraw();},initECharts: function(){if(this._echart === null || this._echart === undefined){this._initECharts();}else {this._echart.dispose();this._initECharts();}},_initECharts: function() {if (this._echart = echarts.init(this._echartsContainer),"3.0" <= echarts.version) {var me = this;console.log(echarts.version);console.log(me._echart);me._echart._geo.prototype.dataToPoint = function(lnglat) {//重寫Echarts內部方法,Ecahrts內部有一套將經緯度轉為像素坐標的方法,這里要換成與Leaflet相匹配的var latlng = new L.latLng(lnglat[1],lnglat[0]), pixel = me._map.latLngToContainerPoint(latlng);return [pixel.x, pixel.y]; //給定地理坐標,返回相對于地圖container容器的相應像素坐標。}}this._unbindEvent();//屏蔽Echarts相關事件},setOption: function(echartsOption) {if (echartsOption.series) {//var series = echartsOption.series || {};this._echart.setOption(echartsOption);}},_unbindEvent: function() {echarts.version < "3.0" ? (this._echart.getZrender().un("dragstart", function() {}),this._echart.getZrender().un("dragend", function() {}),this._echart.getZrender().un("mouseup", function() {}),this._echart.getZrender().un("mousedown", function() {}),this._echart.getZrender().un("mousewheel", function() {})) : (this._echart.getZr().off("dragstart", function() {}),this._echart.getZr().off("dragend", function() {}),this._echart.getZr().off("mouseup", function() {}),this._echart.getZr().off("mousedown", function() {}),this._echart.getZr().off("mousewheel", function() {}))} }),L.overlayEcharts = function(options) {return new L.OverlayEcharts(options) }

? ? ?4. 新建html頁面,代碼太多,就不全放了,源文件下載地址:https://download.csdn.net/download/wml00000/10837134

<script src="lib/leaflet/leaflet.js"></script> <script src="lib/echarts.js"></script> <script src="lib/leaflet/leaflet-echarts.js"></script><div id="map"></div> <script>var map = L.map('map'); L.tileLayer('http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}').addTo(map);map.setView(L.latLng(37.550339, 104.114129), 4); //設置縮放級別及中心點//Echarts相關options配置var option = {};//將Echarts加到地圖上,可以簡單理解為在地圖上添加了Echarts圖層L.overlayEcharts(option).addTo(map);

詳細解讀:

如果只是照著流程來一遍,我認為是沒有靈魂的。說一說到底是如何把Echarts集成進去的。要想深入了解,需要知道Leaflet底層的一些東西,以下內容均為個人理解,請選擇性閱讀。

? ? ? ?這是最開始加載Leaflet地圖的一個DOM結構,我們只是創建了一個id為map的DIV,但是Leaflet內部在我們的DIV里面又創建了眾多div,分為兩部分:map-pane和control-container。主要看map-pane,在這個map-pane里面有tile-pane、overlay-pane等,通過這大概能看出Leaflet是通過DIV的設置實現圖層、marker、覆蓋物等之間的疊加,那么他又是如何根據地理坐標確定在屏幕上的位置關系的?

? ? ? ?可以先參考一下Leaflet的介紹:https://leafletjs.com/examples/extending/extending-2-layers.html??

核心內容:

  • The?L.Map?container has “map panes”, which are?<div>s.
  • L.Layers are HTML elements inside a map pane
  • The map transforms all?LatLngs to coordinates in the map’s CRS, and from that into absolute “pixel coordinates” (the origin of the CRS is the same as the origin of the pixel coordinates)
  • When the?L.Map?is ready (has a center?LatLng?and a zoom level), the absolute pixel coordinates of the top-left corner become the “pixel origin”
  • Each?L.Layer?is offset from its map pane according to the pixel origin and the absolute pixel coordinates of the layer’s?LatLngs
  • The pixel origin is reset after each?zoomend?or?viewreset?event on the?L.Map, and every?L.Layer?has to recalculate its position (if needed)
  • The pixel origin is?not?reset when panning the map around; instead, the whole panes are repositioned.

翻譯一下:

  • 地圖容器里面有個map-pane,里面有很多的div
  • 圖層其實就是map-pane里面的html 元素
  • 地圖把經緯度轉換成投影坐標系統下的坐標,再轉成絕對像素坐標(投影坐標系統原點與像素坐標系原點重合)
  • 當地圖就緒時(中心點以及縮放級別都已經確定了),左上角的絕對像素坐標就是所謂的像素原點(注意這里加了引號,他的像素坐標不一定是0,0)
  • 每個圖層會根據像素原點以及圖層上的經緯度坐標轉換過來的絕對像素坐標在map-pane上進行偏移
  • 每次縮放或視圖重置坐標原點也會重置(可以簡單理解為地圖的重新加載,就是第4條),各個圖層也得重新計算位置(因為一縮放,雖然地理坐標不變,實際上不同縮放級別地理坐標對應的像素坐標是不一樣的)
  • 當地圖平移時像素原點不會重置(實際上當地圖平移時,map-pane這個div樣式中的transform變了,也就是說map-pane的左上角這個像素原點也走了,但是他的像素坐標不變,注意坐標不一定是0,0),這個map-pane上面的其他div也就跟著動了

對照著這個例子https://leafletjs.com/examples/extending/pixelorigin.html?應該能看個差不多。

再插兩句:上面說到的絕對像素坐標是針對地圖切片談的,并不是針對設備坐標。每張地圖切片的大小是256*256,當縮放級別為0時,就是用一張圖片表示全球,絕對像素坐標原點(0,0)值位于圖片左上角,換算成經緯度大約是(-180,85).另外一點,網絡地圖大都采用網絡墨卡托投影,他并不是指投影坐標系,只是一種映射關系,是把球面地理坐標轉為平面坐標的一個過程。附個地址:https://blog.csdn.net/wml00000/article/details/85014021

Echarts的散點圖其實也是在一個Div上畫的,只要把這個div給拿到map-pane里面的overlay-pane里面不就完事了。關于點的位置,因為Echarts內部自己有個把地理坐標轉為像素坐標的方法,咱不能用他的,想辦法給他重寫了,用Leaflet 的latLngToContainerPoint( )代替。

關于Echarts的DIV容器怎么搞,有幾點:

? 1.大小需要與map container匹配

? 2.每次平移,縮放,要重新加載Echarts(可以根據leaflet的moveend監聽)

? 3.重寫Echarts內部方法 dataToPoint

寫的有點亂了

今天突然發現超圖 supermap iclient? 9d for Leaflet有Echarts的例子,可以看看:http://iclient.supermap.io/examples/leaflet/examples.html#viz-ECharts

總結

以上是生活随笔為你收集整理的在Leaflet地图上集成Echarts的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。