前陣子有介紹到如何使用Cytoscape.js來畫網路拓譜圖,限量使用Cytoscape.js與SignalR做出一個即時監控機器狀態的網頁,為了符合一些特殊需求,限量修改Cytoscape.js的Code,讓它可以支援在Canvas節點上掛上HTML DOM元件,在拖拉時HTML DOM元件會跟著節點動。此功能在Chrome是OK的,但是在IE9上因為Browser Threading的問題,所以導致SignalR在一直更新HTML DOM元件內容時會Lock頁面,導致無法對Cytoscape.js的節點進行動作。後來想一想只能想辦法將HTML DOM元件和Cytoscape.js節點一起畫入Canvas內。後來查一查資料就發現此法是可行的,以下就來說明如何將HTML DOM元件畫入Canvas上。
Canvas是HTML5支援的新的元件,主要是用來在Web Page上畫圖。只提供畫圖形, 文字, 與圖片,圖片的話需要將圖片轉換成Stream的方式在畫上去,其他圖形就像是使用小畫家一樣,用點與線繪出來,所以Canvas是不支援直接畫HTML DOM元件的。這時候就要繞個道,先使用SVG把HTML DOM轉成圖片,再用Canvas畫上去。
SVG(Scalable Vector Graphics)定義了許多XML-based的圖形基本圖形定義檔,例如:<circle>圓形, <rec>長方形, <line>線, <polygon>不規則形...等,有了SVG,Canvas在畫個圖時就不用再那麼麻煩(因為Canvas沒有定義基本圖形檔,所以畫個基本圖形都需要定義許多東西,例如:角度, 長, 寬...等),而且SVG裡面可以放HTML DOM元件。
接下來就來看看將HTML DOM畫至Canvas上的步驟,大致上就是先將HTML DOM放置在SVG裡,然後再將SVG轉成Image物件暫存在Web上,接著指定Image onload事件,讓Image load時將此Image畫到Canvas上。詳細範例程式碼如下:
執行結果:
從執行後你可以點點看裡面的Button,是不是連點都不能點,因為變成了圖當然不能點。再來把此解法應用到Cytoscape.js就可以解決了(還是需要去改Cytoscape.js底層Code),真是皆大歡喜。
...
你以為這樣就Happy Ending了嗎?
在IE9上並沒有,因為該死的IE9沒有支援BLOB,要到IE10才有支援。所以限量又遇到了另一個問題,至於如何解決就又是另一段故事了。
參考來源:
MDN - Drawing DOM objects into a canvas
W3CSchool - SVG Tutorial
MDN - SVG
Canvas是HTML5支援的新的元件,主要是用來在Web Page上畫圖。只提供畫圖形, 文字, 與圖片,圖片的話需要將圖片轉換成Stream的方式在畫上去,其他圖形就像是使用小畫家一樣,用點與線繪出來,所以Canvas是不支援直接畫HTML DOM元件的。這時候就要繞個道,先使用SVG把HTML DOM轉成圖片,再用Canvas畫上去。
SVG(Scalable Vector Graphics)定義了許多XML-based的圖形基本圖形定義檔,例如:<circle>圓形, <rec>長方形, <line>線, <polygon>不規則形...等,有了SVG,Canvas在畫個圖時就不用再那麼麻煩(因為Canvas沒有定義基本圖形檔,所以畫個基本圖形都需要定義許多東西,例如:角度, 長, 寬...等),而且SVG裡面可以放HTML DOM元件。
接下來就來看看將HTML DOM畫至Canvas上的步驟,大致上就是先將HTML DOM放置在SVG裡,然後再將SVG轉成Image物件暫存在Web上,接著指定Image onload事件,讓Image load時將此Image畫到Canvas上。詳細範例程式碼如下:
<!DOCTYPE html> <html> <head> <title>SVGTest</title> <script type="text/javascript"> // 在頁面載入後進行事件綁定處理 window.onload = function() { var myCanvas = document.getElementById('myCanvas'); var ctx = myCanvas.getContext('2d'); // 將HTML DOM放置在SVG裡 var data = '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">\ <foreignObject width="100%" height="100%" >\ <div xmlns="http://www.w3.org/1999/xhtml" style="font-size: 20px">\ <b>TEST</b>\ <input type="text" placeholder="input value" />\ <input type="button" value="Send" />\ </div>\ </foreignObject>\ </svg>'; // 取得window.URL物件以用來後續呼叫其方法 var DOMURL = window.URL || window.webkitURL || window; var img = new Image(); // 將SVG圖傳成BLOB型態暫存,並指定MIME type為image/svg+xml var svg = new Blob([data], {type: 'image/svg+xml;charset=utf-8'}); // 產生暫存圖的object url(因為HTML中img需要指定src的url位置) var url = DOMURL.createObjectURL(svg); img.onload = function () { // 將暫存的SVG圖畫至Canvas上,並指定位置 ctx.drawImage(img, 100, 50); // 釋放掉DOMURL資源 DOMURL.revokeObjectURL(url); } img.src = url; } </script> </head> <body> <div id="main"> <canvas id="myCanvas" style="width:700; height: 500; border:1px solid black"> </canvas> </div> </body> </html>
執行結果:
從執行後你可以點點看裡面的Button,是不是連點都不能點,因為變成了圖當然不能點。再來把此解法應用到Cytoscape.js就可以解決了(還是需要去改Cytoscape.js底層Code),真是皆大歡喜。
...
你以為這樣就Happy Ending了嗎?
在IE9上並沒有,因為該死的IE9沒有支援BLOB,要到IE10才有支援。所以限量又遇到了另一個問題,至於如何解決就又是另一段故事了。
參考來源:
MDN - Drawing DOM objects into a canvas
W3CSchool - SVG Tutorial
MDN - SVG
留言
張貼留言