11、D3之基础用法、综合用法、数据平放(有无比例尺)、数据立放(有无比例尺)、饼图、svg子标签、svg背景图片解析

173 阅读2分钟
定义域:domain
值域:range
一、基础用法(绑定文字)
<html> 
    <head> 
        <meta charset="utf-8"> 
        <title>Hello World</title> 
        <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> 
    </head>
    <body>
        <p></p>
        <p></p>
        <p></p>
    </body> 
</html>
<script>  
    var dataset = ["sun","moon","you"];
    var body = d3.select("body");
    var p = body.selectAll("p");
    p.data(dataset).text(function(d, i){
        return "I love " + d;
  });
  console.log(d3.range(5)); 
</script> 

二、综合用法(柱形图,含选择集、数据绑定、比例尺、坐标轴)
<html> 
    <head> 
        <meta charset="utf-8"> 
        <title>Hello World</title> 
        <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> 
        <style>
    .axis path,
    .axis line{
      fill: none;
      stroke: black;
      shape-rendering: crispEdges;
    }
    .axis text {
      font-family: sans-serif;
      font-size: 11px;
    }
    </style>
    </head>
    <body>
    </body> 
</html>
<script>  
  //画布大小
    var width = 400;
    var height = 400;
    //在 body 里添加一个 SVG 画布   
    var svg = d3.select("body")
    .append("svg")
    .attr("width", width)
    .attr("height", height);
    //画布周边的空白
    var padding = {left:30, right:30, top:20, bottom:20};
    //定义一个数组
    var dataset = [10, 20, 30, 40, 33, 24, 12, 5];
    //x轴的比例尺
    var xScale = d3.scale.ordinal()
    .domain(d3.range(dataset.length))
    .rangeRoundBands([0, width - padding.left - padding.right]);
    //y轴的比例尺
    var yScale = d3.scale.linear()
    .domain([0,d3.max(dataset)])
        .range([height - padding.top - padding.bottom, 0]);    
    //定义x轴
    var xAxis = d3.svg.axis()
    .scale(xScale)
    .orient("bottom");
    //定义y轴
    var yAxis = d3.svg.axis()
    .scale(yScale)
        .orient("left");
    //矩形之间的空白
  var rectPadding = 4;
    //添加矩形元素
    var rects = svg.selectAll(".MyRect")
        .data(dataset)
        .enter()
        .append("rect")
        .attr("class","MyRect")
        .attr("transform","translate(" + padding.left + "," + padding.top + ")")
        .attr("x", function(d,i){
            return xScale(i) + rectPadding/2;
        })
        .attr("y",function(d){
            return yScale(d);
        })
        .attr("width", xScale.rangeBand() - rectPadding )
        .attr("height", function(d){
            return height - padding.top - padding.bottom - yScale(d);
        })
        .attr("fill","steelblue");
    //添加文字元素
    var texts = svg.selectAll(".MyText")
        .data(dataset)
        .enter()
        .append("text")
        .attr("class","MyText")
        .attr("transform","translate(" + padding.left + "," + padding.top + ")")
        .attr("x", function(d,i){
            return xScale(i) + rectPadding/2;
        } )
        .attr("y",function(d){
            return yScale(d);
        })
        .attr("dx",function(){
            return (xScale.rangeBand() - rectPadding)/2;
        })
        .attr("dy",function(d){
            return 20;
        })
        .text(function(d){
            return d;
        })            
        .style({
            "fill":"#FFF",
            "text-anchor":"middle"
        });
    //添加x轴
    svg.append("g")
        .attr("class","axis")
        .attr("transform","translate(" + padding.left + "," + (height - padding.bottom) + ")")
        .call(xAxis); 
    //添加y轴
    svg.append("g")
        .attr("class","axis")
        .attr("transform","translate(" + padding.left + "," + padding.top + ")")
        .call(yAxis);
</script> 

三、数据平放(无比例尺)
<html> 
    <head> 
        <meta charset="utf-8"> 
        <title>Hello World</title> 
        <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> 
    </head>
    <body>
    </body> 
</html>
<script>  
  var dataset = [ 250 , 210 , 170 , 130 , 90 ];//数据(表示矩形的宽度)
    var width = 300;//画布的宽度
  var height = 300;//画布的高度
  var svg = d3.select("body")//选择文档中的body元素
    .append("svg")//添加一个svg元素
    .attr("width", width)//设定宽度
    .attr("height", height);//设定高度  
  var rectHeight = 25;//每个矩形所占的像素高度(包括空白)
  svg.selectAll("rect")
    .data(dataset)
    .enter()
    .append("rect")
    .attr("x",20)
    .attr("y",function(d,i){
         return i * rectHeight;
    })
    .attr("width",function(d){
         return d;
    })
    .attr("height",rectHeight-10)
    .attr("fill","steelblue");
</script> 

四、数据平放(有比例尺)
<html> 
    <head> 
        <meta charset="utf-8"> 
        <title>Hello World</title> 
        <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> 
    </head>
    <body>
    </body> 
</html>
<script>  
  var dataset = [ 250 , 210 , 170 , 130 , 90 ];//数据(表示矩形的宽度)
    var width = 300;//画布的宽度
  var height = 300;//画布的高度
  var svg = d3.select("body")//选择文档中的body元素
    .append("svg")//添加一个svg元素
    .attr("width", width)//设定宽度
    .attr("height", height);//设定高度  
  var rectHeight = 25;//每个矩形所占的像素高度(包括空白)
  var dataset = [ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ];
    var linear = d3.scale.linear()
        .domain([0, d3.max(dataset)])
        .range([0, 250]);
    var rectHeight = 25;//每个矩形所占的像素高度(包括空白)
    svg.selectAll("rect")
        .data(dataset)
        .enter()
        .append("rect")
        .attr("x",20)
        .attr("y",function(d,i){
            return i * rectHeight;
        })
        .attr("width",function(d){
            return linear(d);//在这里用比例尺
        })
        .attr("height",rectHeight-10)
        .attr("fill","steelblue");
</script> 

五、数据立放(无比例尺)
<html> 
    <head> 
        <meta charset="utf-8"> 
        <title>Hello World</title> 
        <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> 
    </head>
    <body>
    </body> 
</html>
<script>  
  var dataset = [ 250 , 210 , 170 , 130 , 90 ];//数据(表示矩形的宽度)
    var width = 300;//画布的宽度
  var height = 300;//画布的高度
  var svg = d3.select("body")//选择文档中的body元素
    .append("svg")//添加一个svg元素
    .attr("width", width)//设定宽度
    .attr("height", height);//设定高度  
  var rectHeight = 25;//每个矩形所占的像素高度(包括空白)
  svg.selectAll("rect")
    .data(dataset)
    .enter()
    .append("rect")
    .attr("x",function(d,i){
      return i * rectHeight;
    })
    .attr("y",function(d,i){
      return height - d;
    })
    .attr("width",rectHeight-10)
    .attr("height",function(d){
      return d;
    })
    .attr("fill","steelblue");
</script> 

六、数据立放(有比例尺)
<html> 
    <head> 
        <meta charset="utf-8"> 
        <title>Hello World</title> 
        <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> 
    </head>
    <body>
    </body> 
</html>
<script>  
  var dataset = [ 250 , 210 , 170 , 130 , 90 ];//数据(表示矩形的宽度)
    var width = 300;//画布的宽度
  var height = 300;//画布的高度
  var svg = d3.select("body")//选择文档中的body元素
    .append("svg")//添加一个svg元素
    .attr("width", width)//设定宽度
    .attr("height", height);//设定高度  
  var rectHeight = 25;//每个矩形所占的像素高度(包括空白)
  var dataset = [ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ];
    var linear = d3.scale.linear()
        .domain([0, d3.max(dataset)])
        .range([0, 250]);
    var rectHeight = 25;//每个矩形所占的像素高度(包括空白)
    svg.selectAll("rect")
        .data(dataset)
        .enter()
        .append("rect")
        .attr("x",function(d,i){
            return i * rectHeight;
        })
        .attr("y",function(d,i){
            return 250 - linear(d) ;
        })
        .attr("width",rectHeight-10)
        .attr("height",function(d){
            return linear(d);//在这里用比例尺
        })
        .attr("fill","steelblue");
</script> 

附1、饼图
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/d3/3.2.8/d3.js"></script>
    <script type="text/javascript">
      //准备数据
      var chartData = [
        { label: '漯河', value: 2 },
        { label: '舞阳', value: 3 },
        { label: '郭庄', value: 2 },
        { label: '北京', value: 3 },
        { label: '漯河3', value: 2 },
        { label: '北京3', value: 3 },
        { label: '漯河4', value: 2 },
        { label: '北京4', value: 3 },
        { label: '郭庄2', value: 4 }
      ];
      var colors = [
        '#2484c1',
        '#65a620',
        '#7b6888',
        '#a05d56',
        '#961a1a',
        '#d8d23a',
        '#e98125',
        '#d0743c',
        '#635222'
      ];
      var title = [
        {
          text: 'www.guowenke.tk',
          color: '#333333',
          fontSize: 18,
          font: 'arial'
        }
      ];
      //定义画布大小
      var canvasWidth = 600;
      var canvasHeight = 400;
      $(function () {
        var svg = d3
          .select('#pie')
          .append('svg')
          .attr('width', canvasWidth)
          .attr('height', canvasHeight);
        //标题
        svg
          .selectAll('.title')
          .data(title)
          .enter()
          .append('text')
          .text(function (d) {
            return d.text;
          })
          .attr('class', 'title')
          .attr('fill', function (d) {
            return d.color;
          })
          .style('font-family', function (d) {
            return d.font;
          })
          .attr('x', canvasWidth / 2)
          .attr('y', 30);
        //绘图
        //确定饼图中心
        var pieChartElement = svg
          .append('g')
          .attr(
            'transform',
            'translate(' + canvasWidth / 2 + ',' + canvasHeight / 2 + ')'
          );

        //创建弧生成器
        var arc = d3.svg
          .arc()
          .innerRadius(canvasHeight * 0)
          .outerRadius((canvasHeight * 0.8) / 3)
          .startAngle(0)
          .endAngle(function (d) {
            return (d.value / getSumData(chartData)) * 2 * Math.PI;
          });

        var arcs = pieChartElement
          .selectAll('g')
          .data(chartData)
          .enter()
          .append('g')
          .attr('transform', function (d, i) {
            var angle = 0;
            if (i > 0) {
              angle = getSegmentAngle(i - 1, chartData, getSumData(chartData));
            }
            return 'rotate(' + angle + ')';
          });
        arcs
          .append('path')
          .attr('fill', function (d, i) {
            return colors[i];//设定弧的颜色
          })
          .attr('d', function (d) {
            return arc(d);//使用弧生成器
          });

        //添加标签组
        var outerLabelGroupData = [];
        var lineCoordGroups = [];
        var labels = svg.append('g').attr('class', 'labels');
        var labelGroup = labels
          .selectAll('.labelGroup')
          .data(chartData)
          .enter()
          .append('g')
          .attr('class', 'labelGroup');
        labelGroup.append('text').text(function (d, i) {
          return d.label + ':' + d.value;
        });
        d3.selectAll('.labelGroup')
          .each(function (d, i) {
            var labelGroupDims = $('.labelGroup').get(i).getBBox();
            var angle = getSegmentAngle(i, chartData, getSumData(chartData), {
              midpoint: true
            });
            var originalX = canvasWidth / 2;
            var originalY = canvasHeight / 2 - ((canvasHeight * 0.8) / 3 + 3);
            var newCords = rotate(
              originalX,
              originalY,
              canvasWidth / 2,
              canvasHeight / 2,
              angle
            );
            if (angle > 180) {
              newCords.x -= labelGroupDims.width + 28;
            } else {
              newCords.x += 28;
            }
            outerLabelGroupData[i] = {
              x: newCords.x,
              y: newCords.y,
              w: labelGroupDims.width,
              h: labelGroupDims.height
            };
          })
          .attr('transform', function (d, i) {
            return (
              'translate(' +
              outerLabelGroupData[i].x +
              ',' +
              outerLabelGroupData[i].y +
              ')'
            );
          });
        d3.selectAll('.labelGroup').each(function (d, i) {
          var angle = getSegmentAngle(i, chartData, getSumData(chartData), {
            midpoint: true
          });
          var originalX = canvasWidth / 2;
          var originalY = canvasHeight / 2 - ((canvasHeight * 0.8) / 3 + 3);
          var newCords = rotate(
            originalX,
            originalY,
            canvasWidth / 2,
            canvasHeight / 2,
            angle
          );
          var labelXMargin = 6;
          var originCoords = newCords;
          var heightOffset = outerLabelGroupData[i].h / 5;
          var quarter = Math.floor(angle / 90);
          var midPoint = 4;
          var x2, y2, x3, y3;
          if (quarter === 2 && angle === 180) {
            quarter = 1;
          }
          switch (quarter) {
            case 0:
              x2 =
                outerLabelGroupData[i].x -
                labelXMargin -
                (outerLabelGroupData[i].x - labelXMargin - originCoords.x) / 2;
              y2 =
                outerLabelGroupData[i].y +
                (originCoords.y - outerLabelGroupData[i].y) / midPoint;
              x3 = outerLabelGroupData[i].x - labelXMargin;
              y3 = outerLabelGroupData[i].y - heightOffset;
              break;
            case 1:
              x2 =
                originCoords.x +
                (outerLabelGroupData[i].x - originCoords.x) / midPoint;
              y2 =
                originCoords.y +
                (outerLabelGroupData[i].y - originCoords.y) / midPoint;
              x3 = outerLabelGroupData[i].x - labelXMargin;
              y3 = outerLabelGroupData[i].y - heightOffset;
              break;
            case 2:
              var startOfLabelX =
                outerLabelGroupData[i].x +
                outerLabelGroupData[i].w +
                labelXMargin;
              x2 = originCoords.x - (originCoords.x - startOfLabelX) / midPoint;
              y2 =
                originCoords.y +
                (outerLabelGroupData[i].y - originCoords.y) / midPoint;
              x3 =
                outerLabelGroupData[i].x +
                outerLabelGroupData[i].w +
                labelXMargin;
              y3 = outerLabelGroupData[i].y - heightOffset;
              break;
            case 3:
              var startOfLabel =
                outerLabelGroupData[i].x +
                outerLabelGroupData[i].w +
                labelXMargin;
              x2 = startOfLabel + (originCoords.x - startOfLabel) / midPoint;
              y2 =
                outerLabelGroupData[i].y +
                (originCoords.y - outerLabelGroupData[i].y) / midPoint;
              x3 =
                outerLabelGroupData[i].x +
                outerLabelGroupData[i].w +
                labelXMargin;
              y3 = outerLabelGroupData[i].y - heightOffset;
              break;
          }
          lineCoordGroups[i] = [
            { x: originCoords.x, y: originCoords.y },
            { x: x2, y: y2 },
            { x: x3, y: y3 }
          ];
        });
        var lineGroups = svg
          .append('g')
          .attr('class', 'lineGroups')
          .style('opacity', 1);

        var lineGroup = lineGroups
          .selectAll('.lineGroup')
          .data(lineCoordGroups)
          .enter()
          .append('g')
          .attr('class', 'lineGroup');
        var lineFunction = d3.svg
          .line()
          .interpolate('basis')
          .x(function (d) {
            return d.x;
          })
          .y(function (d) {
            return d.y;
          });
        lineGroup
          .append('path')
          .attr('d', lineFunction)
          .attr('stroke', function (d, i) {
            return colors[i];
          })
          .attr('stroke-width', 1)
          .attr('fill', 'none');
        function rotate(x, y, xm, ym, a) {
          a = (a * Math.PI) / 180;// 转为弧度
          var cos = Math.cos,
            sin = Math.sin,
            xr = (x - xm) * cos(a) - (y - ym) * sin(a) + xm,
            yr = (x - xm) * sin(a) + (y - ym) * cos(a) + ym;
          return { x: xr, y: yr };
        }

        function getSumData(data) {
          var sumData = 0;
          var countData = data.length;
          for (var i = 0; i < countData; i++) {
            sumData += data[i].value;
          }
          return sumData;
        }
        function getSegmentAngle(index, data, sumValue, opts) {
          var options = $.extend(
            {
              compounded: true,
              midpoint: false
            },
            opts
          );

          var currValue = data[index].value;
          var fullValue;
          fullValue = 0;
          for (var i = 0; i <= index; i++) {
            fullValue += data[i].value;
          }
        //值转为角度
          var angle = (fullValue / sumValue) * 360;
          if (options.midpoint) {
            var currAngle = (currValue / sumValue) * 360;
            angle -= currAngle / 2;
          }
          return angle;
        }
      });
    </script>
  </head>
  <body>
    <div id="pie"></div>
  </body>
</html>
 

附2、svg子标签
<html> 
    <head> 
        <meta charset="utf-8"> 
        <title>svg子标签</title> 
    </head>
    <body>
        <div>
            <p>1.矩形</p>
            <p>x 属性定义矩形的左侧位置(例如,x="0" 定义矩形到浏览器窗口左侧的距离是 0px)</p>
            <p>y 属性定义矩形的顶端位置(例如,y="0" 定义矩形到浏览器窗口顶端的距离是 0px)</p>
            <p>CSS 的 fill-opacity 属性定义填充颜色透明度(合法的范围是:0 - 1)</p>
            <p>CSS 的 stroke-opacity 属性定义笔触颜色的透明度(合法的范围是:0 - 1)</p>
    </div>
    <svg width="500" height="500">
      <rect x="20" y="20" width="250" height="100" style="fill:blue;stroke:pink;stroke-width:5;fill-opacity:0.1;stroke-opacity:0.9"/>
    </svg>
    <div>
      <p>2.圆形</p>
      <p>cx 和 cy 属性定义圆点的 x 和 y 坐标。</p>
      <p>如果省略 cx 和 cy,圆的中心会被设置为 (0, 0)</p>
      <p>r 属性定义圆的半径。</p>
    </div>
    <svg width="500" height="500">
      <circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>
    </svg>
    <div>
      <p>3.椭圆</p>
      <p>cx 属性定义圆点的 x 坐标</p>
      <p>cy 属性定义圆点的 y 坐标</p>
      <p>rx 属性定义水平半径</p>
      <p>ry 属性定义垂直半径</p>
    </div>
    <svg width="500" height="500">
      <ellipse cx="300" cy="150" rx="200" ry="80" style="fill:rgb(200,100,50);stroke:rgb(0,0,100);stroke-width:2"/>
    </svg>
    <div>
      <p>4.线</p>
      <p>x1 属性在 x 轴定义线条的开始</p>
      <p>y1 属性在 y 轴定义线条的开始</p>
      <p>x2 属性在 x 轴定义线条的结束</p>
      <p>y2 属性在 y 轴定义线条的结束</p>
    </div>
    <svg width="500" height="500" >
      <line x1="0" y1="0" x2="300" y2="300" style="stroke:rgb(99,99,99);stroke-width:2"/>
    </svg>
    <div>
      <p>5.路径</p>
      <p>定义了一条路径,</p>
      <p>它开始于位置 250 150,到达位置 150 350,</p>
      <p>然后从那里开始到 350 350,</p>
      <p>最后在 250 150 关闭路径。</p>
    </div>
    <svg width="500" height="500">
      <path d="M250 150 L150 350 L350 350 Z" />
    </svg>
    <div>
      <p>6.多边形</p>
      <p>points 属性定义多边形每个角的 x 和 y 坐标</p>
    </div>
    <svg width="500" height="500">
      <polygon points="220,100 300,210 170,250" style="fill:#cccccc; stroke:#000000;stroke-width:1"/>
    </svg>
    <div>
      <p>7.折线</p>
      <p>标签用来创建仅包含直线的形状。</p>
    </div>
    <svg width="500" height="500">
      <polyline points="0,0 0,20 20,20 20,40 40,40 40,60" style="fill:white;stroke:red;stroke-width:2"/>
    </svg>
    </body> 
</html>

附3、svg背景图片解析
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>angular</title>
  <style>
    div {
      width: 100px;
      height: 100px;
      background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23000' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E");
            /* 
            注释
            %3C:<
            %3E:>
            viewBox:包含4个参数的列表 min-x, min-y, width and height,
            %23000:
            console.log(decodeURIComponent("%23000"));的结果是:#000
            console.log(encodeURIComponent("#000"))的结果是:%23000
             */
      background-repeat: no-repeat;
      background-position: center center;
      background-size: 100px 100px;
      background-color:  gray; 
      border:2px solid green;
    }
  </style>
</head>
<body>
  <div></div> 
</body>
</html>