面向对象d3 [英] Object Oriented d3

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

问题描述

我有要添加到SVG的数据对象。考虑下面的伪代码片段:

  var data = [],counter = 0; 
for(var col = 1; col <= 5; col ++)
for(var row = 1; row< = 3; row ++)
data.push({
id :obj-+ ++ counter
,x:col * 120
,y:row * 120
,width:40
,height:40
, shape:counter%2?circle:rect
});

d3.select(。container)。selectAll(。obj)
.data(data)
.enter()
.append g)
.attr(id,function(d){return d.id;}
/ ***
现在我要在这里绘制一个圆形或rect形状键
所以如果(d.shape ==rect) - 我们将使用宽度和高度
if(d.shape ==rect&& d.width == d .height),我们将r设置为width等。
*** /

理想情况下,我将创建一个Shape类型的对象,例如

  function Shape(id,shape,x,y, w,h){

this.id = id;
this.shape = shape;
this.x = x;
this.y = y;
this.width = w;
this.height = h;

this.render = function(parent){

var g = parent.append (g)
.attr(id,this.id);

switch(this.shape){
casecircle:
.append(circle)
.attr(/ *这里更多的代码* /)
break;
caserect:
g.append(rect)
.attr(/ * more code here * /)
break;
casetriangle:
g.append(polygon)
.attr(/ * more code here * /)
break;
}
}
}

做如下:

  var data = [],counter = 0; 
for(var col = 1; col< = 5; col ++)
for(var row = 1; row< = 3; row ++)
data.push $ b id:obj-+ ++ counter
,x:col * 120
,y:row * 120
,width:40
,height:40
,shape:counter%2?circle:rect
)});

但是如何从d3调用Shape的render即

  d3.select(。container)。selectAll(。obj)
.data )
.enter()
/ *给定一个名为d的数据,调用d.render(parent)? * /

我是d3的新手,所以也许数据连接是错误的方式去?是否有一种不同的方式来呈现对于这种情况更好的数据项?

解决方案

面向对象的方式,您可以诉诸不太知名的 选择.append(name) 。根据文档,您可以提供回调 .append(),它需要返回一个DOM元素来追加:



附加名称


;]



名称可以指定为常量字符串或返回要附加的DOM元素的函数。如果name是一个函数,它将传递当前数据d和当前索引i,并将此上下文作为当前DOM元素。要根据绑定数据附加任意元素,必须在函数中创建。例如:

  selection.enter()。append(function(d){
return document.createElementNS( http://www.w3.org/2000/svg,d.type)
})




出于这个问题的目的,可以修改为不创建元素,而是将创建委托给 .render()你的数据对象的方法。

  d3.select(。container)。selectAll(g)
.data(data)
.enter()
.append(function(d){
return d.render(); // .render()将返回DOM元素追加
}

您的 .render()像这样:

  this.render = function(){

//创建组。
var g = document.createElementNS(d3.ns.prefix.svg,g);
g.setAttribute(id,this.id);

//基于this.shape创建和配置子元素。
var child;
switch(this.shape){
casecircle:
child = document.createElementNS(d3.ns.prefix.svg,circle);
child.setAttribute(cx,this.x);
child.setAttribute(cy,this.y);
child.setAttribute(r,this.width / 2);
break;

caserect:
child = document.createElementNS(d3.ns.prefix.svg,rect)
break;

casetriangle:
child = document.createElementNS(d3.ns.prefix.svg,polygon)
break;
}

//将子元素附加到组并返回g DOM元素。
g.appendChild(child);
return g;
}

请看这个代码片段的工作示例:



  function Shape(id,shape,x,y,w,h){this.id = id; this.shape = shape; this.x = x; this.y = y; this.width = w; this.height = h; this.render = function(){//创建组。 var g = document.createElementNS(d3.ns.prefix.svg,g); g.setAttribute(id,this.id); //基于this.shape创建和配置子元素。 var child; switch(this.shape){casecircle:child = document.createElementNS(d3.ns.prefix.svg,circle); child.setAttribute(cx,this.x); child.setAttribute(cy,this.y); child.setAttribute(r,this.width / 2);打破; caserect:child = document.createElementNS(d3.ns.prefix.svg,rect)child.setAttribute(x,this.x); child.setAttribute(y,this.y); child.setAttribute(width,this.width); child.setAttribute(height,this.height);打破; casetriangle:child = document.createElementNS(d3.ns.prefix.svg,polygon)break; } //将该子元素附加到组并返回g DOM元素。 g.appendChild(child); return g; }} var data = [],counter = 0; for(var col = 1; col <= 5; col ++)for(var row = 1; row< = 3; row ++)data.push + ++ counter,counter%2?circle:rect,col * 120,row * 120,40,40) console.log(data); d3.select(。container)。selectAll(g).data(data).enter().append(function(d){return d.render() render()将返回DOM元素附加});  

 < script src =https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js>< / script>< svg width =400height = 400> < g class =container>< / g>< / svg>  


I have data objects that I want to add to an SVG. Consider the following pseudo-snippet:

var data = [], counter = 0;
for (var col=1; col<=5; col++)
  for (var row=1; row<=3; row++)
    data.push({
         id: "obj-" + ++counter
        ,x: col * 120
        ,y: row * 120
        ,width: 40
        ,height: 40
        ,shape: counter % 2 ? "circle" : "rect"
    });

 d3.select(".container").selectAll(".obj")
     .data(data)
     .enter()
         .append("g")
             .attr("id", function(d){ return d.id; }
/*** 
     now I want to draw here a circle or rect based on the shape key 
     so if (d.shape == "rect") -- we will use width and height
        if (d.shape == "rect" && d.width == d.height) we will set "r" to "width", etc.
***/

Ideally, I would create an object of type Shape, e.g.

function Shape(id, shape, x, y, w, h) {

    this.id = id;
    this.shape = shape;
    this.x = x;
    this.y = y;
    this.width = w;
    this.height = h;

    this.render = function(parent) {

        var g = parent.append("g")
            .attr("id", this.id);

        switch (this.shape) {
            case "circle":
                g.append("circle")
                    .attr( /* more code here */ )
                break;
            case "rect":
                g.append("rect")
                    .attr( /* more code here */ )
                break;
            case "triangle":
                g.append("polygon")
                    .attr( /* more code here */ )
                break;
        }
    }
}

Then I'd be able to do something like:

var data = [], counter = 0;
for (var col=1; col<=5; col++)
  for (var row=1; row<=3; row++)
    data.push(new Shape({
         id: "obj-" + ++counter
        ,x: col * 120
        ,y: row * 120
        ,width: 40
        ,height: 40
        ,shape: counter % 2 ? "circle" : "rect"
    )});

But how can I call the Shape's render() method from d3? i.e.

 d3.select(".container").selectAll(".obj")
     .data(data)
     .enter()
         /* given a datum named d, call d.render(parent) ? */

I'm rather new to d3, so maybe data joins is the wrong way to go? Is there a different way to render data items that would be better for this scenario?

解决方案

To have the data objects render themselves in an object-oriented manner you can resort to a less known use of selection.append(name). According to the docs, you can provide a callback to .append() which needs to return a DOM element to append:

selection.append(name)

[…]

The name may be specified either as a constant string or as a function that returns the DOM element to append. If name is a function, it is passed the current datum d and the current index i, with the this context as the current DOM element. To append an arbitrary element based on the bound data it must be created in the function. For example:

selection.enter().append(function(d) {
    return document.createElementNS("http://www.w3.org/2000/svg", d.type)
})

For the purpose of this question this may be modified to not create the element in place, but to delegate the creation to the .render() method of your data objects.

d3.select(".container").selectAll("g")
  .data(data)
  .enter()
  .append(function(d) {
      return d.render();   // .render() will return the DOM element to append
  });

Your .render() method might look something like this:

this.render = function() {

    // Create the group.
    var g = document.createElementNS(d3.ns.prefix.svg, "g");
    g.setAttribute("id", this.id);

    // Create and configure the child element based on this.shape.
    var child;
    switch (this.shape) {
        case "circle":
            child = document.createElementNS(d3.ns.prefix.svg, "circle");
            child.setAttribute("cx", this.x);
            child.setAttribute("cy", this.y);
            child.setAttribute("r", this.width/2);
            break;

        case "rect":
            child = document.createElementNS(d3.ns.prefix.svg, "rect")
            break;

        case "triangle":
            child = document.createElementNS(d3.ns.prefix.svg, "polygon")
            break;
    }

    // Append the child to the group and return the g DOM element.
    g.appendChild(child);
    return g;
}

Have a look at this snippet for a working example:

function Shape(id, shape, x, y, w, h) {

    this.id = id;
    this.shape = shape;
    this.x = x;
    this.y = y;
    this.width = w;
    this.height = h;

    this.render = function() {

        // Create the group.
        var g = document.createElementNS(d3.ns.prefix.svg, "g");
        g.setAttribute("id", this.id);
        
        // Create and configure the child element based on this.shape.
        var child;
        switch (this.shape) {
            case "circle":
                child = document.createElementNS(d3.ns.prefix.svg, "circle");
                child.setAttribute("cx", this.x);
                child.setAttribute("cy", this.y);
                child.setAttribute("r", this.width/2);
                break;
                
            case "rect":
                child = document.createElementNS(d3.ns.prefix.svg, "rect")
                child.setAttribute("x", this.x);
                child.setAttribute("y", this.y);
                child.setAttribute("width", this.width);
                child.setAttribute("height", this.height);
                break;
                
            case "triangle":
                child = document.createElementNS(d3.ns.prefix.svg, "polygon")
                break;
        }
        
        // Append the child to the group and return the g DOM element.
        g.appendChild(child);
        return g;
    }
}

var data = [], counter = 0;
for (var col=1; col<=5; col++)
  for (var row=1; row<=3; row++)
    data.push(new Shape(
         "obj-" + ++counter
        ,counter % 2 ? "circle" : "rect"
        ,col * 120
        ,row * 120
        ,40
        ,40
    ));
    
console.log(data);

d3.select(".container").selectAll("g")
  .data(data)
  .enter()
  .append(function(d) {
    return d.render();   // .render() will return the DOM element to append
  });

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg width="400" height="400">
  <g class="container"></g>
</svg>

这篇关于面向对象d3的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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