如何从 d3.js 实现图形的 html 变量 [英] How to implement the html variables for a graphic from d3.js

查看:28
本文介绍了如何从 d3.js 实现图形的 html 变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在 d3.js 中做一个圆环图.基本上这个想法是写 3 个输入,它应该以这种方式显示:

不幸的是我做不到,我不确定如何在javascript代码中实现变量fuel、fuel 2和fuel 3,我不确定它是必须在html代码中还是在javascript代码中指明.提前致谢.

<代码><元字符集=utf-8"><!-- 加载 d3.js --><script src=https://d3js.org/d3.v4.js"></script><div><输入类型=数字"id=燃料"style="text-align:center">

<div><输入类型=数字"id=燃料2"style="text-align:center">

<div><输入类型=数字"id=燃料3"style="text-align:center">

<!-- 创建一个 div,图形将在其中发生--><div id="my_dataviz"></div>

<代码>var Fuel = document.getElementById('fuel');var Fuel2 = document.getElementById('fuel2');var Fuel3 = document.getElementById('fuel3');//设置图形的尺寸和边距变量宽度 = 450高度 = 450保证金 = 40//饼图的半径是宽度的一半或高度的一半(最小的).我减去了一点保证金.var 半径 = Math.min(width, height)/2 - 边距//将 svg 对象附加到名为my_dataviz"的 divvar svg = d3.select(#my_dataviz").append("svg").attr(宽度",宽度).attr(高度",高度).append("g").attr("transform", "translate(" + width/2 + "," + height/2 + ")");//创建虚拟数据无功数据= {燃料,燃料2,燃料3}//设置色阶var 颜色 = d3.scaleOrdinal().域(数据).range([#98abc5", #8a89a6", #7b6888"])//计算每个组在饼图上的位置:var pie = d3.pie().value(function(d) {return d.value; })var data_ready = pie(d3.entries(data))//构建饼图:基本上,饼图的每个部分都是我们使用 arc 函数构建的路径.svg.selectAll('随便').data(data_ready).进入().append('路径').attr('d', d3.arc().innerRadius(100)//这是甜甜圈洞的大小.outerRadius(半径)).attr('fill', function(d){ return(color(d.data.key)) }).attr(中风",黑色").style("笔画宽度", "2px").style(不透明度", 0.7)``

解决方案

这个答案使用 d3v6

方法一

您可以使用数据数组来表示您的输入框和切片.这可能具有优势,尤其是在从数据源加载图表时.尝试类似:

//表示切片的日期:变量数据 = [{名称:A",值:1},{名称:B",值:1},{名称:B",值:1}];//根据数据创建字段:d3.select(#my_inputs").selectAll(空).data(数据).进入().append(输入").attr("value",function(d) { return d.value; }).on("keyup", function(_,d) {d.value = d3.select(this).node().value;更新();})

这里我们创建了一个数据数组来表示我们的输入字段和切片.我们将数据绑定到输入字段,并在每次字段值变化时更新绑定数据.

现在我们可以在每次值改变时更新图表,并且最初使用如下函数:

函数更新(){var pie = d3.pie().value(function(d) {return d.value; })(data);svg.selectAll('路径').数据(饼图).join('路径').attr(.....}

我在下面做了一些更改,因为我们需要注意,如果切片数量不变,则在第一次绘制切片后,输入选择将为空.所以我使用 selection.join() 虽然 selection.merge() 单独处理更新和输入也很好.

这是两者的结合:

var width = 450高度 = 450保证金 = 40var 半径 = Math.min(width, height)/2 - 边距//代表切片的日期:变量数据 = [{名称:A",值:1},{名称:B",值:1},{名称:C",值:1}];//根据数据创建字段:d3.select("#my_inputs").selectAll(空).data(数据).进入().append("输入").attr("value",function(d) { return d.value; }).on("keyup", function(_,d) {d.value = d3.select(this).node().value;更新();})//创建一个 SVGvar svg = d3.select("#my_dataviz").append("svg").attr("宽度", 宽度).attr("高度", 高度).append("g").attr("transform", "translate(" + width/2 + "," + height/2 + ")");//设置色阶var 颜色 = d3.scaleOrdinal().domain(data.map(function(d) { return d.name; })).range(["#98abc5", "#8a89a6", "#7b6888"])更新();函数更新(){//计算每个组在饼图上的位置:var pie = d3.pie().value(function(d) {return d.value; })(data);//构建饼图:基本上,饼图的每个部分都是我们使用 arc 函数构建的路径.svg.selectAll('路径').数据(饼图).join('路径').attr('d', d3.arc().innerRadius(100).outerRadius(半径)).attr(中风",黑色").style("笔画宽度", "2px").style("fill", function(d) { return color(d.data.name);})}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.1.0/d3.min.js"></script><div id="my_inputs"></div><div id="my_dataviz"></div>

更进一步,通过一些调整,创建一个用户界面,用户可以在其中动态地从饼图中添加/删除字段/切片,这并不困难,因为切片和字段都在数据数组中表示.

方法 2

或者,如果您想对输入字段进行硬编码,无论出于何种原因,您都可以一次选择它们并从中创建一个数据数组:

var data = d3.selectAll("input").nodes();

然后您可以像使用 D3 的任何其他数据数组一样使用它.这不是一个选择, .nodes() 返回一个元素数组.您需要使用 .nodes,因为您需要一个数组来正确使用输入/更新循环,而 D3 选择不是数组.

我们像这样添加事件监听器:

d3.selectAll(输入").on("keyup", function() {更新();})

这更符合你原来的样子:

var width = 450高度 = 450保证金 = 40var 半径 = Math.min(width, height)/2 - 边距//添加事件监听器d3.selectAll("输入").on("keyup", function() {更新();})//创建一个 SVGvar svg = d3.select("#my_dataviz").append("svg").attr("宽度", 宽度).attr("高度", 高度).append("g").attr("transform", "translate(" + width/2 + "," + height/2 + ")");//设置色阶var color =["#98abc5", "#8a89a6", "#7b6888"];更新();函数更新(){var data = d3.selectAll("input").nodes();var pie = d3.pie().value(function(d) {return d.value; })(data);svg.selectAll('路径').数据(饼图).join('路径').attr('d', d3.arc().innerRadius(100).outerRadius(半径)).attr('fill', function(d,i){ return color[i] }).attr(中风",黑色").style("笔画宽度", "2px")}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.1.0/d3.min.js"></script><div id="my_inputs"><input value="1"></input><input value="1"></input><input value="1"></input>

<div id="my_dataviz"></div>

I would like to do a donut-chart in d3.js. Basically the idea would be to write 3 inputs and it should be displayed this way:

Unfortunatelly I cannot make it, I am not sure about how to implement the variables fuel, fuel 2 and fuel 3 in the javascript code, I am not sure wether it has to be indicated in the html code or in the javascript code. Thanks in advance.


<meta charset="utf-8">

<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>

<div>
        <input type="number" id="fuel" style="text-align:center"> 
</div>  

<div>
        <input type="number" id="fuel2" style="text-align:center"> 
</div>  

<div>
        <input type="number" id="fuel3" style="text-align:center"> 
</div>  




<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>


var fuel = document.getElementById('fuel');
var fuel2 = document.getElementById('fuel2');
var fuel3 = document.getElementById('fuel3');



// set the dimensions and margins of the graph
var width = 450
    height = 450
    margin = 40

// The radius of the pieplot is half the width or half the height (smallest one). I subtract a bit of margin.
var radius = Math.min(width, height) / 2 - margin

// append the svg object to the div called 'my_dataviz'
var svg = d3.select("#my_dataviz")
  .append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

// Create dummy data
var data = {fuel,fuel2,fuel3}

// set the color scale
var color = d3.scaleOrdinal()
  .domain(data)
  .range(["#98abc5", "#8a89a6", "#7b6888"])

// Compute the position of each group on the pie:
var pie = d3.pie()
  .value(function(d) {return d.value; })
var data_ready = pie(d3.entries(data))

// Build the pie chart: Basically, each part of the pie is a path that we build using the arc function.
svg
  .selectAll('whatever')
  .data(data_ready)
  .enter()
  .append('path')
  .attr('d', d3.arc()
    .innerRadius(100)         // This is the size of the donut hole
    .outerRadius(radius)
  )
  .attr('fill', function(d){ return(color(d.data.key)) })
  .attr("stroke", "black")
  .style("stroke-width", "2px")
  .style("opacity", 0.7)
``

解决方案

This answer uses d3v6

Approach 1

You could use a data array to represent both your input boxes and your slices. This can have advantages, especially if loading the chart from a data source. Try something like:

// Date representing your slices:
var data = [
  {name:"A",value:1},
  {name:"B",value:1},
  {name:"B",value:1}
];

// Create the fields based on the data:
d3.select("#my_inputs")
  .selectAll(null)
  .data(data)
  .enter()
  .append("input")
  .attr("value",function(d) { return d.value; })
  .on("keyup", function(_,d) { 
    d.value = d3.select(this).node().value;
    update();
  })

Here we create an data array to represent our input fields and the slices. We bind the data to the input fields and update the bound data every time the field value changes.

Now we can update the chart each time a value changes, and initially, with a function like:

function update() {

  var pie = d3.pie()
    .value(function(d) {return d.value; })(data);

  svg
   .selectAll('path')
    .data(pie)
    .join('path') 
    .attr(.....
    
}

I've made a few changes below as we need to be mindful that if the number of slices is constant, the enter selection will be empty after drawing the slices the first time. So I use selection.join() though selection.merge() with separate treatment of update and enter is also fine.

Here's those two together:

var width = 450
    height = 450
    margin = 40

var radius = Math.min(width, height) / 2 - margin

// Date representing your slices:
var data = [
  {name:"A",value:1},
  {name:"B",value:1},
  {name:"C",value:1}
];

// Create the fields based on the data:
d3.select("#my_inputs")
  .selectAll(null)
  .data(data)
  .enter()
  .append("input")
  .attr("value",function(d) { return d.value; })
  .on("keyup", function(_,d) { 
    d.value = d3.select(this).node().value;
    update();
  })

// Create an SVG
var svg = d3.select("#my_dataviz")
  .append("svg")
  .attr("width", width)
  .attr("height", height)
  .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

// set the color scale
var color = d3.scaleOrdinal()
  .domain(data.map(function(d) { return d.name; }))
  .range(["#98abc5", "#8a89a6", "#7b6888"])

update();

function update() {

  // Compute the position of each group on the pie:
  var pie = d3.pie()
    .value(function(d) {return d.value; })(data);


  // Build the pie chart: Basically, each part of the pie is a path that we build using the arc function.
  svg
   .selectAll('path')
    .data(pie)
    .join('path') 
    .attr('d', d3.arc()
      .innerRadius(100)        
      .outerRadius(radius)
    )
    .attr("stroke", "black")
    .style("stroke-width", "2px")
    .style("fill", function(d) { return color(d.data.name);})
    
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.1.0/d3.min.js"></script>
<div id="my_inputs"></div>
<div id="my_dataviz"></div>

Going further, with some tweaking, creating a user interface where the user can dynamically add/remove fields/slices from the pie chart is not difficult as the slices and fields are both represented in the data array.

Approach 2

Alternatively, if you want to have the input fields hard coded for whatever reason, you could select them all at once and make a data array out of them:

var data = d3.selectAll("input").nodes();

You can then use this like any other data array with D3. This is not a selection, .nodes() returns an array of elements. You need to use .nodes as you need an array to use the enter/update cycle correctly and D3 selections are not arrays.

We add the event listener like so:

d3.selectAll("input")
  .on("keyup", function() { 
    update();
  })

This is a bit more in line with what you had originally:

var width = 450
    height = 450
    margin = 40

var radius = Math.min(width, height) / 2 - margin

// Add an event listener
d3.selectAll("input")
  .on("keyup", function() { 
    update();
  })

// Create an SVG
var svg = d3.select("#my_dataviz")
  .append("svg")
  .attr("width", width)
  .attr("height", height)
  .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

// set the color scale
var color =["#98abc5", "#8a89a6", "#7b6888"];

update();

function update() {

  var data = d3.selectAll("input").nodes();

  var pie = d3.pie()
    .value(function(d) {return d.value; })(data);

  svg
   .selectAll('path')
    .data(pie)
    .join('path') 
    .attr('d', d3.arc()
      .innerRadius(100)        
      .outerRadius(radius)
    )
    .attr('fill', function(d,i){ return color[i] })
    .attr("stroke", "black")
    .style("stroke-width", "2px")
    
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.1.0/d3.min.js"></script>
<div id="my_inputs">
<input value="1"></input>
<input value="1"></input>
<input value="1"></input>
</div>
<div id="my_dataviz"></div>

这篇关于如何从 d3.js 实现图形的 html 变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆