将SVG绘制到Canvas中并使用其ID操纵绘制的元素

时间:2013-09-11 11:06:25

标签: javascript html canvas svg

我将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()方法)?有没有办法实现这个目标?如果是,我如何参考这些群组?此外,阴影是一个关键问题,我不想使用闪光灯。感谢

4 个答案:

答案 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/中运行此代码段,您将获得:

loaded svg

让我们检查一下这个分组对象:

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';

greenland in 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元素。

https://svgdotjs.github.io/

还有一个从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或名称访问和操作图层和对象。