使用比特币 WebSocket 在 d3.js 中创建一个实时变化的矩形
Creating a real time changing rectangle in d3.js with a bitcoin WebSocket
我可以访问比特币 websocket,它每分钟都会给我提供比特币的当前市场价格。我想创建一个矩形,该矩形动态更改为当前传递到我的 bardata 数组中的这些值。
代码如下:
<html>
<script type="text/javascript" src="js/d3.min.js"></script>
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<body>
<script>
var webSocket = new WebSocket('wss://socket.cbix.ca/index'); //creating a websocket connection to blockhain.info
webSocket.onopen = function (event) {
console.log('Websocket connection open');
};
var bardata = [];
webSocket.onmessage = function (event) {
var e = jQuery.parseJSON(event.data);
console.log(e);
var high = e.high;
console.log(high);
update();
bardata.push(high);
$('.message').prepend("<p>" + "The highest bitcoin value for this minute is: $" + high + "</p>");
}
var height = 730
, width = 1080
, barWidth = 50
, barOffset = 5;
var yScale = d3.scale.linear()
.domain([0, d3.max(bardata + 100)])
.range([0, height])
var svg = d3.select('body').append('svg')
.attr('width', width)
.attr('height', height)
.style('background', '#C9D7D6')
function update() {
svg.selectAll('rect').data(bardata)
.enter().append('rect')
.style('fill', '#C61C6F')
.attr('width', barWidth)
.attr('height', function (d) {
return yScale(d);
})
.attr('x', function (d, i) {
return i * (barWidth + barOffset);
})
.attr('y', function (d) {
return height - yScale(d);
}).transition()
.attr('height', function (d) {
return yScale(d);
})
.attr('y', function (d) {
return height - yScale(d);
})
.delay(function (d, i) {
return i * 20;
})
.duration(1000)
.ease('elastic')
}
</script>
<div class="message">
</div>
</body>
</html>
然而,当我 运行 这段代码时,每次都会创建一个新柱。我知道这是由于 .onmessage
函数再次更新后,更新函数会重新绘制所有内容。我想知道是否有另一种方法可以解决这个问题,比如使用 AJAX 之类的?如果能提供帮助,我们将不胜感激。
您面临的问题是您的 update
函数只有一个 "enter" 选项。在这种情况下,预期的行为是只有 1 个不变的栏(因为 "enter" 选择从第二次开始为空)。但是当您将值推送到 barData
时,此 barData
数组的长度正在增加,并且您看到的条形图是新的 "enter" 选择。
因此,第一个更改是仅使用 barData
的 last 值,而不是整个数组。
第二个更改是编写正确的输入和更新选择。这是你应该做的。一、绑定数据:
var rect = svg.selectAll("rect")
.data([data]);
然后,创建您的 "enter" 选择:
rect.enter()
.append("rect").attr("x", 0)
.attr("y", 25)
.attr("height", 50)
.attr("width", d => scale(d))
.attr("fill", "#C61C6F");
此 "enter" 选择仅在您第一次调用 update
时有效。从第二次开始,您将只更改现有栏:
rect.transition()
.duration(200)
.ease('elastic')
.attr("width", d => scale(d));
这是一个演示:
setInterval(() => {
var data = ~~(Math.random() * 100)+1;
update(data);
}, 2000);
var svg = d3.select("#svg")
.append("svg")
.attr("width", 300)
.attr("height", 100);
var text = d3.select("#text");
var scale = d3.scale.linear()
.range([0, 300])
.domain([0, 100]);
update(50);
function update(data) {
var rect = svg.selectAll("rect")
.data([data]);
rect.enter()
.append("rect").attr("x", 0)
.attr("y", 25)
.attr("height", 50)
.attr("width", d => scale(d))
.attr("fill", "#C61C6F");
rect.transition().duration(500).ease('elastic').attr("width", d => scale(d));
text.text("The highest bitcoin value for this minute is: $" + data)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="text"></div>
<div id="svg"></div>
我可以访问比特币 websocket,它每分钟都会给我提供比特币的当前市场价格。我想创建一个矩形,该矩形动态更改为当前传递到我的 bardata 数组中的这些值。
代码如下:
<html>
<script type="text/javascript" src="js/d3.min.js"></script>
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<body>
<script>
var webSocket = new WebSocket('wss://socket.cbix.ca/index'); //creating a websocket connection to blockhain.info
webSocket.onopen = function (event) {
console.log('Websocket connection open');
};
var bardata = [];
webSocket.onmessage = function (event) {
var e = jQuery.parseJSON(event.data);
console.log(e);
var high = e.high;
console.log(high);
update();
bardata.push(high);
$('.message').prepend("<p>" + "The highest bitcoin value for this minute is: $" + high + "</p>");
}
var height = 730
, width = 1080
, barWidth = 50
, barOffset = 5;
var yScale = d3.scale.linear()
.domain([0, d3.max(bardata + 100)])
.range([0, height])
var svg = d3.select('body').append('svg')
.attr('width', width)
.attr('height', height)
.style('background', '#C9D7D6')
function update() {
svg.selectAll('rect').data(bardata)
.enter().append('rect')
.style('fill', '#C61C6F')
.attr('width', barWidth)
.attr('height', function (d) {
return yScale(d);
})
.attr('x', function (d, i) {
return i * (barWidth + barOffset);
})
.attr('y', function (d) {
return height - yScale(d);
}).transition()
.attr('height', function (d) {
return yScale(d);
})
.attr('y', function (d) {
return height - yScale(d);
})
.delay(function (d, i) {
return i * 20;
})
.duration(1000)
.ease('elastic')
}
</script>
<div class="message">
</div>
</body>
</html>
然而,当我 运行 这段代码时,每次都会创建一个新柱。我知道这是由于 .onmessage
函数再次更新后,更新函数会重新绘制所有内容。我想知道是否有另一种方法可以解决这个问题,比如使用 AJAX 之类的?如果能提供帮助,我们将不胜感激。
您面临的问题是您的 update
函数只有一个 "enter" 选项。在这种情况下,预期的行为是只有 1 个不变的栏(因为 "enter" 选择从第二次开始为空)。但是当您将值推送到 barData
时,此 barData
数组的长度正在增加,并且您看到的条形图是新的 "enter" 选择。
因此,第一个更改是仅使用 barData
的 last 值,而不是整个数组。
第二个更改是编写正确的输入和更新选择。这是你应该做的。一、绑定数据:
var rect = svg.selectAll("rect")
.data([data]);
然后,创建您的 "enter" 选择:
rect.enter()
.append("rect").attr("x", 0)
.attr("y", 25)
.attr("height", 50)
.attr("width", d => scale(d))
.attr("fill", "#C61C6F");
此 "enter" 选择仅在您第一次调用 update
时有效。从第二次开始,您将只更改现有栏:
rect.transition()
.duration(200)
.ease('elastic')
.attr("width", d => scale(d));
这是一个演示:
setInterval(() => {
var data = ~~(Math.random() * 100)+1;
update(data);
}, 2000);
var svg = d3.select("#svg")
.append("svg")
.attr("width", 300)
.attr("height", 100);
var text = d3.select("#text");
var scale = d3.scale.linear()
.range([0, 300])
.domain([0, 100]);
update(50);
function update(data) {
var rect = svg.selectAll("rect")
.data([data]);
rect.enter()
.append("rect").attr("x", 0)
.attr("y", 25)
.attr("height", 50)
.attr("width", d => scale(d))
.attr("fill", "#C61C6F");
rect.transition().duration(500).ease('elastic').attr("width", d => scale(d));
text.text("The highest bitcoin value for this minute is: $" + data)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="text"></div>
<div id="svg"></div>