highchart圖表的一個常見問題是不能複製文字 比如官網的某個圖表例子,文字不能選擇,也無法複製,有時產品會抓狂... 本文給出一個簡單的方案,包括一些解決的思路,希望能幫助到有需要的人 初期想了蠻久也搜了蠻多,沒搜到,找到的結論是圖表使用的是svg實現,必然無法選擇文字,似乎是個死問題,已經瀕 ...
highchart圖表的一個常見問題是不能複製文字
比如官網的某個圖表例子,文字不能選擇,也無法複製,有時產品會抓狂...
本文給出一個簡單的方案,包括一些解決的思路,希望能幫助到有需要的人
初期想了蠻久也搜了蠻多,沒搜到,找到的結論是圖表使用的是svg實現,必然無法選擇文字,似乎是個死問題,已經瀕臨放棄
不過後來又看到一篇討論,其實svg裡面的文字是可以選擇複製的
頓時信心又來了,展開了新一輪思考
思考一:可能是姿勢不對
試試把標題配成 useHTML: true ,使用普通元素渲染,結果還是無法選
看看DOM結構,實際上已經和svg無關了
思考二:會不會是設置了某些樣式呢
跟選擇複製有關的也就這倆了,直接賦上去,還是無效
思考三:會不會是有事件影響,取消了點擊選擇效果呢
為了測試的簡便與純粹性,最好直接使用官方提供的簡單例子
查看元素對應的事件列表,有幾個需要關註
選擇highchart.js ,跳的不准呀,代碼混淆之後貌似chrome的跳轉一致都不太可靠了
思考四:什麼js東西使得點擊選擇無效呢
可能是事件禁止了冒泡 stopPropagation,或者是取消了元素的事件預設處理機制 preventDefault
一搜,發現前者沒找到,而後者有多處
定位到一個 mouseDown事件觸發的位置,柳暗花明的感覺
試了一下可以發現,上下兩處是關鍵點,直接造成文字選擇功能失效了(當然這可能是作者的本意)
接下來就是驗證環節,把這文件下下來本地,改好後(註釋那倆地方)用Fiddler的文件映射功能,替換這個例子中的 highchart.js,妥妥的可以進行選擇複製
思考五:如何運用在業務代碼中?
在vue中使用的是npm的包管理,所以肯定不能直接改源代碼,可選的一個方案是覆蓋源代碼,即覆蓋這兩個方法
import Highcharts from "highcharts"; // 重寫Highcharts事件處理,使得內容可選擇複製 Highcharts.Pointer.prototype.onContainerMouseDown = function(a) { a = this.normalize(a); 2 !== a.button && (this.zoomOption(a), // a.preventDefault && a.preventDefault(), this.dragStart(a)) }; Highcharts.Pointer.prototype.onContainerMouseMove = function(b) { // 整理變數 let a = Highcharts; let B = Highcharts.charts; let q = function(a) { return "undefined" !== typeof a && null !== a }; var c = this.chart; q(a.hoverChartIndex) && B[a.hoverChartIndex] && B[a.hoverChartIndex].mouseIsDown || (a.hoverChartIndex = c.index); b = this.normalize(b); // b.preventDefault || (b.returnValue = !1); "mousedown" === c.mouseIsDown && this.drag(b); !this.inClass(b.target, "highcharts-tracker") && !c.isInsidePlot(b.chartX - c.plotLeft, b.chartY - c.plotTop) || c.openMenu || this.runPointActions(b) };
找到對象是誰,這一步可以斷點調試看this,或往上翻代碼,其實是個Pointer.
通過分析可知,這個對象的Highcharts對象的一個子對象,我們也需要通過簡單的判斷來進行確認好
需要註意的是,代碼中有一段用到了其他變數 q B a,所以在業務代碼中覆蓋的時候,我們需要另外提前賦值
q(a.hoverChartIndex) && B[a.hoverChartIndex] && B[a.hoverChartIndex].mouseIsDown || (a.hoverChartIndex = c.index);
通過一系列分析和斷點查詢,以及確認值的一致,就能保證能覆蓋地正確
思考六:在vue中為何沒有生效
然鵝並不是順利的,在實際場景vue-highcharts中使用竟然沒啥變化,一輪調試下來也沒有走斷點,
無可奈何只好去看下它的實現,看有沒有什麼突破口
源碼很少,就是一層包裝
但這裡可以發現,如果沒有傳入highcharts,就會另外引入npm包來使用
所以很大可能是沒傳入這個屬性,致使覆蓋的Pointer並不是真正的圖表Pointer
仔細檢查代碼,才發現前人留個個坑,把大寫的屬性改成小寫之後,即可匹配上
當然,這個覆蓋的方式是挺暴力的,可以根據需求加些判斷處理,不過在現有業務中,不失為一個好辦法