复制 D3.js 仪表小部件

Duplicating a D3.js gauge widget

我在尝试实现 this widget found in Codepen 时遇到了一些麻烦,该 this widget found in Codepen 在以下 div:

中加载
<div id="action"></div>

问题是我想在同一页面使用两个以上,但是当我复制代码时,它发生 what you can see in this snippet 实现为两个不同的 divs:

<div id="action"></div>
<div id="action2"></div>

如您所见,第二个小部件将不起作用,正如我所做的那样,您可能认为这与彼此重叠的变量有关,但是 如果您切换 divs 的顺序就可以了!那么它就没有意义了,如果变量重叠那么它总是会这样做,无论哪个小部件先出现。

所以,也许您在想:如果您已经找到了解决方案,那问题是什么?好吧,我需要知道问题出在哪里,因为它们中的每一个都代表从数据库中获取的一些数据,并且可以在dividually 中修改和更新它们以将新配置的数据保存回数据库,所以当我以错误的顺序刷新其中一个,其中一个小部件将永远无法工作,所以现在我必须以正确的顺序刷新它们,直到我发现发生了什么,事实上它们将超过两个同一个页面,所以刷新所有页面以避免崩溃是低效的。

试图解决这个问题,我认为这与定义到函数中的内部 d3.js 变量无关( var t,e,n,r,a,l,s,i,u, o,c,d,g ... ), 因为它们是局部范围的,所以它没有意义。

由于代码被缩小了,代码很难阅读,我用了一个 unminifier 来更清楚地阅读它,但无论如何我对 D3.js...

不太了解

有什么想法吗?提前致谢。

问题在于,在 render 函数中,在 pattern 之后,规范代码做得非常好,但在 update 函数中却失去了它。它开始执行全局 d3.select,它只更新它选择的那些元素的 first 实例。所以修复是在更新函数本身,保留对你正在操作的 svg 元素的引用,并对其进行进一步的选择。

此外,您只需定义一次 guage 函数,您应该为仪表的每个实例使用不同的变量。

请参阅下面的评论,了解我如何更改 guage 函数:

var gauge = function() {
    // added "svg"
    var svg, t, e, n, r, a, l, s, i, u, o, c, d, g, p, f, h, m, v, y, x, A, M, _, R, b, I, P, w, T = {},
        C = 120,
        k = d3.scale.linear().domain([0, C]).range([Math.PI, 2 * Math.PI]),
        z = ["rgb(235,7,27)", "rgb(242,166,0)", "rgb(139,224,91)"],
        W = 0,
        B = 50,
        E = !0,
        G = 100,
        H = 1.57,
        L = 10,
        j = !0,
        q = !0,
        D = 0,
        F = "elastic",
        J = 1e3,
        K = function(t, e) {
            var n = e ? e : 0;
            return g = 0 + (R - n) * Math.cos(t)
        },
        N = function(t, e) {
            var n = e ? e : 0;
            return p = 0 + (R - n) * Math.sin(t)
        },
        O = function() {
            return f = 0 + ((A - x) / 2 + x) * Math.cos(k(B))
        },
        Q = function() {
            return h = 0 + ((A - x) / 2 + x) * Math.sin(k(B))
        },
        S = function(t, e) {
            e.attr("points", "" + K(P(t), 2 * L) + "," + N(P(t), 2 * L) + " " + K(I(t)) + "," + N(I(t)) + " " + K(w(t), 2 * L) + "," + N(w(t), 2 * L) + " ")
        };
    return T.render = function(n) {
        var i = d3.scale.linear().domain([0, C]).range([-H, H]);
        r = k(D), a = k(D - L / 2), l = k(D + L / 2), s = d3.select("#" + _target.id).append("svg").attr("class", "pie").attr("height", e).attr("width", t), m = d3.select("#" + _target.id).append("div").attr("transform", "translate(" + M + "," + _ + ")").attr("class", "gaugeTT"), v = m.append("div").attr("class", "col1"), y = m.append("div").attr("class", "col2");
        var u = [{
                startAngle: -H,
                endAngle: H
            }],
            f = [{
                startAngle: -H,
                endAngle: 0
            }],
            h = [{
                startAngle: -H,
                endAngle: i(B)
            }];
        [{
            startAngle: i(G) - .03,
            endAngle: i(G)
        }];
        d = A - x;
        var I = d3.svg.arc().outerRadius(A).innerRadius(x);
        d3.svg.arc().outerRadius(A - 1).innerRadius(x + 1);
        o = d3.svg.arc().outerRadius(x + .3 * d).innerRadius(x), c = d3.svg.arc().outerRadius(A).innerRadius(A - .7 * d);
        var P = d3.svg.arc().outerRadius(A + 5).innerRadius(A - .7 * d),
            w = s.append("g");
            svg = w;
        w.attr("transform", "translate(" + M + "," + _ + ")").selectAll("path.bg").data(u).enter().append("path").attr("class", "bg").attr("fill", "rgb(236,229,240)").attr("d", function(t, e) {
            return I(t, e)
        }), w.attr("transform", "translate(" + M + "," + _ + ")").selectAll("path.average").data(h).enter().append("path").attr("class", "average").attr("fill", "rgb(74,0,98)").attr("d", function(t, e) {
            return o(t, e)
        }), w.attr("transform", "translate(" + M + "," + _ + ")").selectAll("path.actual").data(f).enter().append("path").attr("class", "actual").attr("d", function(t, e) {
            return c(t, e)
        }), w.append("line").attr("class", "needle-line").attr("x1", 0).attr("y1", 0).attr("x2", function() {
            return g = 0 + R * Math.cos(r)
        }).attr("y2", function() {
            return p = 0 + R * Math.sin(r)
        }), q === !0 && w.append("polygon").attr("class", "needleTip").attr("fill", b), j === !0 && (w.append("circle").attr("cx", 0).attr("cy", 0).attr("r", 45), w.select(".needle-line").style("stroke", b).style("stroke-width", 1), w.select("circle").style("fill", b)), w.append("line").attr("class", "goal-post").attr("x1", function() {
            var t = 0 + x * Math.cos(k(G));
            return t
        }).attr("y1", function() {
            var t = 0 + x * Math.sin(k(G));
            return t
        }).attr("x2", function() {
            var t = 0 + (A + 10) * Math.cos(k(G));
            return t
        }).attr("y2", function() {
            var t = 0 + (A + 10) * Math.sin(k(G));
            return t
        }).style("stroke", "rgb(82,174,201)").style("stroke-width", 5), E === !1 && w.append("circle").attr("class", "average").attr("cx", function() {
            return O(B)
        }).attr("cy", function() {
            return Q(B)
        }).attr("r", 8).style("opacity", .75).style("fill", "rgb(250,250,250)"), w.append("text").attr("class", "centerPercentage").style("fill", "#555").style("font-size", "26").attr("text-anchor", "middle").attr("x", 0).attr("y", 0).attr("dy", ".35em").text("0%"), w.append("text").attr("class", "min-range").style("fill", "#555").style("font-size", "18").attr("text-anchor", "middle").attr("x", -65).attr("y", 75).attr("dy", ".35em").text("0"), w.append("text").attr("class", "max-range").style("fill", "#555").style("font-size", "18").attr("text-anchor", "middle").attr("x", 65).attr("y", 75).attr("dy", ".35em").text(C), w.select(".actual").on("mouseover", function() {
            d3.select(this).transition().duration(400).ease(F).attr("d", function(t) {
                return P(t)
            }), m.transition().style("opacity", "1"), w.on("mousemove", function(t) {
                var e = d3.mouse(this),
                    n = e[0] + 200 + "px",
                    r = e[1] + 200 + "px";
                console.log(e), m.style("top", r), m.style("left", n)
            })
        }), w.select(".actual").on("mouseout", function() {
            d3.select(this).transition().duration(400).ease(F).attr("d", function(t) {
                return c(t)
            }), m.transition().style("opacity", "0"), w.on("mousemove", null)
        })
    }, T.update = function(t) {
        u = W, W = t, v.html("<p>Acutal   " + W + "</p><p>Goal  " + G + "</p><p>Average  " + B + "</p>");
        var e = d3.scale.linear().domain([0, 1]).range([u, t]),
            n = d3.scale.linear().domain([0, 60, 120]).range(z),
            s = d3.scale.linear().domain([0, C]).range([-H, H]),
            i = [{
                startAngle: -H,
                endAngle: s(t)
            }];
        d3.svg.arc().outerRadius(A).innerRadius(x);
        // selection on svg
        svg.selectAll("path.actual").data(i).transition().ease(F).duration(J).attrTween("d", function(t) {
            var r = this.__current__;
            r || (r = {
                startAngle: -H,
                endAngle: -H
            });
            var a = d3.interpolate(r, t);
            return this.__current__ = a(1),
                function(t) {
                    return svg.attr("fill", function(r) {
                        return n(e(t))
                    }), c(a(t))
                }
        });
        var o = r,
            d = a,
            g = l;
        r = k(t), _angleC = k(B), a = k(t - L / 2), l = k(t + L / 2), I = d3.interpolate(o, r), _interpolateC = d3.interpolate(o, _angleC), P = d3.interpolate(d, a), w = d3.interpolate(g, l);
        // selections based on svg
        var p = svg.select(".centerPercentage"),
            f = svg.select("polygon");
        svg.select(".needle-line").transition().ease(F).duration(J).attrTween("x2", function() {
            return function(t) {
                return q === !0 && (S(t, f), p.text(parseInt(e(t)) + "%")), K(I(t))
            }
        }).attrTween("y2", function() {
            return function(t) {
                return N(I(t))
            }
        })
    }, T.width = function(e) {
        return arguments.length ? (t = e, T) : t
    }, T.height = function(t) {
        return arguments.length ? (e = t, T) : e
    }, T.needleWidth = function(t) {
        return arguments.length ? (L = t / 2, T) : L
    }, T.spread = function(t) {
        return arguments.length ? (t < Math.PI / 2 && (t = Math.PI / 2), n = t - Math.PI / 2, H = t, k = d3.scale.linear().domain([0, C]).range([Math.PI - n, 2 * Math.PI + n]), T) : H
    }, T.colors = function(t) {
        return arguments.length ? (i = t, T) : i
    }, T.needleColor = function(t) {
        return arguments.length ? (b = t, T) : b
    }, T.needleTip = function(t) {
        return arguments.length ? (q = t, T) : q
    }, T.target = function(n) {
        return arguments.length ? (_target = document.getElementById(n), t = _target.offsetWidth, e = _target.offsetHeight, M = t / 2, _ = e / 1.5, T) : _target
    }, T.innerRadius = function(t) {
        return arguments.length ? (x = t, T) : x
    }, T.outerRadius = function(t) {
        return arguments.length ? (A = t, R = t, T) : A
    }, T.radius = function(t) {
        return arguments.length ? (R = t, T) : R
    }, T.renderLine = function(t) {
        return arguments.length ? (j = t, T) : j
    }, T.easing = function(t) {
        return arguments.length ? (F = t, T) : F
    }, T.goal = function(t) {
        return arguments.length ? (G = t, T) : G
    }, T.average = function(t) {
        return arguments.length ? (B = t, T) : B
    }, T.duration = function(t) {
        return arguments.length ? (J = t, T) : J
    }, T
};

custom=gauge().target("action").outerRadius(120).innerRadius(78).radius(65).spread(2.2).goal(80).average(75).easing("linear").duration(2e3).needleWidth(23).needleColor("rgb(230,222,236)");

custom.render();
custom.update(110);

window.setTimeout(function() {
  custom.update(120);
}, 4000);

custom2=gauge().target("action2").outerRadius(120).innerRadius(78).radius(65).spread(2.2).goal(80).average(75).easing("linear").duration(2e3).needleWidth(23).needleColor("rgb(230,222,236)");

custom2.render();
custom2.update(70);

window.setTimeout(function() {
  custom2.update(68);
}, 4000);
*{
  box-sizing: border-box;
}

#action{
  width: 600px;
  height: 400px;
  margin-left: 100px;
  color: #ffffff;
  font-family: sans-serif;
  font-weight: 400;
  text-align: center;
  font-size: 18px;
  border: solid 1px #eee;
  position: absolute;
}

#action2{
  top: 400px;
  width: 600px;
  height: 400px;
  margin-left: 100px;
  color: #ffffff;
  font-family: sans-serif;
  font-weight: 400;
  text-align: center;
  font-size: 18px;
  border: solid 1px #eee;
  position: absolute;
}

.gaugeTT{
  width: 125px;
  background-color: rgb(253,253,253);
  font-size: 0.7em;
  text-align: left;
  color: #777;
  opacity: 0;
  position: absolute;
  top: 0;
  left: 15px;
  border: solid 1px #ccc;
}
.gaugeTT p{
  margin: 0;
  padding: 0;
  display: block;
}
.gaugeTT .col1{
  width: 100%;
  text-align: left;
}
<script src="http://d3js.org/d3.v3.js"></script>
<div id="action"></div>
<div id="action2"></div>