Adding title element to paperjs SVG (using node.js) - node.js

I would like to add a <title> element to an SVG file generate with paper.js and its exportSVG function, within a node.js application (using paperjs-jsdom package)
So far, my files look like this :
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="642" height="377" viewBox="0,0,642,377">
<g>
...
</g></svg>
And I would like it to look like this :
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="642" height="377" viewBox="0,0,642,377">
<title>toto</title>
<g>
...
</g></svg>
I have looked into jsdom (which should be included in the paperjs-jsdom package), trying to load <svg> content in a DOM, but I have not been able to make it work.

If your concern is just adding a <title> tag after the <svg> tag, a workaround without even using JSDOM could be to use a RegExp.
Here is a sketch demonstrating the solution.
// Draw a circle.
new Path.Circle({
center: view.center,
radius: 50,
fillColor: 'orange'
})
// Export Paper.js project as SVG string.
var svg = project.exportSVG({asString:true});
// Add title after <svg> tag.
svg = svg.replace(/(^<svg[^>]+>)/, '$1<title>My Title</title>');
// Show result in console.
console.log(svg);
Result is:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1151" height="937" viewBox="0,0,1151,937">
<title>My Title</title>
<g fill="#ffa500" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal">
<path d="M525.5,468.5c0,-27.61424 22.38576,-50 50,-50c27.61424,0 50,22.38576 50,50c0,27.61424 -22.38576,50 -50,50c-27.61424,0 -50,-22.38576 -50,-50z"/>
</g>
</svg>

Related

How do I <use> a named <tspan> element in an SVG document?

I'm trying to define a tspan early in an SVG document so it can be transcluded later inside a text. At least in Firefox, the following code does not produce this result.
<svg version="1.1" width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<tspan id="transcluded-text">This is a text</tspan>
</defs>
<text>
<use href="#transcluded-text"/>
</text>
</svg>
Using Firefox's Inspect tool, the use element contains a shadow DOM (#shadow-root) as expected, but the shadow DOM itself is empty.
Without using Javascript, is it possible to transclude a tspan inside a text like this?
The text element can only contain text content child elements (so, not <use>) and the only text related element the defs element can contain is <text>. So, it all points to that the <tspan> cannot be used in this way.
<svg version="1.1" width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<text x="10" y="20" font-size="20" id="transcluded-text">This is a text</text>
</defs>
<use href="#transcluded-text"/>
</svg>
Since you can not use <use> elements within a <text> element;
or a bare <tspan> within <defs>
A modern Native Web Component can do the replace job:
(this will cause a FOUC you might want to deal with)
<script>
customElements.define("svg-use-replacer", class extends HTMLElement {
connectedCallback() {
setTimeout(() => { // make sure SVG is parsed
this.querySelectorAll('use').forEach(use => {
let href = use.getAttribute("href");
let tspan = this.querySelector(href);
use.replaceWith(tspan); // .replaceWith was not available in IE
});
// if the bare <svg> is required in the DOM:
// this.replaceWith(this.querySelector("svg"));
});
}
});
</script>
<svg-use-replacer>
<svg version="1.1" width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<tspan id="foo" stroke="green">Wonderful</tspan>
</defs>
<text x="10" y="20" font-size="20">
Hello
<use href="#foo" /> Web Component
</text>
</svg>
</svg-use-replacer>
Notes
The oldskool way is to attach a class and after that Element is parsed run JavaScript on it.
With Web Components it totally does not matter WHEN the Web Component is defined.
You can execute the above script any time you want.

Using Gulp to create an SVG sprite without compression

I'm attempting to use this plugin on every SVG in a given project.
I believe the default compression or reformatting of the svg's themselves is causing issues however.
For example, I have a standard three bar menu icon:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg width="200px" height="180px" viewBox="0 0 200 180" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="Artboard-1" fill="#D8D8D8"> <rect id="Rectangle-1" x="0" y="0" width="200" height="40"></rect> <rect id="Rectangle-1" x="0" y="70" width="200" height="40"></rect> <rect id="Rectangle-1" x="0" y="140" width="200" height="40"></rect> </g> </g> </svg>
But once it's compressed:
<symbol id="menu" viewBox="0 0 200 180"> <g fill="#D8D8D8" fill-rule="evenodd"><path d="M0 0h200v40H0zM0 70h200v40H0zM0 140h200v40H0z"/></g> </symbol>
Making it impossible for me to do any animation to the different rect items that I could do with it before it was moved into the sprite.
Is there any way to turn off the compression or reformatting?
According to the documentation it should be possible to remove svgo from the transformation process via
{
shape : {
transform : []
}
}

Using predefined SVG file for creating a custom JointJS shape with ports

I have a series of pre-created SVG symbols I want to use in JointJS.
I've searched about using precreated SVGs and I found to be possible to create a complete custom elements using SVG by putting the SVG in the 'markup' property - (https://groups.google.com/forum/#!topic/jointjs/pQvN_0lXPVk).
Below is the example of an SVG. Your help about how can I embed this definition in the markup property and add ports to it will be highly appreciated.
Thanks
<?xml version="1.0" standalone="no"?>
<svg viewBox="0 0 1024 768" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" stroke-linecap="round" stroke-linejoin="round" fill-rule="evenodd" xml:space="preserve" >
<defs >
<clipPath id="clipId0" >
<path d="M0,768 1024,768 1024,0 0,0 z" />
</clipPath>
</defs>
<g stroke-width="0.1" clip-path="url(#clipId0)" fill="none" stroke="rgb(0,0,0)" />
<g stroke-width="0.25" clip-path="url(#clipId0)" fill="rgb(0,0,0)" stroke="none" >
<path d="M1013.96,634.98 10.0392,634.98 1013.96,133.02 z" />
</g>
<g stroke-width="0.25" clip-path="url(#clipId0)" fill="none" stroke="rgb(0,0,0)" >
<polyline points="10.0392,133.02 1013.96,133.02 1013.96,634.98 10.0392,634.98 10.0392,133.02 " />
<polyline points="10.0392,634.98 1013.96,133.02 " />
</g>
</svg>
You can add the SVGImageElement to your markup to display arbitrary SVG in your shapes. Just convert the SVG file content to dataURL and set the xlink:href attribute.
var shape = new joint.shapes.basic.Image({
// markup: '<g class="rotatable"><g class="scalable"><image/></g><text/></g>',
attrs: {
image: {
'xlink:href': 'data:image/svg+xml;utf8,' + encodeURLComponent(svgFileContent)
}
}
});
http://jsfiddle.net/kumilingus/eqen3pdf/
In order to create a shape showing an SVG image and yet having ports you can e.g. use devs.Model shape and replace the only SVGRectElement in its markup with an SVGImageElement.
new joint.shapes.devs.Model({
markup: '<g class="rotatable"><g class="scalable"><image class="body"/></g><text class="label"/><g class="inPorts"/><g class="outPorts"/></g>',
attrs: {
'.body': {
'xlink:href': 'data:image/svg+xml;utf8,' + encodeURLComponent(svgFileContent)
},
inPorts: ['in'],
outPorts: ['out']
});
http://jsfiddle.net/kumilingus/tm2ctvxq/
Note, that it's possible to insert the SVG file content directly into your markup (without <?xml version="1.0" standalone="no"?>). I would not recommended it for more complex SVG though.
For instance when SVG contains an SVGClipPathElement with an id. Creating 2 instances of your shape breaks condition that all the IDs in the SVG must be unique.

SVG Foreign Object not displaying with SVG Namespace

I have the following SVG file.
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!--<svg width="100%" height="500">-->
<svg id="deviceImage" class="DeviceImage" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMinYMin" currentScale="1" width="3000px" height="1500px" oncontextmenu="return false">
<script type="text/ecmascript">
<![CDATA[
function ExmpleFunction(event, componentGroup)
{
alert('Hello World');
}
]]>
</script>
<defs>
<!-->>>TestShape>>>-->
<symbol id="TestShape">
<polygon points="1,1 650,1 630,175 21,175"></polygon>
</symbol>
<!--<<<TestShape<<<-->
</defs>
<!--TestShape-->
<g id="p1" transform="translate(50, 35)" visibility="visible">
<use id="p2Basic" xlink:href = "#TestShape"/>
</g>
<rect x="500" y="10" width="100" height="150" fill="blue"/>
<foreignObject x="0" y="0" width="200" height="250">
<div xmlns="http://www.w3.org/1999/xhtml">
<embed id="wert" src="TestModule-Basic.svg" type="image/svg+xml" />
</div>
</foreignObject>
</svg>
The aim is to embed another svg image which supports the internal script (so this can't be done as an image) so I am using foreignObject
When run the above code displays the test shape and the rectangle, but it does not display the svg image in the foreignObject.
By experimenting I discovered that if I remove the xmlns="http://www.w3.org/2000/svg" from the main SVG node, the svg image in the foreignObject is displayed but the test shape and rectangle are not displayed. I also see the text within the script tag as part of the image.
I obviously need to include the svg namespace but I am not sure how I get both to display?
All help appreciated!

How to change the color of an embeded SVG image

I have an SVG image element in my code.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<image id="svg_social-link" x="20" y="20" width="17" height="17" xlink:href="mail-dark.png" />
</svg>
The image mail-dark.png is "Black" in color now.
I need to change its color. For example say to "green".I have tried using css as
<style>
#svg_social-link {
fill: green;
}
</style>
But its not worked. Is there any way to do this.
AFAIK, You can not change the background color in a SVG image, you could do it if the image is the HTML code (out of SVG).
However you could do it in SVG with a workaround, using a rect as background:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect x="20" y="20" width="17" height="17" id="bk_rect" style="fill:#800000;"/>
<image id="svg_social-link" x="20" y="20" width="17" height="17" xlink:href="mail-dark.png" />
</svg>
You can set the bk color inline or modify it using JS or CSS
$('#bk_rect').css('fill', '#aaaaaa');
I created JSFiddle: http://fiddle.jshell.net/7dcnZ/1/ To show it

Resources