将 SVG 对象存储在数组中以供加载
Storing SVG objects in an array for loading
我在使用 Snap.svg API 中的函数 Element.append(el)
时遇到了一些问题。我需要将该 SVG 的一个实例存储在一个变量数组中,以便我可以在整个 运行 时间内访问特定的变量。
当我尝试将此代码存储到 groupViews
中时,它起作用了。但是,把它放在一个数组 (groupView
) 给我带来了这个错误:
Uncaught TypeError: Cannot read proerty 'append' of undefined
当我登录 groupViews
和 groupView[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
问题是您在循环内使用了异步函数,因此文件直到完成后才会加载(特别是因为您调用了同一个文件 numOfGroups - 1
次。基本上当结果确实 return,i 已经处理了整个数组并且 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
次请求,并将回调加载到内存中,第二种解决方案实际上效率很低。唯一需要的时候是你真的要调用不同的文件。
最后我会给你一个简单的例子来说明正在发生的事情。
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>
试试这样的方法,它使用了 clone(),因为看起来您每次都在加载同一个 SVG 文件,所以我们可以加载一次,然后 clone() 以保存对服务器的重复调用.
这取决于 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' });
}
我在使用 Snap.svg API 中的函数 Element.append(el)
时遇到了一些问题。我需要将该 SVG 的一个实例存储在一个变量数组中,以便我可以在整个 运行 时间内访问特定的变量。
当我尝试将此代码存储到 groupViews
中时,它起作用了。但是,把它放在一个数组 (groupView
) 给我带来了这个错误:
Uncaught TypeError: Cannot read proerty 'append' of undefined
当我登录 groupViews
和 groupView[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
问题是您在循环内使用了异步函数,因此文件直到完成后才会加载(特别是因为您调用了同一个文件 numOfGroups - 1
次。基本上当结果确实 return,i 已经处理了整个数组并且 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
次请求,并将回调加载到内存中,第二种解决方案实际上效率很低。唯一需要的时候是你真的要调用不同的文件。
最后我会给你一个简单的例子来说明正在发生的事情。
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>
试试这样的方法,它使用了 clone(),因为看起来您每次都在加载同一个 SVG 文件,所以我们可以加载一次,然后 clone() 以保存对服务器的重复调用.
这取决于 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' });
}