d3.js测量针随动态数据旋转

d3.js gauge needle rotate with dynamic data

本文关键字:动态 数据 旋转 js 测量 d3      更新时间:2023-09-26

我是d3.js的新手,我正在尝试用针制作一个量规。

var margin = { top: 0, left: 0, right: 0, bottom: 0 },
    width = 800,
    height = 600;
var maxVal = 12;
var svg = d3.select(".container").append("svg")
   .attr("width", width)
   .attr("height", height)
   .append("g")
   .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var bgArc = d3.svg.arc()
    .outerRadius(100)
    .innerRadius(10)
    .startAngle(0)
    .endAngle(2 * Math.PI);
var needleScale = d3.scale.linear().domain([0, 360]).range([0, 180]);
//draw donut
var wrap = svg.append("g")
    .attr("class", "wrap")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
wrap.append('g')
    .attr('class', 'donut')
    .append("path")
    .attr("d", bgArc)
    .style("fill", "white")
    .style("stroke-width", 2)
    .style("stroke", "white");
wrap.append('g')
    .attr('class', 'outerMostCircle')
    .append("circle")
    .attr("cx", 0)
    .attr("cy", 0)
    .attr("r", 108)
    .style("stroke", "white")
    .style("stroke-width", 2)
    .style("fill", "transparent");
//draw needle
var needle = wrap.append('g')
    .attr("class", "needle")
    .append("line")
    .attr("x1", 0)
    .attr("y1", 0)
    .attr("x2", 0)
    .attr("y2", -102)
    .attr("stroke-width", 6)
    .attr("stroke", "coral");
// add text
var text = svg.append("g")
    .attr("class", "text")
    .append("text")
    .attr("transform", "translate(" + width / 2.2 + "," + height / 4 + ")")
    .attr("font-size", "2em");
setInterval(function() {
    curVal = Math.floor(Math.random()* 12);
        d3.select('.needle').select('line')
            .transition()
            .duration(1000)
            .attrTween('transform', function() {
        return tweenNeedle(curVal, maxVal);
        });
    text.datum(curVal).text(function(d) {
        return d + " m/s";
    });
}, 1500);
function tweenNeedle(data, max) {
    return d3.interpolateString("rotate(0)", "rotate(" + (data / max * 360) + ")");
}
function getEndAngle(data, max) {
    return data / max * 2 * Math.PI;
}
wrap.append('g')
    .attr('class', 'outerCircle')
    .append("circle")
    .attr("cx", 0)
    .attr("cy", 0)
    .attr("r", 20)
    .attr("fill", "pink");
wrap.append('g')
    .attr('class', 'innerCircle')
    .append("circle")
    .attr("cx", 0)
    .attr("cy", 0)
    .attr("r", 10)
    .attr("fill", "#666");

问题是,每当数据发生变化时,指针总是从开始旋转,而不是从最后一个位置旋转。

我试着记住针的最后一个位置/角度,但我似乎记不清了。。。

我该怎么办才能解决这个问题?

以下是我迄今为止所做的工作。https://jsfiddle.net/pq7t2obc/8/提前感谢!

@Robert的评论正是这么说的。这是js小提琴。

只需存储旧的旋转,并使用它将其转换到新的计算位置

// Define global variable
var lastRotationAngle = "rotate(0)";
// Calculate new tween and return InterpolateString into variable.
// inside .attrTween('transform', function() {
var interpolateString = tweenNeedle(lastRotationAngle, curVal, maxVal);
// Update lastRotationAngle 
lastRotationAngle = "rotate(" + (curVal / maxVal * 360) + ")";
// Return the InterpolateString
return interpolateString;

https://jsfiddle.net/pq7t2obc/8/

Tween针新功能:

function tweenNeedle( oldRotation, data, max) {
    return d3.interpolateString(oldRotation, "rotate(" + (data / max * 360) + ")");
}

首先定义一个这样的变量:

var angle = 0;

然后在tweetNedle函数中使用旧值,如下所示:

function tweenNeedle(data, max) {
    var prevAngle = angle;//get the old angle
        angle = (data / max * 360);//update it with the latest angle.
        return d3.interpolateString("rotate(" +prevAngle+")", "rotate(" + (data / max * 360) + ")");
}

此处的工作代码