使用D3的.attr方法时,this.setAttribute不是函数

时间:2017-08-13 23:06:21

标签: javascript d3.js

我在D3中有一个条形图,我想使用自定义函数update_bars()更新条形图。每个rect元素都被赋予一个从0到9的id。该函数应该通过id选择rect然后更改width属性,但我得到“this.setAttribute”不是函数。但是,当我使用普通的旧JavaScript时,它工作正常。我已经评论了哪里出了问题。

<!DOCTYPE>
<html>
<head>
<link rel="shortcut icon" href="">
<script src="https://d3js.org/d3.v4.min.js"></script>

</head>
<body>
	
<script>

<!-- everything works fine here -->
var width = 800, barHeight = 20, height = barHeight*10;
var chart = d3.select("body")
	.append("svg")
	.attr("width", width)
	.attr("height", height); 
var init_year = 2000;

d3.json("topten.json", function(data){
	the_data = data;
	
	var bar = chart.selectAll("g")
				.data(data[init_year])
				.enter()
				.append("g")
				.attr("transform", function(d, i){
					return "translate(0," + i * barHeight + ")";
				})

				
		bar.append("rect")
			.attr("width", function(d){
				return d['articles']
			})
			.attr("height", barHeight - 1)
			.attr("id", function(d,i){ return i; } );
	
});

<!-- problem is in update_bars() -->

function update_bars(data, yr){
	
	data[yr].forEach( function(d, i){

	<!-- this d3 code gives "this.setAttribute is not a function" error -->
	
	/. d3.select(i).attr("width", d['articles']); ./
	
	<!-- this javascript works --> 
	temp = document.getElementById(i); 
	temp.setAttribute("width", d['articles']);
	});
}



</script>
</body>
</html>

2 个答案:

答案 0 :(得分:2)

首先,为了按ID进行选择,您需要在# d3.select("#myID")之前为选择器添加序号:id

但另一个问题是,您的代码是使用此行向<rec id="1">这样的单个数字的每个矩形分配.attr("id", function(d,i){ return i; } );

d3.select("#" +i)

这会导致选择器出现问题,因为您需要使用d3.select("#\\31")选择此选项,但这不会起作用。选择带有前导数字的ID非常痛苦,除非你愿意用这样的unicode代码点选择每一个:

id

(详见此处:Using querySelector with IDs that are numbers

更好的计划是为每个rect分配不同的.attr("id", function(d,i){ return "_" + i; } ); ,例如:

d3.select("#_" + i).attr()

然后您可以选择:

Public Sub btcteste()

    Dim xmlhttp As Object

    'Dim xmlhttp As New MSXML2.ServerXMLHTTP60

    Set xmlhttp = CreateObject("MSXML2.serverXMLHTTP")

    Dim myurl As String
    Dim strText As String
    Dim vSplit As Variant, v As Variant
    Dim vR() As Variant
    Dim n As Integer

    myurl = "https://api.blinktrade.com/api/v1/BRL/ticker?crypto_currency=BTC"
    xmlhttp.Open "GET", myurl, False
    xmlhttp.send
    'MsgBox (xmlhttp.responseText)
    strText = xmlhttp.responseText
    strText = Replace(strText, "}", "")
    strText = Replace(strText, "{", "")
    strText = Replace(strText, Chr(34), "")
    vSplit = Split(strText, ",")
    For Each v In vSplit
        n = n + 1
        ReDim Preserve vR(1 To 2, 1 To n)
        vR(1, n) = Trim(Split(v, ":")(0))
        vR(2, n) = Trim(Split(v, ":")(1))
    Next v
    Range("a1").Resize(n, 2) = WorksheetFunction.Transpose(vR) '<~~ this is vertical
    'Range("a1").Resize(2, n) = vR  '<~~ this is horisontal
End Sub

说了这么多,一般来说你不应该在d3中循环你的数据,而是使用这里所示的一般更新模式:https://bl.ocks.org/mbostock/3808234

答案 1 :(得分:0)

尝试修复代码段,我无法重现上述问题:

&#13;
&#13;
<!DOCTYPE>
<html>
<head>
<link rel="shortcut icon" href="">
<script src="https://d3js.org/d3.v4.min.js"></script>

</head>
<body>
	
<script>

<!-- everything works fine here -->
var width = 800, barHeight = 20, height = barHeight*10;
var chart = d3.select("body")
	.append("svg")
	.attr("width", width)
	.attr("height", height); 
var init_year = 2000;

//d3.json("topten.json", function(data){
//	the_data = data;
	
  var data = { 
  2000: [
    { articles: 10 },
    { articles: 35 },
    { articles: 47 },
    { articles: 2 },
    { articles: 87 },
  ],
  2001: [
    { articles: 5 },
    { articles: 65 },
    { articles: 23 },
    { articles: 76 },
    { articles: 18 },
  ],
  };
  
	var bar = chart.selectAll("g")
				.data(data[init_year])
				.enter()
				.append("g")
				.attr("transform", function(d, i){
					return "translate(0," + i * barHeight + ")";
				})

				
		bar.append("rect")
			.attr("width", function(d){
				return d['articles']
			})
			.attr("height", barHeight - 1)
			.attr("id", function(d,i){ return i; } );
	
//});

<!-- problem is in update_bars() -->

function update_bars(data, yr){
	
	data[yr].forEach( function(d, i){

	<!-- this d3 code gives "this.setAttribute is not a function" error -->
	
	/. d3.select(i).attr("width", d['articles']); ./
	
	<!-- this javascript works --> 
	temp = document.getElementById(i); 
	temp.setAttribute("width", d['articles']);
	});
}

   setTimeout( update_bars, 1000, data, 2001 );



</script>
</body>
</html>
&#13;
&#13;
&#13;

  • 我已经用一些与您的代码匹配的明显合适的数据替换了从JSON文件中获取数据的代码。
  • 然后我添加了一些实际调用update_bars()的代码。

请参阅代码段。它正在工作。所以这个问题似乎与提供意外/不匹配数据格式的topten.json有关,或者与错误时序调用update_bars()有关。在获取JSON文件之前。