我将SVG文件加载到<object>
标记中。我正在使用javascript来操纵这个svg中的一些元素。例如:
var theSvgXml = document.getElementById('theObject').contentDocument;
theSvgXml.getElementById('theElementId').style.display = 'inline';
theSvgXml.getElementById('theElementId').style.fill = 'red';
theSvgXml.getElementById('anotherElement').style.display = 'none';
这很完美,一切都很顺利。但我想知道是否可以用画布做同样的事情。我已经阅读了关于kinetic js,fabric js,canvg js的内容,我看到了通过文件目录,xml或图像将svg文件加载到画布中的各种方法。
但是在将这个svg文件绘制到画布之后,我可以通过它们的ID操作元素吗?
SVG是使用Adove Illustrator创建的,每个图层或组都有一个id,可以使用css选择器进行访问。再次,可以在将SVG绘制到画布上之后在画布中完成。 (请注意,SVG是巨大的,我考虑画布解决方案的唯一原因是因为svg没有显示插图画家的多重效果来创建阴影)
任何帮助都将受到高度赞赏。谢谢。
代码段:
<g id="Pockets">
<g id="Pen__x26__Radio_Arm_Pocket" class="st791"> … </g>
<g id="Pen_Pocket_Arm" class="st791"> … </g>
<g id="Card_Zipper_Arm_Pocket" class="st791"> … </g>
<g id="Radio_Pocket_Arm_Pocket" class="st791"> … </g>
<g id="Angled_Chest_Pocket_Right" class="st791"> … </g>
<g id="Angled_Chest_Pocket_Left" class="st791"> … </g>
<g id="Angled_Chest_Pocket_left_and_Right" class="st791"> … </g>
<g id="Chest_Pocket_Right" class="st791"> … </g>
<g id="Chest_Pocket_Left" class="st791"> … </g>
<g id="Chest_Pocket_left_and_Right" class="st791"> … </g>
<g id="Tool_Pocket" class="st791"> … </g>
<g id="Cargo_x2F_Mobile_Pocket_Velcro" class="st791"> … </g>
<g id="Cargo_x2F_Mobile_Pocket_Zip" class="st791"> … </g>
<g id="Cargo_x2F_Mobile_Pocket_Button" class="st791"> … </g>
<g id="Cargo_Pocket_Velcro" class="st791"> … </g>
<g id="Cargo_Pocket_Button" class="st791"> … </g>
<g id="Cargo_Pocket_Zip" class="st791"> … </g>
<g id="Back_Pocket_Right_Velcro" class="st791"> … </g>
<g id="Back_Pocket_left_Velcro" class="st791"> … </g>
<g id="Back_Pocket_left_and_Right_Velcro" class="st791"> … </g>
<g id="Back_Pocket_Right_Velcro_Button" class="st791"> … </g>
<g id="Back_Pocket_left_Velcro_Button" class="st791"> … </g>
<g id="Back_Pocket_left_and_Right_Button" class="st791"> … </g>
<g id="Back_Pocket_Right_Zip" class="st791"> … </g>
<g id="Back_Pocket_left_Zip" class="st791"> … </g>
<g id="Back_Pocket_left_and_Right_Zip" class="st791"> … </g>
</g>
从adobe illustrator导出文件后,您可以看到形成xml片段,每个组都设置了一个ID。如何将这些作为对象保存在画布中(如Fabrics.js建议使用getObjects()方法)?有没有办法实现这个目标?如果是,我如何参考这些群组?此外,阴影是一个关键问题,我不想使用闪光灯。感谢
答案 0 :(得分:9)
以下是使用Fabric执行此操作的方法:
fabric.loadSVGFromURL('/assets/72.svg', function(objects, options){
var group = fabric.util.groupSVGElements(objects, options);
group
.set({ left: 300, top: 200 })
.scaleToWidth(500)
.setCoords();
canvas.add(group);
}, reviver);
function reviver(element, object) {
object.id = element.getAttribute('id');
}
代码应该是不言自明的。我们加载SVG; Fabric在内部解析它,吐出代表每个元素的对象集。然后,我们将这些元素分组,并将它们添加到画布中的一个块中。 Reviver负责读取每个SVG元素的id并将其分配给相应的结构实例。
在http://fabricjs.com/kitchensink/中运行此代码段,您将获得:
让我们检查一下这个分组对象:
canvas.item(0) + ''; "#<fabric.PathGroup (29303): { top: 200, left: 300 }>"
及其子女:
canvas.item(0).getObjects(); // Array[2287]
让我们通过id检索一个:
var greenland = canvas.item(0).getObjects().filter(function(obj) {
return obj.id === 'path4206';
})[0];
这是所有普通的旧Javascript,如您所见。我们现在改变那个特定物体/形状的颜色:
greenland.fill = 'red';
答案 1 :(得分:1)
<canvas>
对像素进行操作,它没有像SVG这样的对象/元素的概念。因此,为了操作底层SVG所需的图像,并在每次更改后将其重新渲染到画布。
您可以使用<canvas>
方法将SVG图像放在.drawImage
上。
var cvs = document.createElement('canvas'), ctx = cvs.getContext('2d');
cvs.width = 600;
cvs.height = 300;
document.body.appendChild(cvs);
var img = new Image();
img.width = '600';
img.height = '300';
img.onload = function(){
ctx.drawImage(img,0,0);
}
img.src = 'file.svg';
但你无法操纵以这种方式创建的SVG。为此,您应该尝试转换<svg>
元素DOM do base46编码的字符串,将其设置为图像的源,然后渲染到画布。
因此,在上面的示例中,您需要
而不是img.src = 'file.svg'
img.src = 'data:image/svg+xml;base64,' + btoa( document.getElementById('mySvgElement').outerHTML );
答案 2 :(得分:1)
关于您的情况的随机想法
虽然html canvas确实有一些合成模式,但 canvas没有图像多次混合。
然而,Firefox确实如此!它是合成的多重混合扩展:
ctx.globalCompositeOperation = 'multiply';
拥有SVG的主要画布库 - &gt; Canvas翻译器是FabricJS和KineticJS,但他们都没有实现过这种乘法过滤器。在这两者中,FabricJS在这一点上更具SVG能力,我看到Kangax(FabricJS的创建者)评论了你的帖子。你可能会很好地问他是否会添加乘法过滤器;)
由于您似乎可以访问Adobe Illustrator,因此您可以尝试使用Mike Swanson令人印象深刻的SVG - &gt; Canvas翻译器。我不知道它是否处理图像过滤器,但它在制作标准的Adobe Illustrator SVG和创建Canvas图纸方面做得非常出色(如果你问我的话,非常令人印象深刻的应用程序!):http://blog.mikeswanson.com/post/29634279264/ai2canvas
在SVG中思考 - 您应该查看SVGJS库:
SVGJS是一个SVG库,可让您按ID操作SVG元素。
还有一个从Illustrator导入的扩展程序:
https://svgdotjs.github.io/importing-exporting/
最后SVGJS还有一个扩展程序,可以使图像过滤器变暗(不会倍增,但会关闭)
https://svgdotjs.github.io/plugins/svg-filter-js/
如果你绝望了......(不太可能你会绝望!)
你可以通过使用context.getImageData抓取画布像素,然后在你想要乘以的像素的每个r,g,b元素上运行此函数来“滚动自己的”乘法滤镜。
function multiply(top, bottom){
return(top*bottom/255;
}
祝你好运!
答案 3 :(得分:0)
如果您使用像kinetic这样的框架,那么您可以按其ID或名称访问和操作图层和对象。