创建SVG元素而不渲染它们

时间:2018-07-19 19:30:11

标签: javascript d3.js svg

如何创建一个返回自定义SVG图形而不附加任何内容的函数?我可以创建一个空选择并将其返回吗? 我目前有什么:

function makeGraphic(svgParent) {
    return svgParent.append('circle').attrs({...});
}

这就是我想要的:

function makeGraphic() {
    return d3.makeCircle?.attrs({...});
}

svgParent.append(makeGraphic());

2 个答案:

答案 0 :(得分:2)

您可以在函数内部使用svg命名空间创建一个临时的svg节点-无需渲染svg。然后,您可以在处理svg并返回某种形状时将其视为典型节点。

要注意的一件事是.append()接受标记名称或函数,因此我在下面不提供该函数的结果:

var svg = d3.select("body")
  .append("svg")
  .attr("width", 400)
  .attr("height",200)
  .attr("transform", "translate(200,100)");
  
var makeCircle = function() {
  // create a temporary svg
  let svg = document.createElementNS(d3.namespaces.svg, "svg")
  // create a circle
  let circle = d3.select(svg).append("circle")
    .attr("r", 20)
    .attr("fill", "steelblue");
    
  // return a circle
  return circle.node(); 

}

svg.append(makeCircle);
<script src="https://d3js.org/d3.v5.min.js"></script>

这样,您可以制作更复杂的形状生成器以返回形状以供d3.append()之类的东西使用:

let svg = d3.select("body").append("svg")
    .attr("width", 500)
    .attr("height", 200);
    

var shapes = [{shape: "circle",y: 40, fill: "darkblue"},{shape:"square", y: 35},{y:40}]

svg.selectAll()
  .data(shapes)
  .enter()
  .append(shapemaker);    

function shapemaker(options = {}) {
	 let svg = document.createElementNS(d3.namespaces.svg, "svg")
	 var shape;
	 if (options.shape == "circle") {
	   shape = d3.select(svg).append("circle")
       .attr("cx", options.x ? options.x : 50)
       .attr("cy", options.y ? options.y : 50) 
       .attr("r", options.r ? options.r : 10)
       .attr("fill", options.fill ? options.fill : "steelblue" )
    }
    else if (options.shape == "square") {
      shape = d3.select(svg).append("rect")
       .attr("x", options.x ? options.x : 100)
       .attr("y", options.y ? options.y : 50) 
       .attr("width", options.width ? options.size : 10)
       .attr("height", options.width ? options.size : 10)
       .attr("fill", options.fill ? options.fill : "orange" )		
    }
    else {
      let x = options.x ? options.x : 150, y = options.y ? options.y : 50;
      shape = d3.select(svg).append("path")
        .attr("d", d3.symbol().type(d3.symbolStar).size(options.size ? options.size : 100))
        .attr("transform","translate("+[x,y]+")")
        .attr("fill", options.fill ? options.fill : "crimson")
		
    }
	 
  return shape.node();
	   
}
<script src="https://d3js.org/d3.v5.min.js"></script>

答案 1 :(得分:2)

在我看来,这是使用detached element的理想情况。您也可以使用DocumentFragment,但是在D3代码中,分离元素更常见。

要创建分离的whatever SVG元素,您需要做的是:

var detached = d3.create('svg:whatever');

根据文档

  

给出指定的元素名称,返回一个单元素选择,其中包含当前文档中给定名称的分离元素。

这与Andrew's answer非常相似,因为内部d3.create使用document.createElement。但是请注意,它使用document.createElement,而不是document.createElementNS,因此此处需要名称空间:

var detached = d3.create('svg:whatever');
//this is the namespace----ˆ

然后,在那之后,您可以创建所需的结构。例如:

detached.selectAll(null)
    .data(d3.range(5))
    .enter()
    .append("circle")
    //etc...

最后,使用append,获取分离元素的节点并将其附加到所需的位置:

svg.append(function(){ return detached.node();});

这是一个演示,函数makeGraphic创建一个分离的元素,并返回其节点。然后,我们只需将返回值附加到SVG:

var svg = d3.select("body")
  .append("svg")
  .attr("width", 500)
  .attr("height", 300);

function makeGraphic() {
  var detached = d3.create('svg:g');
  detached.selectAll(null)
    .data(d3.range(10))
    .enter()
    .append("circle")
    .attr("cx", function() {
      return Math.random() * 500
    })
    .attr("cy", function() {
      return Math.random() * 300
    })
    .attr("r", function() {
      return Math.random() * 50
    })
    .attr("fill", function(_, i) {
      return d3.schemeCategory10[i]
    });
  return detached.node();
};

svg.append(makeGraphic)
<script src="https://d3js.org/d3.v5.min.js"></script>