I have an svg that uses both a mask and base 64 encoded image. For some reason that combination looks like it causes issues with FabricJS.
Not sure if this is because of the clipping mask in the SVG or the base 64 encoded image, but the images within the svg are coming through with a white clipping image and no base image. Not sure what is going here. Here is the fiddle.
The top image rendering in the browser is the FabricJS rendering on the canvas and the bottom is the browser rendering of the same svg. You can see both by scrolling up and down.
http://jsfiddle.net/jonnyMitts/m8ndkq0h/1/
here is the javascript:
var svgString = `<svg
version="1.1"
id="svg2"
width="1280.0126"
height="720"
viewBox="0 0 1280.0126 720"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs6">
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath16">
<path
d="M 0,0.028 H 959.981 V 539.999 H 0 Z"
clip-rule="evenodd"
id="path14" />
</clipPath>
<mask
maskUnits="userSpaceOnUse"
x="0"
y="0"
width="1"
height="1"
id="mask24">
<image
width="1"
height="1"
style="image-rendering:optimizeSpeed"
preserveAspectRatio="none"
xlink:href="data:image/png;base64,..."
id="image26" />
</mask>
</defs>
<g
id="g8"
transform="matrix(1.3333333,0,0,-1.3333333,0,720)">
<g
id="g10">
<g
id="g12"
clip-path="url(#clipPath16)">
<path
d="M 0,540 H 959.981 V 0.028 L 0,0.028 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
id="path18" />
<path
d="M 0,540 H 960.009 V 0 H 0 Z"
style="fill:#333333;fill-opacity:1;fill-rule:evenodd;stroke:none"
id="path20" />
<g
id="g22"
transform="matrix(806.088,0,0,236.296,76.932,134.731)">
<image
width="1"
height="1"
style="image-rendering:optimizeSpeed"
preserveAspectRatio="none"
transform="matrix(1,0,0,-1,0,1)"
xlink:href="data:image/png;base64,..."
mask="url(#mask24)"
id="image28" />
</g>
<g
id="g30">
<text
xml:space="preserve"
transform="matrix(1,0,0,-1,43.313,25.512)"
style="font-variant:normal;font-weight:normal;font-size:9.014px;font-family:Helvetica;-inkscape-font-specification:Helvetica;writing-mode:lr-tb;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="text34"><tspan
x="0 6.6072621 9.1041403 14.115924 19.217848 24.229631 29.241417 31.837448 38.246403 43.348328 48.360111 51.361771 57.365097 62.467018 67.478806 70.480469 75.58239 77.781807 82.387962 87.399742 91.996887 97.008667 102.1106 107.12238 109.12348 114.22541 119.23719 123.14025 125.63713 128.134 133.23593 138.24771 144.75583 147.2527 149.35297 155.26614 157.35739 159.35851 161.85538 164.85704 166.94829 171.96008 176.97186 179.5679 184.07489 186.67093 189.57344 194.67535 199.18236 204.28429 207.28595 211.88309 216.89487 221.90665"
y="0"
id="tspan32">© 2022 NearShore Technology, LLC. All rights reserved.</tspan></text>
</g>
</g>
</g>
</g>
</svg>
`// Do some initializing stuff
const width = 2560;
const height = 1440;
// initialize fabric canvas and assign to global windows object for debug
var canvas = window._canvas = new fabric.StaticCanvas('c', { width, height });
fabric.loadSVGFromString(svgString, (objects, options) => {
var loadedObject = fabric.util.groupSVGElements(objects, options);
canvas.add(loadedObject);
canvas.renderAll();
console.log(canvas.toJSON())
});
and here is the HTML
<canvas id="c" width="300" height="300"></canvas>
<div>
<svg
version="1.1"
id="svg2"
width="1280.0126"
height="720"
viewBox="0 0 1280.0126 720"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs6">
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath16">
<path
d="M 0,0.028 H 959.981 V 539.999 H 0 Z"
clip-rule="evenodd"
id="path14" />
</clipPath>
<mask
maskUnits="userSpaceOnUse"
x="0"
y="0"
width="1"
height="1"
id="mask24">
<image
width="1"
height="1"
style="image-rendering:optimizeSpeed"
preserveAspectRatio="none"
xlink:href="data:image/png;base64,..."
id="image26" />
</mask>
</defs>
<g
id="g8"
transform="matrix(1.3333333,0,0,-1.3333333,0,720)">
<g
id="g10">
<g
id="g12"
clip-path="url(#clipPath16)">
<path
d="M 0,540 H 959.981 V 0.028 L 0,0.028 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
id="path18" />
<path
d="M 0,540 H 960.009 V 0 H 0 Z"
style="fill:#333333;fill-opacity:1;fill-rule:evenodd;stroke:none"
id="path20" />
<g
id="g22"
transform="matrix(806.088,0,0,236.296,76.932,134.731)">
<image
width="1"
height="1"
style="image-rendering:optimizeSpeed"
preserveAspectRatio="none"
transform="matrix(1,0,0,-1,0,1)"
xlink:href="data:image/png;base64,..."
mask="url(#mask24)"
id="image28" />
</g>
<g
id="g30">
<text
xml:space="preserve"
transform="matrix(1,0,0,-1,43.313,25.512)"
style="font-variant:normal;font-weight:normal;font-size:9.014px;font-family:Helvetica;-inkscape-font-specification:Helvetica;writing-mode:lr-tb;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="text34"><tspan
x="0 6.6072621 9.1041403 14.115924 19.217848 24.229631 29.241417 31.837448 38.246403 43.348328 48.360111 51.361771 57.365097 62.467018 67.478806 70.480469 75.58239 77.781807 82.387962 87.399742 91.996887 97.008667 102.1106 107.12238 109.12348 114.22541 119.23719 123.14025 125.63713 128.134 133.23593 138.24771 144.75583 147.2527 149.35297 155.26614 157.35739 159.35851 161.85538 164.85704 166.94829 171.96008 176.97186 179.5679 184.07489 186.67093 189.57344 194.67535 199.18236 204.28429 207.28595 211.88309 216.89487 221.90665"
y="0"
id="tspan32">© 2022 NearShore Technology, LLC. All rights reserved.</tspan></text>
</g>
</g>
</g>
</g>
</svg>
</div>
The base64 image code is replaced with ... in the above sample because of caharacter limits. The full same is in the fiddle.
The Fabric canvas.toJSON() out is logged in the console.
Also, I am doing the loadSVGFromString on the server, but the output seems to be the same as when it is done in the browser.
I have tried loading from URL and from a string. Both have the same output.
Related
I try to draw a shape with a path that must be reduced like in this solution Find Parallel or Offset SVG path
I use the filter "erode" but with pattern it doesn't work : the pattern is deformed.
Is there a way to do this without the bezier.js solution, with pure SVG/CSS ?
Here is a sample of my problem
I want to have the shape of the right with the pattern of the left.
<!DOCTYPE html>
<html>
<body>
<svg>
<defs>
<pattern id="circ" x="0" y="0" width="30" height="30" patternUnits="userSpaceOnUse">
<rect fill="blue" width="100%" height="100%" />
<circle cx="10" cy="10" r="10" fill="green" />
</pattern>
<filter id="erode">
<feMorphology in="SourceGraphic" operator="erode" radius="10"/>
</filter>
<path id="thing" d="M 0,0 H 50 A 35,35 0 1 0 100,50 V 75 C 50,125 0,85 0,85 Z" />
</defs>
<use href="#thing" fill="url(#circ)" width="400" height="400" filter="#erode"/>
<use x="100" href="#thing" filter="url(#erode)" fill="url(#circ)" width="400" height="400" />
</svg>
</body>
</html>
Yes. You can use a mask.
svg {
width: 300px;
}
.purple {
fill: rebeccapurple;
}
.reduce-me {
mask: url(#reducer);
}
#reduce-amount {
stroke-width: 5px;
}
<svg viewBox="0 0 100 100">
<path class="purple"
d="M 50,10 Q 100,10, 50,50 Q 0,90, 50,90
Q 100,90, 50,50 Q 0,10, 50,10 Z"/>
</svg>
<svg viewBox="0 0 100 100">
<defs>
<!-- the shared path that is used by both the purple path and the mask -->
<path id="shared-path"
id="p" d="M 50,10 Q 100,10, 50,50 Q 0,90, 50,90
Q 100,90, 50,50 Q 0,10, 50,10 Z" />
<!-- a mask that shrinks the shape by half the stroke-width -->
<mask id="reducer">
<use id="reduce-amount" xlink:href="#shared-path"
fill="white" stroke="black"/>
</mask>
</defs>
<!-- the shape that gets reduced -->
<use class="purple reduce-me" xlink:href="#shared-path"/>
</svg>
How this works
If we just render what the mask looks like (on the right) we can see how this works.
svg {
width: 300px;
}
.purple {
fill: rebeccapurple;
}
.reduce-me {
mask: url(#reducer);
}
#reduce-amount {
stroke-width: 10px;
}
<svg viewBox="0 0 100 100">
<path class="purple"
d="M 50,10 Q 100,10, 50,50 Q 0,90, 50,90
Q 100,90, 50,50 Q 0,10, 50,10 Z"/>
</svg>
<svg viewBox="0 0 100 100">
<defs>
<!-- the shared path that is used by both the purple path and the mask -->
<path id="shared-path"
id="p" d="M 50,10 Q 100,10, 50,50 Q 0,90, 50,90
Q 100,90, 50,50 Q 0,10, 50,10 Z" />
</defs>
<use id="reduce-amount" xlink:href="#shared-path"
fill="white" stroke="black"/>
</svg>
We are using the same shape as a mask. However the mask has a thick black stroke around it. Black in a mask makes things transparent. The rest of the mask is white, which stays visible.
You can alter the amount of the shape reduction by changing the stroke-width value in the .reduce-amount class.
The disadvantages of this method are:
1. you need a mask for every different path shape
2. you can't set the stroke style of the reduced size shape. However you could simulate a stroke colour by overlaying two paths with different reduction amounts.
You can extend the filter to make this work. There seems to be a bug eroding pattern filled shapes - it's not taking the minimum of the alpha channels in the radius correctly. But if you start with SourceAlpha rather than SourceGraphic and then create your mask using component transfers it seems to work.
<svg>
<defs>
<pattern id="circ" x="0" y="0" width="30" height="30" patternUnits="userSpaceOnUse">
<rect fill="blue" width="100%" height="100%" />
<circle cx="10" cy="10" r="10" fill="green" />
</pattern>
<filter id="erode3">
<feMorphology in="SourceAlpha" result="eroded"
operator="erode" radius="10"/>
<feComponentTransfer>
<feFuncR type="discrete" tableValues="1 0"/>
<feFuncG type="discrete" tableValues="1 0"/>
<feFuncB type="discrete" tableValues="1 0"/>
</feComponentTransfer>
<feComposite operator ="in" in="SourceGraphic"/>
</filter>
<path id="thing" d="M 0,0 H 50 A 35,35 0 1 0 100,50 V 75 C 50,125 0,85 0,85 Z" />
</defs>
<use href="#thing" fill="url(#circ)" width="400" height="400" filter="url(#erode3)"/>
<use x="100" href="#thing" filter="url(#erode)" fill="url(#circ)" width="400" height="400" />
</svg>
I am new to svg and have a question, how to make svg element to get bigger?
How can i control it?
player container
here is my code:
<div class="player-container">
<svg width="100%" height="100%" viewBox="0 0 97 97" 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"
opacity="0.153808594">
<g id="Car-concept" transform="translate(-193.000000, -733.000000)" fill="#8E95D7">
<g id="Group-10" transform="translate(127.000000, 596.000000)">
<g id="Group-14" transform="translate(66.000000, 137.000000)">
<circle id="Oval" cx="48.5" cy="48.5" r="48.5"></circle>
</g>
</g>
</g>
</g>
</svg>
<svg class="moving-outline" width="100%" height="100%" viewBox="0 0 453 453" fill="none"
xmlns="http://www.w3.org/2000/svg">
<circle cx="226.5" cy="226.5" r="216.5" stroke="#646DBE" stroke-width="10" />
</svg>
<h3 class="time-display">45%</h3>
</div>
I'm trying to create an header using a svg to generate a curved shape, like so
I copied the SVG code generate from Sketch, deleted some extra tags and fixed the image path
<svg viewBox="0 0 1440 638" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<path d="M-4.54747351e-13,163 L1440,163 L1440,700.10075 C1259.32216,751.363088 1140.10686,781.914324 1082.35411,791.754457 C776.214966,843.915606 628.837414,646.620792 362.433874,644.205808 C184.831514,642.595818 64.0202229,656.876199 6.73310296e-11,687.046952 L-4.54747351e-13,163 Z" id="path-1"></path>
</defs>
<g id="Header-Copy" transform="translate(0, -163.000000)">
<mask id="mask" fill="white"><use xlink:href="#path-1"></use></mask>
<use id="Rectangle-Copy-2" fill="#0BE17D" transform="translate(720.000000, 481.765165) scale(-1, 1) translate(-720.000000, -481.765165) " xlink:href="#path-1"></use>
<image style="mix-blend-mode: darken;" mask="url(#mask)" x="0" y="0" width="1462.5" height="975" xlink:href="~assets/header_bg.jpg"></image>
</g>
</svg>
But I end up with this
How can I make this work?
Remove the transform attribute from element <use id="Rectangle-Copy-2">.
<svg viewBox="0 0 1440 638" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path d="M-4.54747351e-13,163 L1440,163 L1440,700.10075 C1259.32216,751.363088 1140.10686,781.914324 1082.35411,791.754457 C776.214966,843.915606 628.837414,646.620792 362.433874,644.205808 C184.831514,642.595818 64.0202229,656.876199 6.73310296e-11,687.046952 L-4.54747351e-13,163 Z" id="path-1"></path>
</defs>
<g id="Header-Copy" transform="translate(0, -163.000000)">
<mask id="mask" fill="white"><use xlink:href="#path-1"></use></mask>
<use id="Rectangle-Copy-2" fill="#0BE17D" xlink:href="#path-1"></use>
<image style="mix-blend-mode: darken;" mask="url(#mask)" x="0" y="0" width="1462.5" height="975" xlink:href="~assets/header_bg.jpg"></image>
</g>
</svg>
I have this dummy svg showing a cirle with some grey figure inside
<svg viewBox="0 0 86 86" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<circle id="path-1" cx="43" cy="43" r="43"></circle>
</defs>
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g transform="translate(-585.000000, -391.000000)">
<g transform="translate(585.000000, 391.000000)">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="Oval" fill="currentcolor" xlink:href="#path-1"></use>
<g id="Group" mask="url(#mask-2)" fill="#b8b8b8">
<g transform="translate(21.500000, 27.823529)" id="Page-1">
<path d="M0.5,0.176470588 L0.5,58.1764706 L15.5,58.1764706 L15.5,49.1764706 L29.5,49.1764706 L29.5,31.1764706 L7.5,31.1764706 L7.5,37.1764706 Z"></path>
</g>
</g>
</g>
</g>
</g>
when I convert it to a sprite using gulp-svg-sprite with mode symbol I get this result
<?xml version="1.0" encoding="UTF-8" ?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><symbol viewBox="0 0 86 86" id="company"><defs><circle id="aa" cx="43" cy="43" r="43"/></defs><g fill="none" fill-rule="evenodd"><mask id="ab" fill="#fff"><use xlink:href="#aa"/></mask><use fill="currentcolor" xlink:href="#aa"/><g mask="url(#ab)" fill="#b8b8b8"><path d="M22 28v58h15v-9h14V59H29v6z"/></g></g></symbol></svg>
Now the grey figure breaks out of the circle and this even happens if I copy root defs- and g-tags from my original svg directly into the symbol-tag. I have also tried inserting a clipPath in the symbol version but with no luck.
What am I missing here?
UPDATED: Simplifying your svg may work ... try with the examples below, one using symbols, one without (in case the gulp sprite code cannot have nested symbols) ... it may be an issue with the defs area.
svg {
width: 100px;
}
<svg viewBox="0 0 86 86" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<symbol id="c">
<circle cx="43" cy="43" r="43" fill="currentColor" />
</symbol>
<mask id="mask" color="#fff">
<use xlink:href="#c" />
</mask>
</defs>
<use xlink:href="#c" color="#666" />
<path fill="#999" mask="url(#mask)" d="M10 0v60h30v-10h20v-20h-30v9z" />
</svg>
<svg viewBox="0 0 86 86" xmlns="http://www.w3.org/2000/svg">
<defs>
<mask id="mask2" color="#fff">
<circle cx="43" cy="43" r="43" fill="#FFF" />
</mask>
</defs>
<circle cx="43" cy="43" r="43" fill="currentColor" />
<path fill="#999" mask="url(#mask2)" d="M10 0v60h30v-10h20v-20h-30v9z" />
</svg>
It is probably not a complete answer but I managed to get it work;
First I extended my defs with a clipPath using my circle
<defs>
<circle id="circle" cx="43" cy="43" r="43"></circle>
<clipPath id="clippath"><use overflow="visible" xlink:href="#circle" /></clipPath>
</defs>
Then, using the clipPath on my first group and switching from gulp-svg-sprite to gulp-svgstore (which moves the defs to the top, above the symbols) gives me what I expect both as single svg and as an svg symbol sprite.
I have an ordinary rectangular bitmap which I would like to be able to use to fill a four-pointed SVG path - basically a mapped texture so that the four corners of the bitmap are mapped to the four points of the path and the rest of the image is 'warped' accordingly.
I have been able to fill an SVG rect with the same image and then transform the rect such that the bitmap is transformed with it:
<defs>
<pattern id="bmp" x="0" y="0" width="1" height="1">
<image x="0" y="0" width="100" height="100" href="mybmp.bmp"/>
</pattern>
</defs>
<rect x="0" y="0" width="100" height="100" fill="url(#bmp)" stroke="black" transform="skewX(10)"/>
When I try to use the bitmap to fill a path though it gets mapped to the bounding box of the path shape and not the four points of the path itself:
<defs>
<pattern id="bmp" x="0" y="0" width="1" height="1">
<image x="0" y="0" width="100" height="100" href="mybmp.bmp"/>
</pattern>
</defs>
<path d="M 0 0 L 100 0 L 120 80 L 50 120 Z" fill="url(#bmp)" stroke="black" />
Is it possible to get the same effect as the first example (texture properly mapped to the all corners of the rectangle) in an arbitrary path shape?
One solution is to give your pattern a viewBox so that its content image gets scaled to fit the pattern bounds.
<svg>
<defs>
<pattern id="bmp" x="0" y="0" width="1" height="1"
viewBox="0 0 100 100">
<image x="0" y="0" width="100" height="100" xlink:href="http://www.placekitten.com/100/100"/>
</pattern>
</defs>
<path d="M 0 0 L 100 0 L 120 80 L 50 120 Z" fill="url(#bmp)" stroke="black" />
</svg>
Depending on the shape of your path, you may also need to set preserveAspectRatio="xMidYMid slice". This will ensure that the pattern gets scaled to a size large enough to cover the whole path with no gaps.
<svg>
<defs>
<pattern id="bmp" x="0" y="0" width="1" height="1"
viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice">
<image x="0" y="0" width="100" height="100" xlink:href="http://www.placekitten.com/100/100"/>
</pattern>
</defs>
<path d="M 0 0 L 100 0 L 120 80 L 50 120 Z" fill="url(#bmp)" stroke="black" />
</svg>