基础部分

2018-11-19  本文已影响0人  今天女朋友想我了没

坐标系

D3通过SVG画图,SVG的坐标系同HTML中的坐标系类似,都是以左上角作为坐标原点,向下向右为正延伸。

坐标轴

坐标轴的实现有多种方法,主要可以分为以下几种:

坐标轴的绘制通过上述的各种映射,然后根据映射设置样式,如d3中的axisBottom()绘制在底部的坐标轴,还可以设置刻度的长度、数量等等,然后通过添加g元素,通过call回调来画出给定格式的坐标轴,轴通过path绘制,刻度通过d3中提供的line(“path generator“之一)进行绘制,刻度之下的标注通过text标签,各项的位置可以通过attr添加transform属性来添加translate进行微调。

主要的图表元素

例如矩形图中的rect、散点图中的circle都是SVG中的元素,在d3中通过selectAll("rect").data(dataset).enter().append("rect")这种方式来给各项创建的矩形绑定数据。
.data会给所选择的元素分配数据,如果所给元素少于可分配数据的话,就会把数据存于placeholder,.enter返回代表需要增加的那些元素(已经绑定了placeholder数据)的selection,所以在后面接的append()创建元素一经创建都绑定了所给的数据。矩形元素的定位依靠x,y,其中x,y的数据需要与坐标轴进行绑定,就是通过上述的各种映射,计算出相应的在SVG图上的位置。

在SVG中可以通过path路径来进行产生任意的graph,d3提供了path generator可以根据points数组为我们自动创建path所需的d属性字符串,两者结合,可以很轻松的创建复杂的图形,对于想饼图这种需要startangle、endangle,输入的数据只是一个数组,故先把数组转换为对应的[startangle,endangle]数组,然后通过弧生成器来绘制最终的饼图。

Brush and Zoom

刷子选定选区,zoom进行缩放,缩放的原理是将选中的选区映射到整个画布之中,相当于一种对画布的重新绘制。
条形图、面积图和折线图的zoom采用的机制都比较类似。都是先调用zoom的各项API创建一个zoom behavior,
zoom.extent()设置平移显示的视口范围,
zoom.scaleExtent()设置缩放的倍数,
zoom.translateExtent()设置可以平移的元素范围,
zoom.on()声明监听器,处理鼠标手势发生时的进行的操作,

在监听器处理程序之中,最主要的一步就是
xScale.range([2*padding,width-2*padding].map(d => d3.event.transform.applyX(d)));这是对x轴的比例尺的range进行改写,
d3.event.transform.applyX(d)返回的是转换之后的x轴坐标.对比例尺进行改写之后再重新绘制各个元素的位置达到缩放的效果。

demo

完整代码见 github

//部分关键代码
var svg = d3.select("#chart")
        .append("svg")
        .attr("id","column")
        .attr("width",width)
        .attr("height",height)
        .call(zoom);
  
    var xScale = d3.scaleBand()
        .domain(tumourid)
        .rangeRound([2*padding,width-2*padding]);
  
    var yScale = d3.scaleLinear()
        .domain([0,1.1*yAxisWidth])
        .range([height-3*padding,3*padding]);
  
    var xAxis = d3.axisBottom(xScale)
        .tickSize(0)
        .tickPadding(6)
        .tickValues(xScale.domain().filter(function(d,i){return !(i%10)}));
        
    var yAxis = d3.axisLeft(yScale).tickSize(0);
   //缩放操作
    function zoom(svg){
      const extent = [[2*padding,3*padding],[width-2*padding,height-3*padding]];
      svg.call(d3.zoom()
        .scaleExtent([1,20])
        .translateExtent(extent)
        .extent(extent)
        .on("zoom",zoomed));
      function zoomed(){
        xScale.range([2*padding,width-2*padding].map(d => d3.event.transform.applyX(d)));
        svg.select("#svgrects")
          .selectAll("rect")
          .attr("x",function(d){
            return xScale(d["ID "])+xScale.bandwidth()/2;
          })
          .attr("width",xScale.bandwidth());
        svg.select(".axis--x").call(xAxis);
      }
    }
//缩放裁剪
    svg.append("defs").append("clipPath")
        .attr("id","myclip")
        .append("rect")
        .attr("x","40")
        .attr("y","0")
        .attr("width","600")
        .attr("height","500");

    function make_y_axis(){
      return d3.axisLeft(yScale);
    }
    svg.append("g")
        .attr("stroke","lightgray")
        .attr("stroke-opacity","0.1")
        .attr("shape-rendering","crispEdges")
        .call(make_y_axis()
         .tickSize(-width+4*padding,0,0)
         .tickFormat(""))
        .attr("transform","translate("+(2*padding)+",0)");
  
    svg.append("g")
        .attr("class","axis axis--x")
        .attr("clip-path","url(#myclip)")
        .attr("transform","translate(0,"+(height-3*padding)+")")
        .call(xAxis)
        .selectAll("text")
        .attr("transform","rotate(90)"+"translate("+(1.4*padding)+",0)")
    svg.append("text")
        .attr("fill","black")
        .attr("text-anchor","end")
        .attr("font-size",10)
        .attr("x",width-padding)
        .attr("y",height-2*padding)
        .text("肿瘤ID");
    
    svg.append("g")
        .attr("class","axis axis--y")
        .attr("transform","translate("+(2*padding)+",0)")
        .call(yAxis)
        .append("text")
        .attr("text-anchor","middle")
        .attr("font-size",10)
        .attr("fill","black")
        .attr("x",0)
        .attr("y",3*padding)
        .text(s);
    
    svg.selectAll("text")
        .attr("fill","black");
    var rects = svg.append("g")
        .attr("id","svgrects")
        .attr("clip-path","url(#myclip)")
        .selectAll("rect")
        .data(dataset)
        .enter()
        .append("rect")
        .attr("fill",document.getElementById("variablescolor").value)
        .attr("x",function(d){
          return xScale(d["ID "])+xScale.bandwidth()/2;
        })
        .attr("y",function(d){
          return yScale(d[s]);
        })
        .attr("width",xScale.bandwidth())
        .attr("height",function(d){
          return height-yScale(d[s])-3*padding;
        }) ;
//部分关键代码
var svg = d3.select("#chart")
        .append("svg")
        .attr("id","solid")
        .attr("width",width)
        .attr("height",height)
  
    var xScale = d3.scaleLinear()
        .domain([0,1.1*xAxisWidth])
        .range([2*padding,width-padding*2]);
  
    var yScale = d3.scaleLinear()
        .domain([0,1.1*yAxisWidth])
        .range([height-padding,padding]);
      var circle =svg.append("g")
        .attr("id","svgcircles")
        .attr("clip-path","url(#myclip)")
        .selectAll("circle")
        .data(dataset)
        .enter()
        .append("circle")
        .attr("fill",document.getElementById("variablescolor").value)
        .attr("cx",function(d){
          return xScale(d[xstring]);
        })
        .attr("cy",function(d){
          return yScale(d[ystring]);
        })
        .attr("r",document.getElementById("variablessize").value);
  
    var xAxis = d3.axisBottom(xScale).tickSize(0,0,0);
       
    var yAxis = d3.axisLeft(yScale).tickSize(0,0,0);
    
    function make_x_axis(){
      return d3.axisBottom(xScale);
    }
    function make_y_axis(){
      return d3.axisLeft(yScale);
    }
    svg.append("g")
      .attr("calss","grid grid--x")
      .attr("stroke","lightgray")
      .attr("stroke-opacity","0.1")
      .attr("shape-rendering","crispEdges")
      .call(make_x_axis()
        .tickSize(height-2*padding,0,0)
        .tickFormat("")
      )
      .attr("transform","translate(0,"+padding+")");
    svg.append("g")
    .attr("class","grid grid--y")
    .attr("stroke","lightgray")
    .attr("stroke-opacity","0.1")
    .attr("shape-rendering","crispEdges")
    .call(make_y_axis()
      .tickSize(-width+4*padding,0,0)
      .tickFormat("")
    )
    .attr("transform","translate("+(2*padding)+",0)");
    svg.append("g")
        .attr("class","axis axis--x")
        .attr("transform","translate(0,"+(height-padding)+")")
        .call(xAxis)
        .append("text")
        .attr("fill","black")
        .attr("text-anchor","end")
        .attr("font-size",10)
        .attr("x",width)
        .attr("y",0)
        .text(xstring);
    
    svg.append("g")
        .attr("class","axis axis--y")
        .attr("transform","translate("+(2*padding)+",0)")
        .call(yAxis)
        .append("text")
        .attr("fill","black")
        .attr("text-anchor","middle")
        .attr("font-size",10)
        .attr("x",0)
        .attr("y",padding)
        .text(ystring);
  
    svg.selectAll("text")
        .attr("fill","black");
   
    svg.append("defs").append("clipPath")
        .attr("id","myclip")
        .append("rect")
        .attr("x","40")
        .attr("y","20")
        .attr("width","420")
        .attr("height","460");
    var brush = d3.brush().on("end",brushended),
        idleTimeout,
        idleDelay = 350;
    svg.append("g")
        .attr("id","brush")
        .call(brush);
    d3.select(".overlay").attr("pointer-events","none");
    d3.select("svg")
    .on("mousedown",function(){
      d3.select(".overlay").attr("pointer-events","all");
    });
        
    function brushended(){
      var s = d3.event.selection;
      if(!s){
        if(!idleTimeout){
          return idleTimeout = setTimeout(idled,idleDelay);
        }
        xScale.domain([0,1.1*xAxisWidth]);
        yScale.domain([0,1.1*yAxisWidth]);
      }else{
        xScale.domain([s[0][0],s[1][0]].map(xScale.invert,xScale));
        yScale.domain([s[1][1],s[0][1]].map(yScale.invert,yScale));
        svg.select("#brush").call(brush.move,null);
      }
      d3.select(".overlay").attr("pointer-events","none");
      zoom();
    }
    function idled(){
      idleTimeout = null;
    }
    function zoom(){
      var t = svg.transition().duration(750);
      svg.select(".axis--x").transition(t).call(xAxis);
      svg.select(".axis--y").transition(t).call(yAxis);
      svg.select(".grid--x").transition(t).call(make_x_axis()
      .tickSize(height-2*padding,0,0)
      .tickFormat(""));
      svg.select(".grid--y").transition(t).call(make_y_axis()
      .tickSize(-width+4*padding,0,0)
      .tickFormat(""));
      d3.select("#svgcircles").selectAll("circle").transition(t)
          .attr("cx",function(d){return xScale(d[xstring]);})
          .attr("cy",function(d){return yScale(d[ystring]);});
    }
上一篇下一篇

猜你喜欢

热点阅读