2016-07-29 32 views
0

我已经使用了一个SVG defs组(创建时使用d3js)来创建一个复杂的项目,我想实例化,然后修改,但是从我所有的演奏和研究中,我可以得出的唯一结论是每个实例实际上是一个链接的实例,而不是独立的实例。我确信有这些技术的计算机科学的名字,但我相信你知道我的意思:o)有没有办法使SVG USE随后可修改(或不同的技术)?

我已经建立了一些示例代码来说明我有问题。 在SVG DEFS部分定义了一个组,它由两个正方形和一个文本元素组成。然后在SVG容器下建立一个类似的结构。最后,我使用USE + XLINK:HREF来实例化包含两个正方形和文本的组元素的两个副本。最初,所有的声明都有在STYLE部分中指定的类。

为了说明问题并尝试使用它,我添加了一些元素修改,使用jQuery访问对象(我发现它比d3或直接的Javascript DOM操作更容易)。看起来我禁止在DEFS中实例化的层次结构中查询,但是我可以访问直接绘制区域的完整层次结构。这是我项目中的一个问题,因为我在频繁发生的子元素上有一些小的形状变化,但其中每个元素至少会有不同的标记。我不想创造每一个长手,除非我必须,甚至以编程方式。理想情况下,我只想将几个子组件切换到opacity = 0,并使用d3js插入文本标签和描述。 DEFS/USE有什么替代方案,这意味着我可以使复制的实例不是链接的实例?

<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <meta charset="utf-8"> 
    <title> 
    Testing how to navigate 'DEFS' &amp; 'USE' to change attributes of the elements in the instance 
    </title> 
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> 
    <script src="https://code.jquery.com/jquery-1.12.4.js"></script> 
    <!--script src="https://code.jquery.com/ui/1.12.0/jquery-ui.js"></script--> 

    <style> 
    .pinkBox { 
    fill: #fdc4fe; 
    stroke: black; 
    stroke-width: 2px; 
    stroke-linecap: square; 
    stroke-linejoin: round; 
    opacity: 1; 
    } 
    .redBox { 
    fill: #fb198e; 
    stroke: black; 
    stroke-width: 2px; 
    stroke-linecap: square; 
    stroke-linejoin: round; 
    opacity: 1; 
    } 
    .lightGreenBox { 
    fill: #bdf07c; 
    stroke: black; 
    stroke-width: 2px; 
    stroke-linecap: square; 
    stroke-linejoin: round; 
    opacity: 1; 
    } 
    .GreenBox { 
    fill: #4a9a03; 
    stroke: black; 
    stroke-width: 2px; 
    stroke-linecap: square; 
    stroke-linejoin: round; 
    opacity: 1; 
    } 
    .greyText{ 
    font-family:sans-serif; 
    font-size: 12px; 
    fill: grey; 
    } 
    </style> 
</head> 
<body> 
<script type="text/javascript"> 
    var svgContainer = d3.select("body") 
     .append("svg") 
     .attr("width", 1024) 
     .attr("height", 768); 

    var BG = svgContainer.append("rect") 
     .attr("width", "100%") 
     .attr("height", "100%") 
     .attr("fill", "#2d2525"); 

    var reusables = svgContainer.append("defs") 

    var USEgrp = reusables.append("g") 
     //.attr("id","Ugrp") 
     .attr("transform","translate(20,20)"); 

    var RB = USEgrp.append("rect") 
     //.attr("id","RB") 
     .attr("x","10") 
     .attr("y","10") 
     .attr("height","100") 
     .attr("width","100") 
     .attr("rx","10") 
     .attr("ry","10") 
     //.attr("class","redBox") 
     ; 

    var BB = USEgrp.append("rect") 
     //.attr("id","BB") 
     .attr("x","120") 
     .attr("y","10") 
     .attr("height","100") 
     .attr("width","100") 
     .attr("rx","10") 
     .attr("ry","10") 
     //.attr("class","blueBox") 
     ; 

    var Txt = USEgrp.append("text") 
     //.attr("id","TxtU") 
     .attr("x",250) 
     .attr("y",70) 
     //.attr("class","greyText") 
     //.attr("fill","white") 
     .text("These boxes are 'USEed' from the prototype in the 'DEFS' section"); 

    var canvasgrp = svgContainer.append("g") 
     .attr("id","Cgrp") 
     .attr("transform","translate(0,0)"); 

    var GB = canvasgrp.append("rect") 
     .attr("id","GB") 
     .attr("x","30") 
     .attr("y","350") 
     .attr("height","100") 
     .attr("width","100") 
     .attr("rx","10") 
     .attr("ry","10") 
     .attr("class","greenBox") 
     ; 

    var OB = canvasgrp.append("rect") 
     .attr("id","OB") 
     .attr("x","140") 
     .attr("y","350") 
     .attr("height","100") 
     .attr("width","100") 
     .attr("rx","10") 
     .attr("ry","10") 
     .attr("class","orangeBox") 
     ; 

    var Txt2 = canvasgrp.append("text") 
     .attr("id","TxtC") 
     .attr("x",270) 
     .attr("y",400) 
     .attr("class","greyText") 
     .attr("fill","white") 
     .text("These boxes drawn directly to SVG canvas"); 

    var inst1 = svgContainer.append("use") 
     .attr("xlink:href","#Ugrp") 
     .attr("id","inst1") 
     .attr("transform","translate(0,0)"); 

    var inst2 = svgContainer.append("use") 
     .attr("xlink:href","#Ugrp") 
     .attr("id","inst1") 
     .attr("transform","translate(0,150)"); 

    var USEbox1 = ($("g").filter("#Ugrp").children().first().attr("stroke","yellow").attr("stroke-width","6")); 
    var USEtext = ($("g").filter("#Ugrp").children().last().attr("fill","brown")); 
    var USEbox2 = ($("g").filter("#Ugrp").children().first().next().attr("style",".GreenBox")); 


    var SVGbox1 = ($("g").filter("#Cgrp").children().first().attr("stroke","pink").attr("stroke-width","6")); 
    var SVGtext = ($("g").filter("#Cgrp").children().last().attr("fill","cyan")); 
    var SVGbox2 = ($("g").filter("#Cgrp").children().first().next().attr("stroke","magenta").attr("stroke-width","1")); 

</script> 

+1

你不想使用,你想在JavaScript的一些基本对象,克隆它,然后修改克隆。 –

+0

罗伯特,感谢您的迅速反应(像往常一样:-))。请你添加一些代码来说明你的意思吗? (或弹出一个链接到一个例子?) 我认为JS对象可能很方便,但我无法想象与SVG的相互作用! – Greg

+0

getElementById(“thing”)。clone()然后改变它并将其追加到appendChild –

回答

0

罗伯特是正确与clone(),但我想探索多种想法,以及他们的机遇和限制是,所以我建立了一个小d3js代码来尝试出来。我决定定义一个复杂的程序集来实例化,然后尝试更改程序集的子组件。该模型是一个group,包含两个rects和一个text。我探索的不同选择是:

直接在SVG容器中创建我的复杂层次结构。这代表了最坏的情况,一切都必须手工制作。

var canvasgrp = svgContainer.append("g") 
     .attr("id","Cgrp") 
     ...snipped 
    ); 

    var BA = canvasgrp.append("rect") 
     .attr("id","BA") 
     ...snipped); 

    var BB = canvasgrp.append("rect") 
     .attr("id","BB") 
     ...snipped); 

    var BC = canvasgrp.append("text") 
     .attr("id","BC") 
     ...snipped 
     .text("These boxes drawn directly to SVG canvas"); 

创建<defs>部分,也包含同样复杂的层次结构,所以内容将不会被渲染。层次结构的顶层组是'USEgrp'。

var reusables = svgContainer.append("defs") 

    var USEgrp = reusables.append("g") 
     .attr("id","Ugrp") 
    var AA = USEgrp.append("rect")...etc 
    var AB = USEgrp.append("rect")...etc 
    var AC = USEgrp.append("text")...etc 

直接克隆USEgrp,随后代码设置为组,并将其放置一个新的唯一ID:

var clonedInst1 = svgContainer 
    .append(function(){ return sidingTemplate.cloneNode(true); }) 
    .attr("id","clonedInst1") 
    .attr("transform","translate(20,380)"); 

使用对象的方法克隆USEgrp,使得有可能向使对象与创建,控制和处理复杂层次结构的方法,在<defs>部分中定义一次。这是我的目标。

var boxCollection = { 
     new: function (parent) { 
     var defaultID = "instance"; 
     var ID = '_'+ defaultID + "-" + Math.random().toString(36).substr(2, 9); 
     var template = document.getElementById("Ugrp"); 
     var objInst = svgContainer.append(function(){ return template.cloneNode(true); }) 
     .attr("id",ID) 
     .attr("transform","translate(20,140)"); 
     } 

var newInstance = boxCollection.new("svgContainer");一起用它来实例化一个副本,并设置它。

最后,我尝试了.append('use')命令,这证明几乎完全不适合于生成复杂层次结构的不同实例,其中每个实例都需要一些可预测的自定义。Firefox确实允许每个实例更改为矩形填充和笔画,但不允许文本显示(尽我所知),而Chrome则允许文本更改以及填充和笔划(闪烁很多),但仅限于所有同时定义对象的实例。

var inst1 = svgContainer.append("use") 
     .attr("xlink:href","#Ugrp") 
     .attr("id","inst1") 
     .attr("transform","translate(20,260)"); 

我测试用侧翻和部署事件来改变和恢复填充,笔触中风宽度&文本访问矩形和文字的能力。

的代码可以在https://jsfiddle.net/nohjose/1mktmbvp/9/

相关问题