定义自定义D3符号 [英] Defining custom D3 symbols

查看:57
本文介绍了定义自定义D3符号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在D3中开发自定义形状,但是我有点绿色的Javascript智慧,并且不确定 D3-Shapes 库在后台运行.

尤其是,我不确定default 函数是什么.js" rel ="nofollow noreferrer"> symbol.js 正在执行或如何使用.从一点点JS中,我确实知道它似乎在描述原型或可能的类.可以使用 symbol.type 类/函数来注册其他形状但是我不确定应该如何称呼这个 var symbol = symbol("SYMBOL").type(SYMBOL)或可能的 var SYMBOL = symbol().type(SYMBOL)或其他组合.问题23 讨论了形状库与我认为的原始实现有何不同否定此 SO:答案.我还搜寻了 D3-Symbol-Extra 的线索,但没有骰子.

到目前为止,对于超椭圆,我具有以下形状定义,该形状与D3 Shapes库中的符号定义匹配,例如圆圈

为明确起见,我正在按如下方式调用它:

  var superellipse = {绘制:函数(上下文,大小){var w = size;var h =大小;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);函数visualize(json){var nodes = svg.selectAll("g nodetext").data(json.nodes);var entryPoint = nodes.enter().append("g").attr("class","node").attr("transform",function(d){返回"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(填充",粉红色")//.n(function(d){return d.n;}).attr("w",function(d){返回d.w;}).attr("h",function(d){返回d.h;});var nodeText = entryPoint.append("text").text(function(d){返回d.text;}).attr({文本锚":中间"});}var json = {节点":[{"text":测试A","x":100,"y":100,"w":200,"n":0.5,"h":200,红色"},{"text":测试B","x":200,"y":200,"w":200,"n":3,"h":100,红色"},]};visualize(json);  

 <脚本src ="https://d3js.org/d3.v5.min.js"></script>< svg></svg>  

您声称自己...

无法通过设置r属性来调整尺寸.在这种情况下,可以通过设置n,h和w属性.

好吧,在您的情况下,您可以使用 symbol.size()传递一个属性.例如, 100 :

  .attr("d",d3.symbol().type(superellipse).size(100)) 

但是,问题是 symbol.size()仅传递一个值:您不能尝试传递多个参数,数组,对象或类似的东西.因此,在上面的示例中, w h n 将为 100 .

如果您查看源代码 of symbol.size(),您将看到:

  symbol.size = function(_){返回arguments.length?(size = typeof _ ==="function"?_:constant(+ _),symbol):大小;}; 

一元加号向我们表明,如果您尝试传递数组或对象,则会得到一个 NaN ,如果传递多个值,它们将被忽略./p>

那么,我们该如何解决呢?

正确的任务工具

最后,在我看来,您的问题仅仅是因为您为此任务使用了错误的通行费.您不需要符号生成器,可以使用通用函数来生成< path> 元素的 d 属性.

例如:

 函数超级椭圆(w,h,n){返回"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)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)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)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)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)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)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)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)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 属性,并将它们毫无问题地传递给函数

以下是包含您的数据的演示:

 函数超级椭圆(w,h,n){返回"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)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)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)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)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)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)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)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)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);函数visualize(json){var nodes = svg.selectAll("g nodetext").data(json.nodes);var entryPoint = nodes.enter().append("g").attr("class","node").attr("transform",function(d){返回"translate("+ d.x +","+ d.y +")});var nodeShape = entryPoint.append("path").attr("d",function(d){返回超级椭圆(d.w,d.h,d.n)}).style("stroke","gray").attr("fill","pink");var nodeText = entryPoint.append("text").text(function(d){返回d.text;}).attr({文本锚":中间"});}var json = {节点":[{"text":测试A","x":100,"y":100,"w":200,"n":0.5,"h":200,红色"},{"text":测试B","x":300,"y":100,"w":200,"n":3,"h":100,红色"},]};visualize(json);  

 <脚本src ="https://d3js.org/d3.v5.min.js"></script>< svg></svg>  

I'm trying to develop a custom shape in D3, but I'm a little green Javascript wise and am not sure what the D3-Shapes library is doing under the hood.

In particular, I'm not sure what the default function in symbol.js is doing or how it is used. From the little bit of JS that I do know it appears to be describing a prototype or possibly a class. Supposedly one may register additional shapes using the symbol.type class/function but I'm not sure how I should be calling this e.g. var symbol = symbol("SYMBOL").type(SYMBOL) or possibly var SYMBOL = symbol().type(SYMBOL) or some other combination. Issue 23 discusses how the shapes library has changed from the original implementation which I think negates this SO: answer. I also scrounged the D3-Symbol-Extra for clues but no dice.

So far I have the following shape definition for a superellipse that matches up to the symbol definitions in the D3 Shapes library, e.g. circle, diamond, etc.

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();
  }
};

I can get the shape to be drawn according to the default size, but I can't tweak the dimensions as one might for a circle by setting the r attribute; in this case by setting the n, h and w attributes.

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"
        });
};

To be explicit, I'm invoking this as follows :

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>

解决方案

You claimed that you...

can't tweak the dimensions as one might for a circle by setting the r attribute; in this case by setting the n, h and w attributes.

Well, in your case you can pass one attribute, using symbol.size(). For instance, 100:

.attr("d", d3.symbol().type(superellipse).size(100))

However, the problem is that symbol.size() will pass just a single value: you cannot try to pass several arguments, or an array, or an object, or anything like these. So, in the example above, w, h and n will be 100.

If you inspect the source code of symbol.size() you'll see:

symbol.size = function(_) {
    return arguments.length ? 
        (size = typeof _ === "function" ? _ : constant(+_), symbol) : size;
};

That unary plus show us that, if you try to pass an array or an object, you'll get a NaN, and if you pass more than one value they will be simply ignored.

So, how can we fix this?

The correct tool for the task

In the end, it seems to me that your problem is simply that you're using the wrong toll for this task. You don't need a symbol generator, you can use a common function to generate the d attribute of the <path> element.

For instance:

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)));
};

That way you can get the w, h and n properties defined in the datum object and pass them to the function without any problem.

Here is a demo with your data:

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>

这篇关于定义自定义D3符号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆