将SVG对象存储在数组中以加载

时间:2017-01-04 20:04:48

标签: javascript svg snap.svg

我在使用Snap.svg API中的函数Element.append(el)时遇到了一些麻烦。我需要在变量数组中存储该SVG的实例,以便我可以在整个运行时访问特定的SVG。

当我尝试将此代码存储到groupViews时,它可以正常工作。但是,把它放在一个数组(groupView)给我带来了这个错误:

Uncaught TypeError: Cannot read proerty 'append' of undefined

当我记录groupViewsgroupView[i]时,控制台会向我显示相同的输出,所以我不确定还有什么可以尝试。

关于如何解决这个问题的任何想法?谢谢。

for(var i = 0; i < numOfGroups; i++)
  {
    var sel = '#GroupView' + i;
    groupView[i] = Snap(sel);
    console.log(groupView[i]);
    groupViews = Snap('#GroupView0');
    console.log(groupViews);


    Snap.load("/svg/groupView-12_13_2016-01.svg", function(f) {
      groupView[i].append(f);
      groupViews.append(f);


    }); //end of Snap.load(groupView)


  }

编辑(1/5):

这是我加载了空SVG的HTML代码:

<div class = "groupView0">
    <svg viewBox='0 0 3640.9 540.5' id='GroupView0'></svg>
</div>

<div class = "groupView1">
    <svg viewBox='0 0 3640.9 540.5' id='GroupView1'></svg>
</div>

因此,这就是我加载特定SVG文件并将其附加到JS中的原因。有一个更好的方法吗?

编辑(1/6):

以下是我的svg文件的一小部分:

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 20.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     viewBox="0 0 3640.9 540.5" style="enable-background:new 0 0 3640.9 540.5;" xml:space="preserve">

<g id="A" onclick="detailedView();" cursor="pointer">
    <rect id="PanelBackground" x="35.4" y="55.5" class="st2" width="173.2" height="155"/> <!--height="444" -->
    <g id="UpperBar">
        <linearGradient id="Header_20_" gradientUnits="userSpaceOnUse" x1="35.3937" y1="67.0279" x2="208.5774" y2="67.0279">
            <stop  offset="0" style="stop-color:#F68E1E"/>
            <stop  offset="0.5" style="stop-color:#F16A22"/>
            <stop  offset="0.903" style="stop-color:#F05F22"/>
            <stop  offset="1" style="stop-color:#F05C22"/>
        </linearGradient>
        <polygon id="Header" class="st3" points="35.4,55.5 208.6,55.5 208.6,78.6 35.4,78.6      "/>
        <g>
            <rect x="82.1" y="61.8" class="st4" width="121" height="10.8"/>
            <text id="GroupName" transform="matrix(1 0 0 1 82.0885 71.6627)" class="st5 st6 st7">A</text>
            <text id="FloorNumber" transform="matrix(1 0 0 1 182.3287 141.8773)" class="st2 st19 st7">X</text>
        </g>
     </g>
</svg>

执行您发布的代码后.. 如果我尝试运行如下代码:

groupName[0] = groupView[0].select('#GroupName');
groupName[0].attr({
    text: "something"
});

我收到此错误:Uncaught TypeError: Cannot set property '0' of undefined

2 个答案:

答案 0 :(得分:1)

尝试类似这样的东西,它使用clone(),因为它看起来每次都在同一个SVG文件中加载,所以我们可以加载一次,然后克隆()它以保存对服务器的重复调用。 / p>

这依赖于svg文件中包含外部标记的基础。如果它是部分svg,并且只有一个元素,则将select('svg')更改为select('group')或其他任何内容。

然后我们存储对该克隆的引用,然后将该元素附加到索引的svg元素。

这是一个完整的例子,加载的svg test.svg只是..

<svg>
  <rect x="20" y="20" width="100" height="100" />
</svg>

主要html / js

<body>
<div class="groupView0">
  <svg id="groupView0"></svg>
</div>
<div class="groupView1">
  <svg id="groupView1"></svg>
</div>
<div class="groupView2">
  <svg id="groupView2"></svg>
</div>

<script>

var sel = "#groupView";
var groupView = [];
var numOfGroups = 3;

Snap.load("test.svg",onSVGLoaded);

function onSVGLoaded ( fragment ) {
  groupView[0] = Snap( sel + '0' ).append( fragment ).select('svg');

  for( var i = 1; i < numOfGroups; i++ ) {
    groupView[i] = groupView[0].clone().appendTo( Snap( sel + i ) );
  } 

  groupView[0].attr({ fill: 'yellow' });
  groupView[1].attr({ fill: 'red' });
  groupView[2].attr({ fill: 'green' });
} 

Working example

答案 1 :(得分:0)

问题是你在循环中使用异步函数,所以文件在完成之后才会加载(特别是因为你调用相同的文件numOfGroups - 1次。基本上当结果是返回,我已经处理了整个数组,并且i的值不再在你期望的范围内(确切地说numOfGroups)。

由于groupView[numOfGroups]从未设置为值,因此未定义。

理想的解决方案是在循环之前(在回调函数中)等待外部文件加载,如下所示:

var sel = '#GroupView';
var groupView = [];
Snap.load("/svg/groupView-12_13_2016-01.svg", function(f) {
      for(var i = 0; i < numOfGroups; i++) {
          groupView[i] = new Snap(sel+i);
          groupView[i].append(f);
      }      
}); 

或者在循环范围内定义一个变量,以便在分配负载值时欺骗回调函数使用范围变量,同样如下:

for(var i = 0; i < numOfGroups; i++)
  {
    var sel = '#GroupView' + i;
    var cur = i; //This creates a scope variable for the current callback.
    groupView[i] = Snap(sel);
    console.log(groupView[i]);
    groupViews = Snap('#GroupView0');
    console.log(groupViews);


    Snap.load("/svg/groupView-12_13_2016-01.svg", function(f) {
      groupView[cur].append(f);
      groupViews.append(f);


    }); //end of Snap.load(groupView)
  }

然而,考虑到第二个解决方案对同一个文件发出numOfGroups次请求,并将numOfGroups个回调加载到内存中,实际上效率非常低。唯一需要的是你实际上打算调用不同的文件。

最后,我将举例说明正在发生的事情。

var d = document.getElementById("testOutput");
var b = document.getElementById("trigger");

function RunTest() {
  var arr = [];
  d.innerHTML = "";
  for (var i = 0; i < 10; i++) {
    d.innerHTML += "Loop: " + i;
    arr[i] = i;
    setTimeout(function() {
      d.innerHTML += "i is " + i + "<br />";
    }, 1000); //Simulates Delay while loading...
    d.innerHTML += "...Finished Loop </br>";
  }
}
<input id="trigger" type="button" onClick="RunTest()" value="Test" />
<div id="testOutput"></div>