我需要帮助使用 D3 将图例功能添加到我的图表中

问题描述 投票:0回答:1

本作业的目标是创建交互式可视化。我正在制作一个条形图,其中包含用于切换某些条形的图例。

我的图表的 y 轴显示欧洲的电动汽车销量,x 轴显示国家/地区。图表的颜色代表该国家/地区的人口范围。我想创建一个图例,当单击特定颜色时,会用相应的颜色切换条形。

这是我第一次使用 D3,所以我的代码可能会也可能不会达到标准。如有任何帮助,我们将不胜感激!

var salesData;
var runningData;
var runningColors;

var customLegendData = [{
    label: "Population: >10 Million",
    color: "#008B8B"
  },
  {
    label: "Population: 10 Million - 50 Million",
    color: "#2F4F4F"
  },
  {
    label: "Population: 50 Million - 100 Million",
    color: "#48308B"
  }
];

$(document).ready(function() {
  Plot();
  addCustomLegend(customLegendData);
  attachLegendToggle();
});

function Plot() {
  TransformChartData(chartData, chartOptions);
  BuildBar("chart", chartData, chartOptions);
}

function BuildBar(id, chartData, options, level) {
  var chart = d3.select("#" + id);

  var margin = {
      top: 10,
      right: 10,
      bottom: 70,
      left: 70
    },
    barWidth = 70,
    barPadding = 5;
  var width = (barWidth + barPadding) * runningData.length; // Adjusted the width
  var height = $(chart[0]).outerHeight() - margin.top - margin.bottom;

  var xVarName;
  var yVarName = options[0].yaxis;

  xVarName = options[0].xaxis;

  var xAry = runningData.map(function(el) {
    return el[xVarName];
  });

  var yAry = runningData.map(function(el) {
    return el[yVarName];
  });

  var capAry = runningData.map(function(el) {
    return el.caption;
  });

  var x = d3.scale.ordinal().domain(xAry).rangeRoundBands([0, width], 0.1);

  var yMax = d3.max(runningData, function(d) {
    return +d[yVarName];
  });
  var y = d3.scale.linear().domain([0, yMax]).range([height, 0]);

  var rcolor = d3.scale.ordinal().range(runningColors);

  chart = chart
    .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  var bars = chart.selectAll("g")
    .data(runningData)
    .enter()
    .append("g")
    .attr("class", function(d) {
      return "bar " + d[xVarName]; // Add a class based on the country
    })
    .attr("data-country", function(d) {
      return d[xVarName]; // Add data attribute with the country name
    })
    .attr("transform", function(d) {
      return "translate(" + (x(d[xVarName]) + barPadding / 2) + ", 0)";
    });

  var ctrtxt = 0;

  var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom")
    .ticks(xAry.length)
    .tickFormat(function(d) {
      var mapper = options[0].captions[0];
      return mapper[d];
    });

  var yAxisTicks = [0, 10000, 50000, 100000, 200000, 300000, 400000]
  var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left")
    .tickValues(yAxisTicks);

  bars.append("rect")
    .attr("class", function(d) {
      return "bar-" + d[xVarName]; // Add a class based on the country
    })
    .attr("y", function(d) {
      return y(parseInt(d[yVarName]));
    })
    .attr("height", function(d) {
      return height - y(parseInt(d[yVarName]));
    })
    .attr("width", x.rangeBand() - barPadding)
    .style("fill", function(d) {
      return rcolor(d[xVarName]);
    });

  bars.append("text")
    .attr("x", x.rangeBand() / 2)
    .attr("y", function(d) {
      return y(parseInt(d[yVarName])) - 5;
    })
    .attr("dy", ".35em")
    .text(function(d) {
      return d[yVarName];
    })
    .attr("class", "bar-text");

  chart.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis)
    .selectAll(".tick text")
    .style("text-anchor", "end")
    .attr("dx", "-.8em")
    .attr("dy", ".15em")
    .attr("transform", "rotate(-45)");

  chart.append("g")
    .attr("class", "y axis")
    .call(yAxis)
    .append("text")
    .attr("transform", "rotate(-90)")
    .attr("y", -40)
    .attr("dy", ".71em")
    .style("text-anchor", "end");

  return chart;
}

function attachLegendToggle() {
  d3.selectAll("#legend .legend-item").on("click", function(event, d) {
    var country = d.label;
    var barsToToggle = d3.selectAll("#chart [data-country='" + country + "']");

    barsToToggle.classed("hidden", function() {
      var isHidden = d3.select(this).classed("hidden");
      return !isHidden;
    });
  });
}

function TransformChartData(chartData, opts, level, filter) {
  var result = [];
  var resultColors = [];
  var counter = 0;
  var hasMatch;
  var xVarName;
  var yVarName = opts[0].yaxis;

  xVarName = opts[0].xaxis;

  for (var i in chartData) {
    hasMatch = false;
    for (var index = 0; index < result.length; ++index) {
      var data = result[index];

      if (data[xVarName] == chartData[i][xVarName]) {
        result[index][yVarName] = result[index][yVarName] + chartData[i][yVarName];
        hasMatch = true;
        break;
      }
    }
    if (hasMatch == false) {
      ditem = {};
      ditem[xVarName] = chartData[i][xVarName];
      ditem[yVarName] = chartData[i][yVarName];
      ditem["caption"] = opts[0].captions != undefined ? opts[0].captions[0]
        [chartData[i][xVarName]] : "";
      ditem["title"] = opts[0].captions != undefined ? opts[0].captions[0]
        [chartData[i][xVarName]] : "";
      ditem["op"] = 1;
      result.push(ditem);

      resultColors[counter] = opts[0].color != undefined ? opts[0].color[0]
        [chartData[i][xVarName]] : "";

      counter += 1;
    }
  }
  runningData = result;
  runningColors = resultColors;
  return;
}


var chartData = [{
    "Country": "UK",
    "Sales": "370000"
  },
  {
    "Country": "France",
    "Sales": "340000"
  },
  {
    "Country": "Norway",
    "Sales": "166000"
  },
  {
    "Country": "Sweden",
    "Sales": "163000"
  },
  {
    "Country": "Italy",
    "Sales": "114000"
  },
  {
    "Country": "Netherlands",
    "Sales": "107000"
  },
  {
    "Country": "Belgium",
    "Sales": "97000"
  },
  {
    "Country": "Spain",
    "Sales": "82000"
  },
  {
    "Country": "Switzerland",
    "Sales": "59000"
  },
  {
    "Country": "Denmark",
    "Sales": "57000"
  },
  {
    "Country": "Austria",
    "Sales": "38900"
  },
  {
    "Country": "Portugal",
    "Sales": "34000"
  },
  {
    "Country": "Finland",
    "Sales": "31000"
  },
  {
    "Country": "Poland",
    "Sales": "25000"
  },
  {
    "Country": "Iceland",
    "Sales": "11900"
  },
  {
    "Country": "Greece",
    "Sales": "8300"
  },
  {
    "Country": "Turkey",
    "Sales": "7540"
  },
];

chartOptions = [{
  "captions": [{
    "Germany": "Germany",
    "UK": "UK",
    "France": "France",
    "Norway": "Norway",
    "Sweden": "Sweden",
    "Italy": "Italy",
    "Netherlands": "Netherlands",
    "Belgium": "Belgium",
    "Spain": "Spain",
    "Switzerland": "Switzerland",
    "Denmark": "Denmark",
    "Austria": "Austria",
    "Portugal": "Portugal",
    "Finland": "Finland",
    "Poland": "Poland",
    "Iceland": "Iceland",
    "Greece": "Greece",
    "Turkey": "Turkey",
  }],

  "color": [{
    "Germany": "#483D8B",
    "UK": "#483D8B",
    "France": "#483D8B",
    "Norway": "#008B8B",
    "Sweden": "#2F4F4F",
    "Italy": "#483D8B",
    "Netherlands": "#2F4F4F",
    "Belgium": "#2F4F4F",
    "Spain": "#2F4F4F",
    "Switzerland": "#008B8B",
    "Denmark": "#008B8B",
    "Austria": "#008B8B",
    "Portugal": "#2F4F4F",
    "Finland": "#483D8B",
    "Poland": "#2F4F4F",
    "Iceland": "#008B8B",
    "Greece": "#2F4F4F",
    "Turkey": "#483D8B",
  }],
  "xaxis": "Country",
  "yaxis": "Sales"
}];

function addCustomLegend(legendData) {
  var legend = d3.select("#legend")
    .selectAll(".legend-item") // Add class selector
    .data(legendData)
    .enter()
    .append("g")
    .attr("class", "legend-item") // Add class
    .attr("transform", function(d, i) {
      return "translate(0," + i * 20 + ")";
    });

  legend.append("rect")
    .attr("width", 18)
    .attr("height", 18)
    .style("fill", function(d) {
      return d.color;
    });

  legend.append("text")
    .attr("x", 24)
    .attr("y", 9)
    .attr("dy", ".35em")
    .style("text-anchor", "start")
    .text(function(d) {
      return d.label;
    });
}
#chart text {
  fill: black;
  font: 10px sans-serif;
  text-anchor: end;
}

.axis text {
  font: bold 10px sans-serif;
}

.axis text.x-axis-label {
  font: bold 10px sans-serif;
}

.axis path,
.axis line {
  fill: none;
  shape-rendering: crispEdges;
}

html,
body {
  height: 100%;
  margin: 0;
}

body {
  color: #eaeaea;
  padding: 0px;
  background: linear-gradient(to bottom, #3498db, #ffffff);
  background-attachment: fixed;
}

path {
  stroke: steelblue;
  stroke-width: 2;
  fill: none;
}

#chart-title {
  text-align: center;
  margin-top: 20px;
}

#chart-title h2 {
  font-size: 50px;
  color: #333;
}

#chart {
  width: 100%;
}

#legend {
  position: absolute;
  padding-top: 1%;
  padding-right: 1%;
  padding-left: 1%;
  top: 100px;
  right: 20px;
  background-color: #FFFFFF;
}
<script src="https://code.jquery.com/jquery-1.12.4.min.js" charset="utf-8"></script>
<script src="https://d3js.org/d3.v3.min.js"></script>
<div id="chart-title">
  <h2>2022 Electric Vehicle Sales in Europe</h2>
</div>
<div id="chart" style="height:100%; width:100%;"></div>
<svg id="legend" width="200" height="200"></svg>

javascript d3.js charts visualization
1个回答
0
投票

var salesData;
var runningData;
var runningColors;

var customLegendData = [{
    label: "Population: >10 Million",
    color: "#008B8B",
    lowerRange : 0,
    upperRange : 10000000
  },
  {
    label: "Population: 10 Million - 50 Million",
    color: "#2F4F4F",
     lowerRange : 10000000,
     upperRange : 50000000
  },
  {
    label: "Population: 50 Million - 100 Million",
    color: "#48308B",
    lowerRange : 50000000,
    upperRange : 100000000
  }
];

$(document).ready(function() {
  Plot();
  addCustomLegend(customLegendData);
  attachLegendToggle();
});

function Plot() {
  TransformChartData(chartData, chartOptions);
  BuildBar("chart", chartData, chartOptions);
}

function BuildBar(id, chartData, options, level) {
  d3.select("#" + id).select("svg").remove();
  var chart = d3.select("#" + id);

  var margin = {
      top: 10,
      right: 10,
      bottom: 70,
      left: 70
    },
    barWidth = 70,
    barPadding = 5;
  var width = (barWidth + barPadding) * runningData.length; // Adjusted the width
  var height = $(chart[0]).outerHeight() - margin.top - margin.bottom;

  var xVarName;
  var yVarName = options[0].yaxis;

  xVarName = options[0].xaxis;

  var xAry = runningData.map(function(el) {
    return el[xVarName];
  });

  var yAry = runningData.map(function(el) {
    return el[yVarName];
  });

  var capAry = runningData.map(function(el) {
    return el.caption;
  });

  var x = d3.scale.ordinal().domain(xAry).rangeRoundBands([0, width], 0.1);

  var yMax = d3.max(runningData, function(d) {
    return +d[yVarName];
  });
  var y = d3.scale.linear().domain([0, yMax]).range([height, 0]);

  var rcolor = d3.scale.ordinal().range(runningColors);

  chart = chart
    .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  var bars = chart.selectAll("g")
    .data(runningData)
    .enter()
    .append("g")
    .attr("class", function(d) {
      return "bar " + d[xVarName]; // Add a class based on the country
    })
    .attr("data-country", function(d) {
      return d[xVarName]; // Add data attribute with the country name
    })
    .attr("transform", function(d) {
      return "translate(" + (x(d[xVarName]) + barPadding / 2) + ", 0)";
    });

  var ctrtxt = 0;

  var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom")
    .ticks(xAry.length)
    .tickFormat(function(d) {
      var mapper = options[0].captions[0];
      return mapper[d];
    });

  var yAxisTicks = [0, 10000, 50000, 100000, 200000, 300000, 400000]
  var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left")
    .tickValues(yAxisTicks);

  bars.append("rect")
    .attr("class", function(d) {
      return "bar-" + d[xVarName]; // Add a class based on the country
    })
    .attr("y", function(d) {
      return y(parseInt(d[yVarName]));
    })
    .attr("height", function(d) {
      return height - y(parseInt(d[yVarName]));
    })
    .attr("width", x.rangeBand() - barPadding)
    .style("fill", function(d) {
      return rcolor(d[xVarName]);
    });

  bars.append("text")
    .attr("x", x.rangeBand() / 2)
    .attr("y", function(d) {
      return y(parseInt(d[yVarName])) - 5;
    })
    .attr("dy", ".35em")
    .text(function(d) {
      return d[yVarName];
    })
    .attr("class", "bar-text");

  chart.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis)
    .selectAll(".tick text")
    .style("text-anchor", "end")
    .attr("dx", "-.8em")
    .attr("dy", ".15em")
    .attr("transform", "rotate(-45)");

  chart.append("g")
    .attr("class", "y axis")
    .call(yAxis)
    .append("text")
    .attr("transform", "rotate(-90)")
    .attr("y", -40)
    .attr("dy", ".71em")
    .style("text-anchor", "end");

  return chart;
}

function attachLegendToggle() {
  d3.selectAll("#legend .legend-item").on("click", function(event, d) {
    var country = d.label;
    var barsToToggle = d3.selectAll("#chart [data-country='" + country + "']");

    barsToToggle.classed("hidden", function() {
      var isHidden = d3.select(this).classed("hidden");
      return !isHidden;
    });
  });
}

function TransformChartData(chartData, opts, level, filter) {
  var result = [];
  var resultColors = [];
  var counter = 0;
  var hasMatch;
  var xVarName;
  var yVarName = opts[0].yaxis;

  xVarName = opts[0].xaxis;

  for (var i in chartData) {
    hasMatch = false;
    for (var index = 0; index < result.length; ++index) {
      var data = result[index];

      if (data[xVarName] == chartData[i][xVarName]) {
        result[index][yVarName] = result[index][yVarName] + chartData[i][yVarName];
        hasMatch = true;
        break;
      }
    }
    if (hasMatch == false) {
      ditem = {};
      ditem[xVarName] = chartData[i][xVarName];
      ditem[yVarName] = chartData[i][yVarName];
      ditem["caption"] = opts[0].captions != undefined ? opts[0].captions[0]
        [chartData[i][xVarName]] : "";
      ditem["title"] = opts[0].captions != undefined ? opts[0].captions[0]
        [chartData[i][xVarName]] : "";
      ditem["op"] = 1;
      result.push(ditem);

      resultColors[counter] = opts[0].color != undefined ? opts[0].color[0]
        [chartData[i][xVarName]] : "";

      counter += 1;
    }
  }
  runningData = result;
  runningColors = resultColors;
  return;
}


var chartData = [{
    "Country": "UK",
    "Sales": "370000",
    "Population":60000000
  },
  {
    "Country": "France",
    "Sales": "340000",
    "Population":70000000
  },
  {
    "Country": "Norway",
    "Sales": "166000",
     "Population":6000000
    
  },
  {
    "Country": "Sweden",
    "Sales": "163000",
    "Population":11000000
  },
  {
    "Country": "Italy",
    "Sales": "114000",
    "Population":80000000
  },
  {
    "Country": "Netherlands",
    "Sales": "107000",
    "Population":12000000
  },
  {
    "Country": "Belgium",
    "Sales": "97000",
    "Population":13000000
  },
  {
    "Country": "Spain",
    "Sales": "82000",
    "Population":14000000
  },
  {
    "Country": "Switzerland",
    "Sales": "59000",
     "Population":7000000
  },
  {
    "Country": "Denmark",
    "Sales": "57000",
     "Population":8000000
  },
  {
    "Country": "Austria",
    "Sales": "38900",
     "Population":9000000
  },
  {
    "Country": "Portugal",
    "Sales": "34000",
    "Population":15000000
  },
  {
    "Country": "Finland",
    "Sales": "31000",
    "Population":90000000
  },
  {
    "Country": "Poland",
    "Sales": "25000",
    "Population":16000000
  },
  {
    "Country": "Iceland",
    "Sales": "11900",
     "Population":6500000
  },
  {
    "Country": "Greece",
    "Sales": "8300",
    "Population":95000000
  },
  {
    "Country": "Turkey",
    "Sales": "7540",
     "Population":96000000
  },
];

chartOptions = [{
  "captions": [{
    "Germany": "Germany",
    "UK": "UK",
    "France": "France",
    "Norway": "Norway",
    "Sweden": "Sweden",
    "Italy": "Italy",
    "Netherlands": "Netherlands",
    "Belgium": "Belgium",
    "Spain": "Spain",
    "Switzerland": "Switzerland",
    "Denmark": "Denmark",
    "Austria": "Austria",
    "Portugal": "Portugal",
    "Finland": "Finland",
    "Poland": "Poland",
    "Iceland": "Iceland",
    "Greece": "Greece",
    "Turkey": "Turkey",
  }],

  "color": [{
    "Germany": "#483D8B",
    "UK": "#483D8B",
    "France": "#483D8B",
    "Norway": "#008B8B",
    "Sweden": "#2F4F4F",
    "Italy": "#483D8B",
    "Netherlands": "#2F4F4F",
    "Belgium": "#2F4F4F",
    "Spain": "#2F4F4F",
    "Switzerland": "#008B8B",
    "Denmark": "#008B8B",
    "Austria": "#008B8B",
    "Portugal": "#2F4F4F",
    "Finland": "#483D8B",
    "Poland": "#2F4F4F",
    "Iceland": "#008B8B",
    "Greece": "#2F4F4F",
    "Turkey": "#483D8B",
  }],
  "xaxis": "Country",
  "yaxis": "Sales"
}];

function addCustomLegend(legendData) {
  var legend = d3.select("#legend")
    .selectAll(".legend-item") // Add class selector
    .data(legendData)
    .enter()
    .append("g")
    .attr("class", "legend-item") // Add class
    .attr("transform", function(d, i) {
      return "translate(0," + i * 20 + ")";
    });

  legend.append("rect")
    .attr("width", 18)
    .attr("height", 18)
    .style("fill", function(d) {
      return d.color;
    })
    .on("click",function(data){
     console.log(data)
     let updattedChartData = chartData.filter((el => el.Population >= data.lowerRange && el.Population <=data.upperRange))
    TransformChartData(updattedChartData, chartOptions);
    BuildBar("chart", updattedChartData, chartOptions);
    });

  legend.append("text")
    .attr("x", 24)
    .attr("y", 9)
    .attr("dy", ".35em")
    .style("text-anchor", "start")
    .text(function(d) {
      return d.label;
    })
      .on("click",function(data){
     console.log(data)
     let updattedChartData = chartData.filter((el => el.Population >= data.lowerRange && el.Population <=data.upperRange))
    TransformChartData(updattedChartData, chartOptions);
    BuildBar("chart", updattedChartData, chartOptions);
    });
    
}
#chart text {
  fill: black;
  font: 10px sans-serif;
  text-anchor: end;
}

.axis text {
  font: bold 10px sans-serif;
}

.axis text.x-axis-label {
  font: bold 10px sans-serif;
}

.axis path,
.axis line {
  fill: none;
  shape-rendering: crispEdges;
}

html,
body {
  height: 100%;
  margin: 0;
}

body {
  color: #eaeaea;
  padding: 0px;
  background: linear-gradient(to bottom, #3498db, #ffffff);
  background-attachment: fixed;
}

path {
  stroke: steelblue;
  stroke-width: 2;
  fill: none;
}

#chart-title {
  text-align: center;
  margin-top: 20px;
}

#chart-title h2 {
  font-size: 50px;
  color: #333;
}

#chart {
  width: 100%;
}

#legend {
  position: absolute;
  padding-top: 1%;
  padding-right: 1%;
  padding-left: 1%;
  top: 100px;
  right: 20px;
  background-color: #FFFFFF;
}
<script src="https://code.jquery.com/jquery-1.12.4.min.js" charset="utf-8"></script>
<script src="https://d3js.org/d3.v3.min.js"></script>
<div id="chart-title">
  <h2>2022 Electric Vehicle Sales in Europe</h2>
</div>
<div id="chart" style="height:100%; width:100%;"></div>
<svg id="legend" width="280" height="80"></svg>

注意:您使用的是过时版本的 D3.js,并且您的代码似乎杂乱无章。为简单的条形图创建更有组织、更高效的代码还有改进的空间。

© www.soinside.com 2019 - 2024. All rights reserved.