编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

H5开发:用D3绘制图形

wxchong 2024-06-13 03:29:57 开源技术 11 ℃ 0 评论

概述

D3基于SVG来绘制矢量图,也支持Canvas绘制标量图。提供基于DOM的操作模型,支持事件的绑定,用起来比较方便。

D3将数据集合与数据绑定做得比较优秀,提供了组件管理能力,用来实现一些图形化的拖曳式配置界面,无疑是很好的选择。

实例

简单动画

Html页面代码【./d3/demo04.html】如下:

<html>
    <head>
        <meta charset="UTF-8">
        <script src="./Js/d3.v6.min.js"></script>
        <script src="./Js/demo/demo_04.js"></script>
        
    </head>
    <body onload="makeDemo04()">
    </body>
</html>
?

Javascript脚本代码【./d3/Js/demo/demo_04.js】如下:

function makeDemo04(){
    var vs = ["From East","to West","at Home","is Best"];

    d3.select("body")
        .append("ul").selectAll("li")
        .data(vs).enter()
        .append("li").text(d => d)
        .on("click",function(){
            this.toggleState = ! this.toggleState;

            d3.select(this)
                .transition().duration(1000)
                .style("color",this.toggleState?"red":"black");
        }

        );
}

折线图

Html页面代码如下

<html>
    <head>
        <meta charset="UTF-8">
        <script src="./Js/d3.v6.min.js"></script>
        <script src="./Js/demo/demo_03.js?20201230"></script>
    </head>
    <body onload="makeDemo03()">
        <svg id="demo03" width="600" height="300" style="background-color: antiquewhite;"></svg>       
    </body>
</html>

Javascript脚本代码如下:

function makeDemo03(){
    d3.tsv("./Dat/demo02.tsv")
        .then(function(data){
            var svg = d3.select("svg");

            var pxX = svg.attr("width");
            var pxY = svg.attr("height");

            var makeScale = function (accessor,range){
                return d3.scaleLinear()
                    .domain(d3.extent(data,accessor))
                    .range(range)
                    .nice();
            }

            var scX  = makeScale(d => d.x , [0,pxX]);
            var scY1 = makeScale(d => d.y1, [pxY,0]);
            var scY2 = makeScale(d => d.y2, [pxY,0]);


            var drawData = function (g,accessor,curve) {
                // draw circle
                g.selectAll("circle").data(data).enter()
                    .append("circle")
                    .attr("r",5)
                    .attr("cx",d => scX(d.x))
                    .attr("cy", accessor);
                // draw lines
                var lnMkr = d3.line().curve(curve)
                    .x( d => scX(d.x))
                    .y( accessor);
                
                    g.append("path").attr("fill","none")
                        .attr("d",lnMkr(data));
            }

            var g1 = svg.append("g");
            var g2 = svg.append("g");

            drawData(g1, d => scY1(d.y1) ,d3.curveStep);
            drawData(g2, d => scY2(d.y2), d3.curveNatural);

            g1.selectAll("circle").attr("fill","green");
            g1.selectAll("path").attr("stroke","cyan");

            g2.selectAll("circle").attr("fill","blue");
            g2.selectAll("path").attr("stroke","red");

            var axMkr = d3.axisRight(scY1);
            axMkr(svg.append("g"));

            // draw bottom & right axis with dimon
            axMkr = d3.axisLeft(scY2);
            svg.append("g")
                .attr("transform","translate("+pxX+",0)")
                .call(axMkr);

            svg.append("g")
                .call(d3.axisTop(scX))
                .attr("transform","translate(0,"+pxY+")");

        })
}

拖曳

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>拖拽操作</title>
    <meta charset="UTF-8">
    <script src="./Js/d3.v6.min.js"></script>
    <script src="./Js/demo/drag.js?123"></script>
</head>
<body onload="makeDragDrop();">
  <svg id="dragdrop" width="600" height="200"> 
    <circle cx="100" cy="100" r="20" fill="red" />
    <circle cx="300" cy="100" r="20" fill="green" />
    <circle cx="500" cy="100" r="20" fill="blue" />
  </svg>

</body>
</html>
function makeDragDrop(){
    var widget = undefined, color = undefined;
    var preX = 0, preY = 0;
    var preCX = 0, preCY = 0;



    var drag = d3.drag()
        .on("start",function (e){
            console.log("start",this)
            color = d3.select(this).attr("fill");
            widget = d3.select(this).attr("fill","gray");

            preCX = parseInt(widget.attr("cx"));
            preCY = parseInt(widget.attr("cy"));

            var pt = d3.pointer(e);
            console.log("start",e,pt)
            preX = pt[0];
            preY = pt[1];

            console.log(preX,preY,preCX,preCY);
        })
        .on("drag",function(e){
            var pt = d3.pointer(e);
            console.log("drag",e,pt)
            widget.attr("cx",preCX + pt[0]-preX).attr("cy",preCY+pt[1]-preY);
        })
        .on("end",function(e){
            console.log("end",this)
            widget.attr("fill",color);
            widget = undefined;
        });
    
    drag(d3.select("#dragdrop").selectAll("circle"));
}


事件

基于选择集合,绑定事件处理函数,并可分发事件。获取时间发生所在坐标。主要通过on、dispatch、pointer、pointers来完成。

动画

提供了一些过渡效果,缩放以及滤镜。可参考Transitions,Zooming等API来实现。


生成器

这个比较有特点,可以将准备好的数据做成组件,然后放置到页面上。并且其自己也提供了一些内置的算法与数据,用来生成一些常用图形样式与组件。


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Symbol</title>
    <meta charset="UTF-8">
    <script src="./Js/d3.v6.min.js"></script>
    <script>
      function arrow(){
        return "M0 0 L16 0 M8 4 L16 0 L8 -4";
      }

      function makeSymbols(){
        var data = [
          {"x":40,  "y":10,   "val":"A"},
          {"x":80,  "y":30,   "val":"B"},
          {"x":120, "y":-10,  "val":"C"},
          {"x":160, "y":15,   "val":"D"},
          {"x":200, "y":0,    "val":"E"},
          {"x":240, "y":10,   "val":"F"},
          
          {"x":280,  "y":10,   "val":"G"},
          {"x":320,  "y":30,   "val":"H"},
          {"x":360, "y":-10,  "val":"I"},
          {"x":400, "y":15,   "val":"J"},
          {"x":440, "y":0,    "val":"K"},
          {"x":480, "y":10,   "val":"L"},
        ];

        var symMkr = d3.symbol().size(181).type(d3.symbolStar);

        var scY = d3.scaleLinear().domain([-10,30]).range([80,40]);

        d3.select("#symbols").append("g")
          .selectAll("patch").data(data).enter().append("path")
          .attr("d",symMkr)
          //.attr("d",arrow)
          .attr("fill","red")
          .attr("transform",d=>"translate("+d["x"]+","+scY(d["y"])+")");

        var scT = d3.scaleOrdinal(d3.symbols).domain(["A","B","C","D","E","F","G","H","I","J","K","L"]);
        
        d3.select("#symbols").append("g")
          .attr("transform","translate(000,100)")
          .selectAll("path").data(data).enter().append("path")
          .attr("d",d=>symMkr.type(scT(d["val"]))())
          .attr("fill","blue")
          .attr("stroke","green").attr("stroke-width",2)
          .attr("transform",d=>"translate("+d["x"]+","+scY(d["y"])+")");

      }
    </script>
</head>
<body onload="makeSymbols();">
  <svg id="symbols" width="600" height="200">   </svg>
</body>
</html>

比例尺

d3引入这个概念给绘图带了较大的方便,可以将x、y坐标按照设定的区间进行缩放。例如

d3.scaleLineear().domain([1,9]).range([50,250])

直线与曲线

<html>
    <head>
  <meta charset="UTF-8">
  <title>Line</title>
    <meta charset="UTF-8">
    <script src="./Js/d3.v6.min.js"></script>
    <script>

      function makeLine(){
        var data =[
          [1,1],[2,2],[3,4],[4,4],[5,2],
          [6,2],[7,3],[8,1],[9,2]
        ];

        var xSc = d3.scaleLinear().domain([1,9]).range([50,250]);
        var ySc = d3.scaleLinear().domain([0,5]).range([175,25]);

        data = data.map(d=>[  xSc(d[0]),ySc(d[1] ) ]);



        d3.select("#lines").append("g")
          .selectAll("circle").data(data).enter().append("circle")
          .attr("r",3)
          .attr("cx",d=>d[0])
          .attr("cy",d=>d[1]);

          //var lineMkr = d3.line(); 
          //var lineMkr = d3.line().defined((d,i) => i==3?false:true); 
					// 设定线型
          //var lineMkr = d3.line().curve(d3.curveLinear);
          var lineMkr = d3.line().curve(d3.curveNatural);

        d3.select("#lines").append("g").append("path")
          .attr("d",lineMkr(data))
          .attr("fill","none")
          .attr("stroke","red");
      }

    </script>
</head>
<body onload="makeLine();">
  

  <svg id="lines" width="600" height="300">
  </svg>

</body>
</html>

布局

布局可协助计算数据相关的位置数据,便于绘制图形。



var data =[
         {name:"A",votes:"30"},
         {name:"B",votes:"40"},
         {name:"C",votes:"20"},
        ];

        var pie = d3.pie().value(d=>d.votes).padAngle(0.025)(data);
        console.log(pie);


组件

<html>
    <head>
  <meta charset="UTF-8">
  <title>Com</title>
    <meta charset="UTF-8">
    <script src="./Js/d3.v6.min.js"></script>
    <script>
      function sticker(sel,label){
        sel.append("rect").attr("rx",5).attr("ry",5)
          .attr("width",70).attr("height",30)
          .attr("x",-35).attr("y",-15)
          .attr("fill","none").attr("stroke","blue")
          .classed("frame",true);

          sel.append("text").attr("x",0).attr("y",5)
          .attr("text-anchor","middle").attr("font-family","sans-serif")
          .attr("font-size",14).attr("stroke","blue")
          .classed("label",true)
          .text( label ? label: d=>d );
      }
      function makeCom(){
        var labels = ["Hello","World","How" ,"Are","You?"];

        var scX = d3.scaleLinear().domain([0,labels.length-1]).range([100,500]);
        var scY = d3.scaleLinear().domain([0,labels.length-1]).range([50,150]);

        d3.select("#com").selectAll("g").data(labels).enter().append("g")
          .attr("transform",(d,i) => "translate(" + scX(i)+","+scY(i)+")")
          .call(sticker);
        
        d3.select("#com").append("g")
          .attr("transform","translate(75,150)")
          .call(sticker,"I'am fine.")
          .selectAll(".label").attr("stroke","red");
      }
    </script>
</head>
<body onload="makeCom();">
  <svg id="com" width="600" height="500">  </svg>
</body>
</html>

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表