Div & Svg可視化探索筆記

最近因?yàn)楣ぷ餍枰隽它c(diǎn)HTML5可視化研究如下
為什么簡書沒有字體顏色作為一個(gè)設(shè)計(jì)師很不爽
第一次發(fā)文有寫錯(cuò)的地方還請(qǐng)諸位高手多多包涵

問題陳述

設(shè)想,要在頁面中生成大量的簡單圖形,比如10萬個(gè)方塊,并對(duì)它們進(jìn)行拖拽操作。
基本思路有三種方式,傳統(tǒng)Div,Svg,與Canvas。
為了加拖拽,暫時(shí)沒有用canvas。
因?yàn)閏anvas無法生成dom節(jié)點(diǎn),不存在id這種屬性,需要通過判斷鼠標(biāo)位置來獲取元素再進(jìn)行操作。雖然寫個(gè)isMouseinObj()的function也不是不行,但總覺得以后針對(duì)某對(duì)象單獨(dú)處理會(huì)夜長夢多(主要還是懶)。。。不過從生成圖形角度講,canvas理論上是最快的。


因?yàn)樨澤滤罁?dān)心Dom過多死機(jī),準(zhǔn)備先分區(qū)生成方塊,于是:
一個(gè)簡圖,整體劃分如下,設(shè)兩個(gè)input框的值分別為m, n,每個(gè)藍(lán)塊包括n個(gè)綠塊。點(diǎn)擊每個(gè)藍(lán)塊可在下方生成n個(gè)綠塊。
點(diǎn)擊GenAll可一次性生成m*n個(gè)綠塊。點(diǎn)擊Drag可對(duì)綠塊進(jìn)行拖拽。


js-1.png

模擬開始。

Div+Html5 Drag & Drop

首先是用div模擬方塊。因?yàn)楸容^熟悉寫起來也簡單。

  • 初始化Div
    js循環(huán)批量生成。
for(var i=0;i<n;i++) {
    var box = document.createElement("div");
    box.className = 'abox';
    var id = i+1;
    box.id = 'box'+id;
    box.innerHTML = 'Box'+id;
    $('#boxdetail').append(box);
    delete box;
}

Div的拖拽方式可以分成兩種。

  • 應(yīng)用插件拖拽
    偷懶大法,用jquery-ui的話,只需要一句話。給要拖拽的元素加上draggable()即可。
<script type="text/javascript" src="jquery-ui.js"></script>
$("#drag").click(function(){
    alert('now you can drag');
    $(".abox").draggable(); 
});
js-2.png

Jquery-ui的draggble還有很多其他參數(shù),請(qǐng)參考api文檔。

  • Html原生事件拖拽
    Html5有原生Drag and Drop事件,堪稱神器。
    被拖動(dòng)對(duì)象可以觸發(fā)的事件有:
    (1)ondragstart:源對(duì)象開始被拖動(dòng)
    (2)ondrag:源對(duì)象被拖動(dòng)過程中(鼠標(biāo)可能在移動(dòng)也可能未移動(dòng))
    (3)ondragend:源對(duì)象被拖動(dòng)結(jié)束
    拖動(dòng)源對(duì)象可以進(jìn)入到上方的目標(biāo)對(duì)象可以觸發(fā)的事件有:
    (1)ondragenter:目標(biāo)對(duì)象被源對(duì)象拖動(dòng)著進(jìn)入
    (2)ondragover:目標(biāo)對(duì)象被源對(duì)象拖動(dòng)著懸停在上方
    (3)ondragleave:源對(duì)象拖動(dòng)著離開了目標(biāo)對(duì)象
    (4)ondrop:源對(duì)象拖動(dòng)著在目標(biāo)對(duì)象上方釋放/松手
    添加事件的方式也多種多樣,以ondrop為例:
    HTML 中:<element ondrop="myScript">
    JavaScript 中:object.ondrop=function(){myScript};
    JavaScript 中, 使用 addEventListener() 方法:object.addEventListener("drop",myScript);

現(xiàn)在假定一種新情形:綠色方塊只能拖拽到虛線框之內(nèi)。


js-3

默認(rèn)情況下,Html元素均不可拖拽,所以需要設(shè)置拖拽元素的draggable屬性為true。同時(shí),默認(rèn)無法將元素放置到其他元素中,所以需要event.preventDefault()設(shè)置允許放置。
本例中,為class為abox的綠方塊添加draggable。
為class為wrap的虛線框添加preventDefault。
之后通過dataTransfer傳輸數(shù)據(jù),實(shí)現(xiàn)box的移動(dòng)。

$("#drag").click(function(){
    alert('now you can drag');
    $(".abox").attr('draggable',true); //設(shè)置可拖動(dòng)
    boxes=$(".abox")
    for(i=0;i<boxes.length;i++){ //循環(huán)使每個(gè)box均可拖動(dòng)
        boxes[i].ondragstart = function(event) {
            event.dataTransfer.setData("Text",event.target.id); //存儲(chǔ)
            console.log('drag', event.target.id)
        }
    }
    document.ondragover = function(event) {
        if(event.target.className == "awrap"){
            event.preventDefault();  //設(shè)置可放置
        }
    }
    document.ondrop = function(event) {
        if(event.target.className == "awrap"){
            event.preventDefault();
            var data=event.dataTransfer.getData("Text");
            console.log('data', data);
            event.target.appendChild(document.getElementById(data)); //放置
        }
    }
});
js-4.png

Svg

由于Svg也是直接在Html中生成Dom節(jié)點(diǎn),理論上Div所能實(shí)現(xiàn)的功能它都可以實(shí)現(xiàn),并且繪圖效果更佳。

  • 初始化Svg
    同Div的生成方式類似,Svg需要先生成個(gè)畫布,并定義長寬。
var svg = document.createElementNS('http://www.w3.org/2000/svg','svg'); 
svg.setAttribute("height",'100%'); 
svg.setAttribute("width",'100%');

然后生成Svg元素,并設(shè)置其屬性。

for (var i = 0; i < Count; i++) {
    var rect = document.createElementNS('http://www.w3.org/2000/svg','rect'); 
    rect.setAttribute( .... ); 
    svg.appendChild(rect); 
}
  • 應(yīng)用插件拖拽
    svg.draggable.js是個(gè)跟Jquery ui draggable差不多的插件。也是引入之后加個(gè)draggable屬性即可隨意拖拽。
<script type="text/javascript" src="svg.min.js"></script>
<script type="text/javascript" src="svg.draggable.js"></script>

循環(huán)生成Svg方塊并添加拖拽屬性。

var svg = SVG('boxdetail').size(1000, 400);
for (var i = 0; i < n; i++) {
    var rect = svg.rect(80, 20);
    rect.x(100 * i);
    rect.fill('#e1fbdd'); 
    rect.id('box'+i);
    rect.draggable({ //設(shè)定只能在畫布大小內(nèi)拖動(dòng)
        minX: 0, 
        minY: 0, 
        maxX: 1000, 
        maxY: 400
    });
}

但這種方式有個(gè)問題,就是——慢。當(dāng)生成僅10000個(gè)方塊時(shí),效率便低的不可估量。
然而Svg無法應(yīng)用Html5原生的Drag and Drop事件。

  • 鼠標(biāo)事件觸發(fā)拖拽
    一種基本方法,是利用鼠標(biāo)的mousedown, mousemove, mouseup事件檢測鼠標(biāo)點(diǎn)擊、移動(dòng)、松開,并記錄鼠標(biāo)坐標(biāo)位置,從而改變被拖拽元素坐標(biāo)。
$("#drag").click(function(){
    alert('now you can drag');
    var selectedElement = null;
    var currentX = 0;
    var currentY = 0;
    $("#mysvg > rect").mousedown(function (e) {
        // 選中拖拽元素,記錄原始坐標(biāo)
        currentX = e.clientX;
        currentY = e.clientY;
        selectedElement = e.target;
    }).mousemove(function (e) {    
        // 更新坐標(biāo)
        if (selectedElement) {
            var dx = parseInt(selectedElement.getAttribute("x")) + e.clientX - currentX;
            var dy = parseInt(selectedElement.getAttribute("y")) + e.clientY - currentY;
            currentX = e.clientX;
            currentY = e.clientY;
            selectedElement.setAttribute("x", dx);
            selectedElement.setAttribute("y", dy);
        }
    }).mouseup(function (e) {
        // 取消元素選中狀態(tài)
        selectedElement = null;  
    });
});

相比于引用插件,這樣的效率提高了不少。


js-5.png

Div與Svg效率對(duì)比

從結(jié)果上看,在數(shù)量少時(shí),針對(duì)方塊這種簡單圖形的簡單操作Div和Svg均可勝任。然而設(shè)置了總共生成100000個(gè)方塊,發(fā)現(xiàn)單從生成的角度,Svg的渲染用時(shí)大約是Div的1/2(這里指Dom中直接繪制Svg而非通過js插件繪制Svg)。
加上拖拽功能后,用Html5原生拖放事件的Div,及用鼠標(biāo)事件的Svg,明顯快快快快于應(yīng)用js插件拖放的效率。于是乎插件雖然強(qiáng)大但對(duì)于大量節(jié)點(diǎn)的處理實(shí)在過于緩慢。
于是在圖形化上還是應(yīng)用Svg更舒暢一些。
但有一個(gè)尚未解決的問題。
應(yīng)用鼠標(biāo)事件拖動(dòng)Svg,當(dāng)鼠標(biāo)移動(dòng)過快時(shí),mousemove事件無法觸發(fā),導(dǎo)致移動(dòng)效果不能實(shí)現(xiàn)。粗略查了下似乎可以添加透明背景層接收所有觸發(fā)事件,不過還沒有深入研究。
這篇就到此吧。等解決了mousemove的bug再更新后續(xù)。
(′?ω?`)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift版本點(diǎn)擊這里歡迎加入QQ群交流: 594119878最新更新日期:18-09-17 About A cu...
    ylgwhyh閱讀 26,139評(píng)論 7 249
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,379評(píng)論 4 61
  • 我有一個(gè)夢 讀書屋檐下 桃花與葡萄架 看,星星眨眼 ...
    Jay_Ray閱讀 420評(píng)論 6 6
  • 【一悟】小米智能路由器 定位:高性價(jià)比的家庭智能路由器,不僅僅局限于路由功能,還要成為家庭數(shù)據(jù)中心和智能家居控制中...
    毛嘎子閱讀 431評(píng)論 0 1

友情鏈接更多精彩內(nèi)容