What I am trying to achieve:
Generate an SVG file from html canvas using javascript.
What I have tried:
I am generating the image I need using HTML canvas using canvas's CanvasRenderingContext2D and createCanvas().
Writing it to an svg file using canvas's toBuffer() and node's writeFileSync() functions.
The problem:
The generated file is not an actual vector image, but a flattened image in svg format.
This does not allow design softwares to modify the svg.
Something like:
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="800pt" height="800pt" viewBox="0 0 800 800" version="1.1">
<defs>
<image id="image47" width="800" height="800" xlink:href="data:image/png;base64,iVBORw0KGgoAAAA
//...
</defs>
<g id="surface36">
<use xlink:href="#image47"/>
</g>
</svg>
Is it possible to generate an actual vector (that can be edited in design softwares) from the HTML canvas using any other approach / third party libraries?
I can't get the children from the svg fragment pre-entered in the string.
Need return content <g> element from source string;
Example:
has dom:
<svg>
<g class="parent"> <rect ... /> </g>
<svg>
let strNewContent = '<g class="draggable-group" data-id-device="Light-X[room-1549613406671][0]"> <rect height="75" width="184" x="8" y="0" fill="#DDD" rx="6" ry="6" /> </g>'; // created svg string using handlebars.js
// need replace old content in new content
// need extrude `<rect ... /> & etc...` from string and put (innerSVG)
$('.parent').html($(strNewContent).html()) // I understand it won't work. (It's just to understand what I mean.)
d3.select(svgElem).html(d3.select(svgElem).html()); // костыль для обновления svg документа
ps:Thank you for your patience and understanding for my English
need extrude <rect ... /> & etc... from string and put (innerSVG)
I understand that this can be done in 2 ways (as I can see): by a regular expression, cut the content or convert it to a fragment and try to squeeze out the content and add it to a new element as content (helped by #altocumulus). But I really already tried, many times to convert to a fragment and to squeeze out contents, nothing turns out (only now came to the decision, with a regular expression)(now I will experiment).
ps: What's best to correct (title) the issue for everyone to deal with this problem to solve it?
I have a problem with the use of a canvas in svg, using foreignObject.
The probleme is that the canvas is inserted in a group, which have a transformation (translation or rotation or scale), but the canvas isn't printed with the transformation.
I am on Chrome.
You can see my example there :
https://jsfiddle.net/Surre/qjrvxgos/
<body>
<svg width="400px" height="300px" viewBox="0 0 400 300"
xmlns="http://www.w3.org2000/svg">
<g transform='translate(250,10)rotate(40)'>
<foreignObject height="700" width="370" y="0" x="0">
<span xmlns="http://www.w3.org/1999/xhtml">
<canvas id="canvas" width="400px" height="300px" fill-style="#FF0000"></canvas>
<div>Comment</div>
</span>
</foreignObject>
</g>
</svg>
</body>
The "Comment" has the good transformation, but the canvas hasn't.
But if you use dev tools and inspect element canvas, you will see that it's like he is in the good place, with the transformation.
Hoping you can help me.
Thanks
From what I understand, this is actually a bug in chrome that's been known about since 2015 https://bugs.chromium.org/p/chromium/issues/detail?id=467484 There's talk of fixing it
I needed a solution too though, so here's what I've put together; I use the image element (which functions fine in svg) in conjunction with a hidden canvas. The system draws all it likes to the canvas, then transfers the canvas data to the image element.
imageElement.setAttribute('href',hiddenCanvas.toDataURL("image/png"));
It's an extra step, but it produces essentially the same result. In my project I've bundled this all together into an JS element maker
this.canvas = function(id=null, x=0, y=0, width=0, height=0, angle=0, res=1){
var canvas = document.createElement('canvas');
canvas.setAttribute('height',res*height);
canvas.setAttribute('width',res*width);
var image = document.createElementNS('http://www.w3.org/2000/svg','image');
image.id = id;
image.style = 'transform: translate('+x+'px,'+y+'px) scale('+1/res+') rotate('+angle+'rad)';
image.setAttribute('height',height*res);
image.setAttribute('width',width*res);
return {
element:image,
canvas:canvas,
context:canvas.getContext("2d"),
c:function(a){return a*res;},
print:function(){
this.element.setAttribute('href',this.canvas.toDataURL("image/png"));
}
};
};
It's kinda clunky, but I think it's what you need. It also handles resolution with the 'res' argument, and the 'c' function (which you can use with any of the canvas drawing functions
canvas.context.fillRect(canvas.c(0), canvas.c(0), canvas.c(width), canvas.c(height));
I think you neither rotate nor transform your canvas. If you want to rotate/transform it you can use CSS style. See the below code.
.transform {
-ms-transform:translateX(200px) rotate(40deg) translateY(130px); /* IE 9 */
-webkit-transform:translateX(200px) rotate(40deg) translateY(130px); /* Chrome, Safari, Opera */
transform:translateX(200px) rotate(40deg) translateY(130px);
background:#FF0000;
}
This css code will work on most of the browsers. You can use this class in your example like the following.
<canvas id="canvas" width="400px" height="300px" class="transform"></canvas>
You can see on https://jsfiddle.net/qjrvxgos/3/ your example with my update.
Canvas and SVG are different libraries, you can't use them together. You can convert one to another to do what you need. see the following link may it helps you http://www.inkfood.com/svg-to-canvas/ also you can do your example like the following example
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g transform='translate(250,10)rotate(40)'>
<rect x="10" y="20" height="50" width="75"
style="stroke: #ffff00; fill: #ff0000"/>
<text x="10" y="90" style="stroke: #660000; fill: #ff0000">
Comment</text>
</g>
I'm trying to view a polygon with dynamic coordinates (retrieved from the server) inside a svg space.
What i want to happen is that this polygon will be stretched over the entire svg, instead what i was able to achieve is either viewing a very small polygon or not viewing it at all.
Here is my best attempt so far:
<svg width="100%" viewBox="4980 4980 5020 5020">
<polygon points="5020,5000 5010,5017.320508075689 4990,5017.320508075689 4980,5000 4990,4982.679491924311 5010,4982.679491924311"></polygon>
</svg>
The last two parameters of viewBox are width and height.
<svg width="100%" height="100%" viewBox="4980 4980 40 40">
<polygon points="5020,5000 5010,5017.320508075689 4990,5017.320508075689 4980,5000 4990,4982.679491924311 5010,4982.679491924311"></polygon>
</svg>
The idea is pretty simple:
I have an SVG path and an Rect,
I need to make the path carve through the Rect, the resulting "hole" should be see-through.
Here's jsfiddle with a copy of how it's looking right now:
https://jsfiddle.net/9u0jyhr7/embedded/result/
current HTML example:
<div id="container">
<svg id="theSVG" xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect id="theRect" width="100%" height="100%" fill="#ffffff"></rect>
<path id="thePath" d="M7 25.69305419921875L7 25.6875L7.00505256652832 25.6875L293.9971923828125 25.6875L294 25.6875L294 25.709388732910156L294 90.67454528808594L294 90.6875L294.0021667480469 90.6875L321.85845947265625 90.6875L321.8607482910156 90.6875L294 183.69180297851562L294 206.421142578125L294 206.42408752441406L294 206.42701721191406L294 228.93441772460938L294 228.936279296875L294 228.93814086914062L294 248.68634033203125L294 248.6875L294.0007629394531 248.6875L304.7754211425781 248.6875L304.7763671875 248.6875L304.7773132324219 248.6875L306.581298828125 248.6875L306.581298828125 248.6875L306.582275390625 248.6875L306.582275390625 248.6875L306.583251953125 248.6875L306.583251953125 248.6875L324.73028564453125 248.6875L324.7316589355469 248.6875L324.7330017089844 248.6875L330.1683044433594 248.6875L330.1697998046875 248.6875L330.1712951660156 248.6875L357.22027587890625 248.6875L357.22265625 248.6875L357.2250061035156 248.6875L360.99749755859375 248.6875L361 248.6875L507 172.48577880859375L507 342.3311767578125L507 342.3337097167969L502.9844665527344 341.6875L436.00836181640625 341.6875L436 341.6875L436 341.6893615722656L436 378.0494079589844L436 378.051513671875L436 378.0536193847656L436 406.68511962890625L507 448.48748779296875L507 448.4908447265625L507 578.6819458007812L507 578.6875L506.9949951171875 578.6875L479.0045166015625 578.6875L479 578.6875L289.9993591308594 341.6875L279.00048828125 341.6875L279 341.6875L278.99951171875 341.6875L273.92425537109375 341.6875L273.9237976074219 341.6875L273.92333984375 341.6875L270.4071350097656 341.6875L270.4067077636719 341.6875L270.4062805175781 341.6875L265.60040283203125 341.6875L265.6000061035156 341.6875L265.5995788574219 341.6875L264.8004150390625 341.6875L264.79998779296875 341.6875L264.7995910644531 341.6875L263.8423156738281 341.6875L263.8419189453125 341.6875L263.84149169921875 341.6875L263.2403869628906 341.6875L263.239990234375 341.6875L263.2395935058594 341.6875L253.1584930419922 341.6875L253.15809631347656 341.6875L253.15769958496094 341.6875L251.40040588378906 341.6875L251.39999389648438 341.6875L251.39959716796875 341.6875L245.081787109375 341.6875L245.0813446044922 341.6875L245.08090209960938 341.6875L223.00071716308594 341.6875L223 341.6875L9.995001792907715 578.6875L7.00505256652832 578.6875L7 578.6875L7 578.6819458007812 " fill="#000000"></path>
</svg>
</div>
Here's an image of what it would probably look like if we can carve that hole:
http://i.stack.imgur.com/5fjBR.png
The Path is dynamically generated and can be quite complex, so I can't really eyeball the result.
It has to be done in javascript (or with some very clever usage of styles).
I need the result to be a DOM node that I can eventually move between z-indexes (could be grouped? a resulting "difference" path calculated in js?).
Performance and experimental features are not an issue, this is aimed at nwjs app.
Some other notes:
I'm already using jQuery, svg.js and a bunch of other libraries, so adding
new libraries is not a problem.
The rect could also be replaced by just a color filled div, if that helps solve the problem.
Ive already tried masks and clips but couldnt come to a working solution.
Any help appreciated, Thank you in advance.
A mask is what you need. I'm not sure what you tried before, but it should do what you want.
Just create a mask like so:
<defs>
<mask id="theMask">
<rect width="100%" height="100%" fill="white"/>
<path id="thePath" d="..." fill="#000000"></path>
</mask>
</defs>
Either move the original path into the mask, or copy it and hide the original.
Then apply the mask to the rect
#theRect {
mask: url(#theMask);
}
Demo fiddle here