0

I'm using d3 and I'd like to append a group with basic shapes attached to it, like the following:

  1. startEvent (a circle)
  2. task (a recangle)
  3. endEvent (two circles)

since I'm new to d3 I'd like to know how to append each group dynamically depending on the 'shape type' and avoid to append each shape one by one using a foreach.

this is the code:

var shapes ={
    startEvent:function(id,x,y,params){
        var radius = 18,
        cy = Math.floor(Number(y) + radius),
        cx = Math.floor(Number(x) + radius),
        g = d3.select('g');

        var circle = g.append('circle')
            .attr('cx', cx)
            .attr('cy', cy)
            .attr('r', radius)
            .attr('id', id);

        if(params.label!==undefined){
            var txt = g.append('text')
            .attr('y',y).text(params.label);
                txt.attr('x',Number(x));
                txt.attr('y',Number(y));
        }
        return g;
    },
    endEvent:function(id,x,y, params){
       // something similar to startEvent, but with two circles instead of one
    },
    task:function(id,x,y, params){
       // something similar but with a rectangle
    }
};

passing the data and rendering the elements:

svg.selectAll('g')
    .data(data)
    .enter()
    .append(function(d){
        params={label: d.meta.name};
        return shapes[d.type](d.id,d.x,d.y,params);
     });

but I'm getting

Error: Failed to execute 'appendChild' on 'Node': The new child element is null.

I guess that's because I'm returning the selector, any ideas?

pedrommuller
  • 15,741
  • 10
  • 76
  • 126

1 Answers1

0

based on this and this answers I got to the following point, it seems like you need to create an instance manually under the d3 namespace, once you got that you can use a d3 selector over it and return the node() of the element which return the actual DOM code.

this is the code:

var shapes ={
    startEvent:function(id,x,y,params){
        var radius = 18,
                    cy = Math.floor(Number(y) + radius),
                    cx = Math.floor(Number(x) + radius),
                    e =  document.createElementNS(d3.ns.prefix.svg,'g'),
                    g = d3.select(e).attr('id', id).
                    attr('class','node');
                    var circle = g.append('circle')
                    .attr('cx', cx)
                    .attr('cy', cy)
                    .attr('r', radius)
                    .attr('class','circle');

                    if(params.label!==undefined){
                        var txt = g.append('text')
                        .attr('y',y).text(params.label);
                        txt.attr('x',Number(x));
                        txt.attr('y',Number(y));

                    }
                    return g;
    },
    endEvent:function(id,x,y, params){
       // something similar to startEvent, but with two circles instead of one
    },
    task:function(id,x,y, params){
       // something similar but with a rectangle
    }
};

and then return the node

svg.selectAll('g')
    .data(data)
    .enter()
    .append(function(d){
        params={label: d.meta.name};
        var v = shapes[d.type](d.id,d.x,d.y,params);
        return v.node();
     });
Community
  • 1
  • 1
pedrommuller
  • 15,741
  • 10
  • 76
  • 126