我正在尝试在D3中开发自定义形状,但是我有点绿色的Javascript智慧,并且不确定D3-Shapes库在幕后的作用。
尤其是,我不确定symbol.js中的default
函数在做什么或如何使用。从一点点JS中,我确实知道它似乎是在描述原型或可能的类。可能有人可以使用symbol.type类/函数来注册其他形状,但是我不确定应该如何称呼它,例如var symbol = symbol("SYMBOL").type(SYMBOL)
或可能的var SYMBOL = symbol().type(SYMBOL)
或其他组合。 Issue 23讨论了形状库与原始实现之间的变化,我认为该实现否定了SO: answer。我还搜寻了D3-Symbol-Extra的线索,但没有骰子。
到目前为止,对于超椭圆,我具有以下形状定义,该形状与D3 Shapes库中的符号定义匹配,例如circle,diamond等
var superellipse = {
draw : function (context, size) {
var w = size;
var h = size;
var n = 2/4;
context.moveTo(w/2*Math.sign(Math.cos( 0/9*2*Math.PI))*Math.pow(Math.abs(Math.cos( 0/9*2*Math.PI)), n), h/2*Math.sign(Math.sin( 0/9*2*Math.PI))*Math.pow(Math.abs(Math.sin( 0/9*2*Math.PI)), n));
context.lineTo(w/2*Math.sign(Math.cos( 1/9*2*Math.PI))*Math.pow(Math.abs(Math.cos( 1/9*2*Math.PI)), n), h/2*Math.sign(Math.sin( 1/9*2*Math.PI))*Math.pow(Math.abs(Math.sin( 1/9*2*Math.PI)), n));
context.lineTo(w/2*Math.sign(Math.cos( 2/9*2*Math.PI))*Math.pow(Math.abs(Math.cos( 2/9*2*Math.PI)), n), h/2*Math.sign(Math.sin( 2/9*2*Math.PI))*Math.pow(Math.abs(Math.sin( 2/9*2*Math.PI)), n));
context.lineTo(w/2*Math.sign(Math.cos( 3/9*2*Math.PI))*Math.pow(Math.abs(Math.cos( 3/9*2*Math.PI)), n), h/2*Math.sign(Math.sin( 3/9*2*Math.PI))*Math.pow(Math.abs(Math.sin( 3/9*2*Math.PI)), n));
context.lineTo(w/2*Math.sign(Math.cos( 4/9*2*Math.PI))*Math.pow(Math.abs(Math.cos( 4/9*2*Math.PI)), n), h/2*Math.sign(Math.sin( 4/9*2*Math.PI))*Math.pow(Math.abs(Math.sin( 4/9*2*Math.PI)), n));
context.lineTo(w/2*Math.sign(Math.cos( 5/9*2*Math.PI))*Math.pow(Math.abs(Math.cos( 5/9*2*Math.PI)), n), h/2*Math.sign(Math.sin( 5/9*2*Math.PI))*Math.pow(Math.abs(Math.sin( 5/9*2*Math.PI)), n));
context.lineTo(w/2*Math.sign(Math.cos( 6/9*2*Math.PI))*Math.pow(Math.abs(Math.cos( 6/9*2*Math.PI)), n), h/2*Math.sign(Math.sin( 6/9*2*Math.PI))*Math.pow(Math.abs(Math.sin( 6/9*2*Math.PI)), n));
context.lineTo(w/2*Math.sign(Math.cos( 7/9*2*Math.PI))*Math.pow(Math.abs(Math.cos( 7/9*2*Math.PI)), n), h/2*Math.sign(Math.sin( 7/9*2*Math.PI))*Math.pow(Math.abs(Math.sin( 7/9*2*Math.PI)), n));
context.lineTo(w/2*Math.sign(Math.cos( 8/9*2*Math.PI))*Math.pow(Math.abs(Math.cos( 8/9*2*Math.PI)), n), h/2*Math.sign(Math.sin( 8/9*2*Math.PI))*Math.pow(Math.abs(Math.sin( 8/9*2*Math.PI)), n));
context.lineTo(w/2*Math.sign(Math.cos( 9/9*2*Math.PI))*Math.pow(Math.abs(Math.cos( 9/9*2*Math.PI)), n), h/2*Math.sign(Math.sin( 9/9*2*Math.PI))*Math.pow(Math.abs(Math.sin( 9/9*2*Math.PI)), n));
context.closePath();
}
};
我可以根据默认尺寸绘制形状,但是我无法通过设置r
属性来调整尺寸。在这种情况下,可以通过设置n
,h
和w
属性来实现。
var svg = d3.select("svg")
.attr("width", 500)
.attr("height", 500);
function visualize(json) {
var nodes = svg.selectAll("g nodetext")
.data(json.nodes);
var entryPoint = nodes.enter()
.append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + ",80)"
});
// var ellipse = entryPoint.append("circle")
// .attr("r", 50);
var nodeShape = entryPoint.append("path")
.attr("d", d3.symbol().type(superellipse))
.style("stroke", "gray")
.attr("fill", "pink")
// .n(function(d) {return d.n;})
.attr("w", function(d) {
return d.w;
})
.attr("h", function(d) {
return d.h;
});
var nodeText = entryPoint.append("text")
.text(function(d) {
return d.text;
})
.attr({
"text-anchor": "middle"
});
};
为明确起见,我按如下方式调用它:
var superellipse = {
draw: function(context, size) {
var w = size;
var h = size;
var n = 2 / 4;
context.moveTo(w / 2 * Math.sign(Math.cos(0 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(0 / 9 * 2 * Math.PI)), n), h / 2 * Math.sign(Math.sin(0 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(0 / 9 * 2 * Math.PI)), n));
context.lineTo(w / 2 * Math.sign(Math.cos(1 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(1 / 9 * 2 * Math.PI)), n), h / 2 * Math.sign(Math.sin(1 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(1 / 9 * 2 * Math.PI)), n));
context.lineTo(w / 2 * Math.sign(Math.cos(2 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(2 / 9 * 2 * Math.PI)), n), h / 2 * Math.sign(Math.sin(2 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(2 / 9 * 2 * Math.PI)), n));
context.lineTo(w / 2 * Math.sign(Math.cos(3 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(3 / 9 * 2 * Math.PI)), n), h / 2 * Math.sign(Math.sin(3 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(3 / 9 * 2 * Math.PI)), n));
context.lineTo(w / 2 * Math.sign(Math.cos(4 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(4 / 9 * 2 * Math.PI)), n), h / 2 * Math.sign(Math.sin(4 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(4 / 9 * 2 * Math.PI)), n));
context.lineTo(w / 2 * Math.sign(Math.cos(5 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(5 / 9 * 2 * Math.PI)), n), h / 2 * Math.sign(Math.sin(5 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(5 / 9 * 2 * Math.PI)), n));
context.lineTo(w / 2 * Math.sign(Math.cos(6 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(6 / 9 * 2 * Math.PI)), n), h / 2 * Math.sign(Math.sin(6 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(6 / 9 * 2 * Math.PI)), n));
context.lineTo(w / 2 * Math.sign(Math.cos(7 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(7 / 9 * 2 * Math.PI)), n), h / 2 * Math.sign(Math.sin(7 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(7 / 9 * 2 * Math.PI)), n));
context.lineTo(w / 2 * Math.sign(Math.cos(8 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(8 / 9 * 2 * Math.PI)), n), h / 2 * Math.sign(Math.sin(8 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(8 / 9 * 2 * Math.PI)), n));
context.lineTo(w / 2 * Math.sign(Math.cos(9 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(9 / 9 * 2 * Math.PI)), n), h / 2 * Math.sign(Math.sin(9 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(9 / 9 * 2 * Math.PI)), n));
context.closePath();
}
};
var svg = d3.select("svg")
.attr("width", 500)
.attr("height", 500);
function visualize(json) {
var nodes = svg.selectAll("g nodetext")
.data(json.nodes);
var entryPoint = nodes.enter()
.append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + ",80)"
});
// var ellipse = entryPoint.append("circle")
// .attr("r", 50);
var nodeShape = entryPoint.append("path")
.attr("d", d3.symbol().type(superellipse))
.style("stroke", "gray")
.attr("fill", "pink")
// .n(function(d) {return d.n;})
.attr("w", function(d) {
return d.w;
})
.attr("h", function(d) {
return d.h;
});
var nodeText = entryPoint.append("text")
.text(function(d) {
return d.text;
})
.attr({
"text-anchor": "middle"
});
}
var json = {
"nodes": [{
"text": "test A",
"x": 100,
"y": 100,
"w": 200,
"n": 0.5,
"h": 200,
"color": "red"
},
{
"text": "test B",
"x": 200,
"y": 200,
"w": 200,
"n": 3,
"h": 100,
"color": "red"
},
]
};
visualize(json);
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>
答案 0 :(得分:2)
您声称自己...
无法通过设置r属性来调整尺寸。在这种情况下,可以通过设置n,h和w属性。
好吧,在您的情况下,您可以使用symbol.size()
传递一个属性。例如,100
:
.attr("d", d3.symbol().type(superellipse).size(100))
但是,问题是symbol.size()
仅传递一个值:您不能尝试传递多个参数,数组,对象或类似的东西。因此,在上面的示例中,w
,h
和n
将是100
。
如果您检查symbol.size()
中的source code,则会看到:
symbol.size = function(_) {
return arguments.length ?
(size = typeof _ === "function" ? _ : constant(+_), symbol) : size;
};
一元加号向我们表明,如果您尝试传递数组或对象,则会得到NaN
,并且如果传递多个值,它们将被忽略。
那么,我们该如何解决呢?
最后,在我看来,您的问题仅仅是因为您为此任务使用了错误的通行费。您不需要符号生成器,可以使用通用函数来生成d
元素的<path>
属性。
例如:
function superellipse (w, h, n){
return "M" + (w / 2 * Math.sign(Math.cos(0 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(0 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(0 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(0 / 9 * 2 * Math.PI)), n)))
+ " L" + (w / 2 * Math.sign(Math.cos(1 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(1 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(1 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(1 / 9 * 2 * Math.PI)), n)))
+ " L" + (w / 2 * Math.sign(Math.cos(2 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(2 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(2 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(2 / 9 * 2 * Math.PI)), n)))
+ " L" + (w / 2 * Math.sign(Math.cos(3 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(3 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(3 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(3 / 9 * 2 * Math.PI)), n)))
+ " L" + (w / 2 * Math.sign(Math.cos(4 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(4 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(4 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(4 / 9 * 2 * Math.PI)), n)))
+ " L" + (w / 2 * Math.sign(Math.cos(5 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(5 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(5 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(5 / 9 * 2 * Math.PI)), n)))
+ " L" + (w / 2 * Math.sign(Math.cos(6 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(6 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(6 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(6 / 9 * 2 * Math.PI)), n)))
+ " L" + (w / 2 * Math.sign(Math.cos(7 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(7 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(7 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(7 / 9 * 2 * Math.PI)), n)))
+ " L" + (w / 2 * Math.sign(Math.cos(8 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(8 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(8 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(8 / 9 * 2 * Math.PI)), n)))
+ " L" + (w / 2 * Math.sign(Math.cos(9 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(9 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(9 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(9 / 9 * 2 * Math.PI)), n)));
};
通过这种方式,您可以获得在基准对象中定义的w
,h
和n
属性,并将它们毫无问题地传递给函数。
以下是包含您的数据的演示:
function superellipse (w, h, n){
return "M" + (w / 2 * Math.sign(Math.cos(0 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(0 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(0 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(0 / 9 * 2 * Math.PI)), n)))
+ " L" + (w / 2 * Math.sign(Math.cos(1 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(1 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(1 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(1 / 9 * 2 * Math.PI)), n)))
+ " L" + (w / 2 * Math.sign(Math.cos(2 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(2 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(2 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(2 / 9 * 2 * Math.PI)), n)))
+ " L" + (w / 2 * Math.sign(Math.cos(3 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(3 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(3 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(3 / 9 * 2 * Math.PI)), n)))
+ " L" + (w / 2 * Math.sign(Math.cos(4 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(4 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(4 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(4 / 9 * 2 * Math.PI)), n)))
+ " L" + (w / 2 * Math.sign(Math.cos(5 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(5 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(5 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(5 / 9 * 2 * Math.PI)), n)))
+ " L" + (w / 2 * Math.sign(Math.cos(6 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(6 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(6 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(6 / 9 * 2 * Math.PI)), n)))
+ " L" + (w / 2 * Math.sign(Math.cos(7 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(7 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(7 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(7 / 9 * 2 * Math.PI)), n)))
+ " L" + (w / 2 * Math.sign(Math.cos(8 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(8 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(8 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(8 / 9 * 2 * Math.PI)), n)))
+ " L" + (w / 2 * Math.sign(Math.cos(9 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.cos(9 / 9 * 2 * Math.PI)), n) + "," + (h / 2 * Math.sign(Math.sin(9 / 9 * 2 * Math.PI)) * Math.pow(Math.abs(Math.sin(9 / 9 * 2 * Math.PI)), n)));
};
var svg = d3.select("svg")
.attr("width", 500)
.attr("height", 500);
function visualize(json) {
var nodes = svg.selectAll("g nodetext")
.data(json.nodes);
var entryPoint = nodes.enter()
.append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"
});
var nodeShape = entryPoint.append("path")
.attr("d", function(d){
return superellipse(d.w, d.h, d.n)
})
.style("stroke", "gray")
.attr("fill", "pink");
var nodeText = entryPoint.append("text")
.text(function(d) {
return d.text;
})
.attr({
"text-anchor": "middle"
});
}
var json = {
"nodes": [{
"text": "test A",
"x": 100,
"y": 100,
"w": 200,
"n": 0.5,
"h": 200,
"color": "red"
},
{
"text": "test B",
"x": 300,
"y": 100,
"w": 200,
"n": 3,
"h": 100,
"color": "red"
},
]
};
visualize(json);
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>