2016-10-04 100 views
2

目前我正在开发FCC的一个项目,基本上我已完成整个项目。使用d3.js创建水平图例(v4)

不过,我很难做一个简单的传奇,尤其是当我使用scaleQuantile作为我colorScale

这里是我的codepen链接:http://codepen.io/neotriz/pen/PGOLBb

基本上我想创建一个水平传说输出所有的颜色(在数组color内)并根据数据附加其文本。

我可以硬编码的图例文本,但我宁愿做抽象(文本是基于数据本身) 如果任何人都可以指出我正确的方向,我将不胜感激。

let toolTip = d3.select("#canvas") 
       .append("div") 
       .classed("toolTip",true) 
       .style("opacity",0) 

const colors = ["#5e4fa2", "#3288bd", "#66c2a5", "#abdda4", 
      "#e6f598", "#ffffbf", "#fee08b", "#fdae61", 
      "#f46d43", "#d53e4f", "#9e0142"]; 

const width = w - (margin.left + margin.right); 
const height = h - (margin.top + margin.bottom); 
const yOffset = 40; 

//lets create new object to add degree key and its value 
data = rawData.map(oneData => { 
    let degree = base + oneData.variance 
    return Object.assign({}, oneData, {degree: degree}) 
}) 


const svg = d3.select("#canvas") 
       .append("svg") 
       .attr("id","chart") 
       .attr("width", w) 
       .attr("height", h) 

const chart = svg.append("g") 
       .classed("display", true) 
       .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

const yearParser = d3.timeParse("%Y") 
const monthParser = d3.timeParse("%m") 

const x = d3.scaleTime() 
      .domain(d3.extent(data,function(d){ 
       let year = yearParser(d.year) 
       return year 
      })) 
      .range([0,width]); 

const y = d3.scaleTime() 
      .domain([monthParser(data[0].month),monthParser(data[11].month)]) 
      .range([0,height-yOffset]) 

const xAxis = d3.axisBottom(x) 
       .tickFormat(d3.timeFormat("%Y")).tickSize(9) 

const yAxis = d3.axisLeft(y) 
       .tickFormat(d3.timeFormat("%B")).tickSize(0).tickPadding(6); 

const colorScale = d3.scaleQuantile() 
         .domain(d3.extent(data,function(d){ 
         return d.degree 
         })) 
         .range(colors) 
function toolTipText(d){ 
    const rawMonth = monthParser(d.month); 
    const monthFormat = d3.timeFormat("%B"); 

    const month = monthFormat(rawMonth) 
    let text = '<strong>' + month + " " + d.year + '</strong>'+ '<br>'; 
    text += d.degree.toFixed(3) +' °C'+ '<br>'; 
    text += 'Variance: '+d.variance +' °C'+ '<br>'; 
    return text 
} 

function drawAxis(params){ 
    //draw xAxis 
    this.append("g") 
     .call(params.axis.x) 
     .classed("x axis", true) 
     .attr("transform", "translate(0,"+ height +")") 
     .selectAll("text") 
     .style("font-size",16) 

    //draw yAxis 
    this.append("g") 
     .call(params.axis.y) 
     .classed("y axis",true) 
     .attr("transform","translate(0,0)") 
     .selectAll("text") 
     .attr("dy",25) 
     .style("font-size",14) 

    //label x axis 
    this.select(".x.axis") 
     .append("text") 
     .classed("x axis-label",true) 
     .attr("transform","translate(-60,"+ -height/2 +") rotate(-90)") 
     .style("fill","black") 
     .text("Months") 

    this.select(".y.axis") 
     .append("text") 
     .classed("y axis-label",true) 
     .attr("transform","translate("+ width/2 +","+ (height+60) +")") 
     .style("fill","black") 
     .text("Years") 
} 

function plot(params){ 
    if (params.initialize){ 
    drawAxis.call(this,params) 
    } 
    //enter() 
    this.selectAll(".degree") 
    .data(params.data) 
    .enter() 
     .append("rect") 
     .classed("degree", true) 

    //update 
    this.selectAll(".degree") 
    .transition() 
    .delay(100) 
    .attr("x",function(d,i){ 
     let year = yearParser(d.year) 
     return x(year) 
    }) 
    this.selectAll(".degree") 
    .attr("y",function(d,i){ 
     let month = monthParser(d.month) 
     return y(month) 
    }) 
    this.selectAll(".degree") 
    .attr("width", 4) 
    this.selectAll(".degree") 
    .attr("height", yOffset) 
    this.selectAll(".degree") 
    .style("fill", function(d,i){ 
     return colorScale(d.degree) 
    }) 
    .on("mouseover",function(d,i){ 
    let text = toolTipText(d) 
    toolTip.transition() 
      .style("opacity",.9) 
    toolTip.html(text) 
      .style("left", (d3.event.pageX + 15) + "px") 
      .style("top", (d3.event.pageY - 28) + "px") 

    d3.select(this) 
     .style("stroke","gray") 
     .style("stroke-width", 3) 
    }) 
    .on("mouseout",function(d,i){ 
    toolTip.transition() 
     .style("opacity",0) 
    d3.select(this) 
     .style("stroke","none") 
    }) 

    //exit() 
    this.selectAll(".degree") 
    .data(params.data) 
    .exit() 
    .remove() 
} 

plot.call(chart,{ 
    base: base, 
    data: data, 
    axis: { 
    x: xAxis, 
    y: yAxis 
    }, 
    initialize: true 
}) 
+0

'追加其文本的基础上,data'什么意思是不是?规模与度有关,是文本? – Mark

+0

是的,这就是我的意思。 – Alejandro

回答

3

这里有一个快速的实现:

function drawLegend(){ 
     var legend = this.select(".x.axis").append("g"), 
     legW = 40; 

     legend.selectAll('rect') 
     .data(colorScale.range()) 
     .enter() 
     .append('rect') 
     .attr('width', legW) 
     .attr('x', function(d,i){ 
      return i * legW; 
     }) 
     .attr('y', 50) 
     .attr('height', 20) 
     .style('fill', function(d){ 
      return d; 
     }); 

     legend.selectAll('text') 
     .data(colorScale.quantiles()) 
     .enter() 
     .append('text') 
     .attr('x', function(d,i){ 
      return (i + 1) * legW; 
     }) 
     .attr('y', 80) 
     .text(function(d,i){ 
      var rv = Math.round(d*10)/10; 
      if (i === 0) rv = '<' + rv; 
      else if (i === (colorScale.quantiles().length - 1)) rv = '>' + rv; 
      return rv; 
     }) 
     .style('fill', 'black') 
     .style('stroke', 'none'); 
    } 

完全跑步代码:

<html lang="en"> 
 

 
<head> 
 
    <meta name="viewport" content="width=device-width, initial-scale=1" /> 
 
    <meta charset="UTF-8" /> 
 
    <title>FCC Heat-Map</title> 
 
    <style> 
 
    body, 
 
    html { 
 
     text-align: center; 
 
     background: #e2e2e2; 
 
    } 
 
    
 
    #canvas { 
 
     margin: 65px auto; 
 
     width: 1300px; 
 
     height: 600; 
 
     background: white; 
 
     -webkit-box-shadow: 0px 0px 31px -5px rgba(0, 0, 0, 0.5); 
 
     -moz-box-shadow: 0px 0px 31px -5px rgba(0, 0, 0, 0.5); 
 
     box-shadow: 0px 0px 31px -5px rgba(0, 0, 0, 0.5); 
 
    } 
 
    
 
    #chart {} 
 
    
 
    .title { 
 
     padding-top: 11px; 
 
     font-size: 2em; 
 
     font-weight: bold; 
 
    } 
 
    
 
    .year { 
 
     font-size: 1.7em; 
 
    } 
 
    
 
    .description { 
 
     font-size: 0.9em; 
 
     margin-bottom: -35px; 
 
    } 
 
    
 
    .axis-label { 
 
     font-size: 25px; 
 
    } 
 
    
 
    .toolTip { 
 
     color: white; 
 
     position: absolute; 
 
     text-align: center; 
 
     max-width: 250px; 
 
     max-height: 98px; 
 
     padding: 7px; 
 
     font: 15px sans-serif; 
 
     background: black; 
 
     border: 25px; 
 
     border-radius: 12px; 
 
     line-height: 18px; 
 
     pointer-events: none; 
 
     box-shadow: 0px 0px 12px -10px; 
 
    } 
 
    </style> 
 
</head> 
 

 
<body> 
 
    <div id="canvas"></div> 
 
    <script src="//d3js.org/d3.v4.min.js"></script> 
 
    <script src="//ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script> 
 

 
    <script> 
 
    var colorScale = null; 
 
    $(document).ready(function() { 
 
     const w = 1300; 
 
     const h = 600; 
 
     const margin = { 
 
     top: 50, 
 
     bottom: 80, 
 
     left: 100, 
 
     right: 20 
 
     } 
 

 
     function title() { 
 
     const mainTitle = document.createElement("div"); 
 
     mainTitle.innerHTML = "Monthly Global Land-Surface Temperature" 
 
     mainTitle.className = "title"; 
 

 
     const year = document.createElement("div"); 
 
     year.innerHTML = "1753 - 2015"; 
 
     year.className = "year"; 
 

 
     const description = document.createElement("div") 
 
     description.innerHTML = 'Temperatures are in Celsius and reported as anomalies relative to the Jan 1951-Dec 1980 average.<br>' + 
 
      'Estimated Jan 1951-Dec 1980 absolute temperature ℃: 8.66 +/- 0.07'; 
 
     description.className = "description" 
 

 
     let chart = document.getElementById("canvas") 
 

 
     chart.appendChild(mainTitle) 
 
     chart.appendChild(year) 
 
     chart.appendChild(description) 
 

 

 
     } 
 

 
     function render(base, rawData) { 
 
     let toolTip = d3.select("#canvas") 
 
      .append("div") 
 
      .classed("toolTip", true) 
 
      .style("opacity", 0) 
 

 
     const colors = ["#5e4fa2", "#3288bd", "#66c2a5", "#abdda4", 
 
      "#e6f598", "#ffffbf", "#fee08b", "#fdae61", 
 
      "#f46d43", "#d53e4f", "#9e0142" 
 
     ]; 
 

 
     const width = w - (margin.left + margin.right); 
 
     const height = h - (margin.top + margin.bottom); 
 
     const yOffset = 40; 
 

 
     //lets create new object to add degree key and its value 
 
     data = rawData.map(oneData => { 
 
      let degree = base + oneData.variance 
 
      return Object.assign({}, oneData, { 
 
      degree: degree 
 
      }) 
 
     }) 
 

 

 
     const svg = d3.select("#canvas") 
 
      .append("svg") 
 
      .attr("id", "chart") 
 
      .attr("width", w) 
 
      .attr("height", h) 
 

 
     const chart = svg.append("g") 
 
      .classed("display", true) 
 
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 
 

 
     const yearParser = d3.timeParse("%Y") 
 
     const monthParser = d3.timeParse("%m") 
 

 
     const x = d3.scaleTime() 
 
      .domain(d3.extent(data, function(d) { 
 
      let year = yearParser(d.year) 
 
      return year 
 
      })) 
 
      .range([0, width]); 
 

 
     const y = d3.scaleTime() 
 
      .domain([monthParser(data[0].month), monthParser(data[11].month)]) 
 
      .range([0, height - yOffset]) 
 

 
     const xAxis = d3.axisBottom(x) 
 
      .tickFormat(d3.timeFormat("%Y")).tickSize(9) 
 

 
     const yAxis = d3.axisLeft(y) 
 
      .tickFormat(d3.timeFormat("%B")).tickSize(0).tickPadding(6); 
 

 
     colorScale = d3.scaleQuantile() 
 
      .domain(d3.extent(data, function(d) { 
 
      return d.degree 
 
      })) 
 
      .range(colors) 
 

 
     function toolTipText(d) { 
 
      const rawMonth = monthParser(d.month); 
 
      const monthFormat = d3.timeFormat("%B"); 
 

 
      const month = monthFormat(rawMonth) 
 
      let text = '<strong>' + month + " " + d.year + '</strong>' + '<br>'; 
 
      text += d.degree.toFixed(3) + ' °C' + '<br>'; 
 
      text += 'Variance: ' + d.variance + ' °C' + '<br>'; 
 
      return text 
 
     } 
 

 
     function drawAxis(params) { 
 
      //draw xAxis 
 
      this.append("g") 
 
      .call(params.axis.x) 
 
      .classed("x axis", true) 
 
      .attr("transform", "translate(0," + height + ")") 
 
      .selectAll("text") 
 
      .style("font-size", 16) 
 

 
      //draw yAxis 
 
      this.append("g") 
 
      .call(params.axis.y) 
 
      .classed("y axis", true) 
 
      .attr("transform", "translate(0,0)") 
 
      .selectAll("text") 
 
      .attr("dy", 25) 
 
      .style("font-size", 14) 
 

 
      //label x axis 
 
      this.select(".x.axis") 
 
      .append("text") 
 
      .classed("x axis-label", true) 
 
      .attr("transform", "translate(-60," + -height/2 + ") rotate(-90)") 
 
      .style("fill", "black") 
 
      .text("Months") 
 

 
      this.select(".y.axis") 
 
      .append("text") 
 
      .classed("y axis-label", true) 
 
      .attr("transform", "translate(" + width/2 + "," + (height + 60) + ")") 
 
      .style("fill", "black") 
 
      .text("Years") 
 
     } 
 
     
 
     function drawLegend(){ 
 
      var legend = this.select(".x.axis").append("g"), 
 
      legW = 40; 
 
      
 
      legend.selectAll('rect') 
 
      .data(colorScale.range()) 
 
      .enter() 
 
      .append('rect') 
 
      .attr('width', legW) 
 
      .attr('x', function(d,i){ 
 
       return i * legW; 
 
      }) 
 
      .attr('y', 40) 
 
      .attr('height', 20) 
 
      .style('fill', function(d){ 
 
       return d; 
 
      }); 
 
      
 
      legend.selectAll('text') 
 
      .data(colorScale.quantiles()) 
 
      .enter() 
 
      .append('text') 
 
      .attr('x', function(d,i){ 
 
       return (i + 1) * legW; 
 
      }) 
 
      .attr('y', 70) 
 
      .text(function(d,i){ 
 
       var rv = Math.round(d*10)/10; 
 
       if (i === 0) rv = '<' + rv; 
 
       else if (i === (colorScale.quantiles().length - 1)) rv = '>' + rv; 
 
       return rv; 
 
      }) 
 
      .style('fill', 'black') 
 
      .style('stroke', 'none'); 
 
     } 
 

 
     function plot(params) { 
 
      if (params.initialize) { 
 
      drawAxis.call(this, params) 
 
      } 
 
      //enter() 
 
      this.selectAll(".degree") 
 
      .data(params.data) 
 
      .enter() 
 
      .append("rect") 
 
      .classed("degree", true) 
 

 
      //update 
 
      this.selectAll(".degree") 
 
      .transition() 
 
      .delay(100) 
 
      .attr("x", function(d, i) { 
 
       let year = yearParser(d.year) 
 
       return x(year) 
 
      }) 
 
      this.selectAll(".degree") 
 
      .attr("y", function(d, i) { 
 
       let month = monthParser(d.month) 
 
       return y(month) 
 
      }) 
 
      this.selectAll(".degree") 
 
      .attr("width", 4) 
 
      this.selectAll(".degree") 
 
      .attr("height", yOffset) 
 
      this.selectAll(".degree") 
 
      .style("fill", function(d, i) { 
 
       return colorScale(d.degree) 
 
      }) 
 
      .on("mouseover", function(d, i) { 
 
       let text = toolTipText(d) 
 
       toolTip.transition() 
 
       .style("opacity", .9) 
 
       toolTip.html(text) 
 
       .style("left", (d3.event.pageX + 15) + "px") 
 
       .style("top", (d3.event.pageY - 28) + "px") 
 

 
       d3.select(this) 
 
       .style("stroke", "gray") 
 
       .style("stroke-width", 3) 
 
      }) 
 
      .on("mouseout", function(d, i) { 
 
       toolTip.transition() 
 
       .style("opacity", 0) 
 
       d3.select(this) 
 
       .style("stroke", "none") 
 
      }) 
 

 
      //exit() 
 
      this.selectAll(".degree") 
 
      .data(params.data) 
 
      .exit() 
 
      .remove() 
 
      
 
      drawLegend.call(this); 
 
     } 
 

 
     plot.call(chart, { 
 
      base: base, 
 
      data: data, 
 
      axis: { 
 
      x: xAxis, 
 
      y: yAxis 
 
      }, 
 
      initialize: true 
 
     }) 
 

 
     } 
 
     const url = 'https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/global-temperature.json'; 
 
     $.ajax({ 
 
     type: "GET", 
 
     dataType: "json", 
 
     url: url, 
 
     beforeSend:() => {}, 
 
     complete:() => {}, 
 
     success: data => { 
 
      title() 
 
      const baseTemperature = data.baseTemperature; 
 
      const dataAPI = data.monthlyVariance; 
 
      render(baseTemperature, dataAPI); 
 
     }, 
 
     fail:() => { 
 
      console.log('failure!') 
 
     }, 
 
     error:() => { 
 
      let chart = document.getElementById('card'); 
 
      chart.style.display = "table" 
 
      let errorMessage = document.createElement("h1"); 
 
      errorMessage.innerHTML = "ERROR 404: File Not Found!" 
 
      errorMessage.className = "errorMessage"; 
 
      chart.appendChild(errorMessage) 
 
     } 
 
     }); 
 
    }); 
 
    </script> 
 

 

 
</body> 
 

 
</html>

+0

谢谢马克!我很欣赏把你的时间帮助一个人 – Alejandro