How should I connect SVGs using canvas in responsive environment using HTML5? - css

I have 2 SVG rectangles connected by one canvas. I tried HTML5 to make it responsive. SVG is reacting to the code, but the canvas is static, so the connection between them is lost. What can i do?

Try to use an svg element as a ViewBox.
e.g.:
<svg viewBox="0 0 1 1">
<rect width="0.4" height="0.3" y="0" x="0" fill="yellow"/>
<rect width="0.2" height="0.2" y="0" x="0" fill="blue"/>
</svg>

<svg style="position:relative; top: 20x; left: -4px;width: 200; height: 175">
<rect x="5" y="2" rx="20" ry="20" width="100" height="150" style="fill:#FF7070;stroke:black;stroke-width:5;opacity:0.5">
</rect>
</svg>
<svg style="position:absolute; top: 80px; left: 430px">
<rect x="5" y="2" rx="20" ry="20" width="200" height="100" style="fill:#FF7070;stroke:black;stroke-width:5;opacity:0.5">
</rect>
</svg>
<canvas id="canvas1" style=" background-color : gray; position: absolute;top:112px;
left: 110px ;x-index:1;" width="323" height="7" `enter code here`>
</canvas>

Related

CSS :not() does not work on initial page load

The following CSS rotates an SVG upward pointing arrow 180 degrees when the header does NOT have the .collapsed class:
.IRE-content__header:not(.collapsed) svg {
transform: rotate(180deg);
}
But it does not seem to work when the page is first loaded, and none of the headers have the .collapsed CSS class. It only seems to work when the .collapsed class is removed.
This is for a bootstrap 4 accordion.
Inline elements aren't rotated. Set your SVG to display:inline-block
Rough example:
.IRE-content__header:not(.collapsed) svg {
transform: rotate(45deg);
color: red;
display: inline-block;
}
<div class="IRE-content__header collapsed"><svg viewBox="0 0 220 100" xmlns="http://www.w3.org/2000/svg">
<!-- Here the yellow rectangle is displayed -->
<rect x="0" y="0" width="100" height="100" fill="skyblue"></rect>
<rect x="20" y="20" width="60" height="60" fill="yellow"></rect>
</svg></div>
<div class="IRE-content__header"><svg viewBox="0 0 220 100" xmlns="http://www.w3.org/2000/svg">
<!-- Here the yellow rectangle is displayed -->
<rect x="0" y="0" width="100" height="100" fill="skyblue"></rect>
<rect x="20" y="20" width="60" height="60" fill="yellow"></rect>
</svg></div>

SVG masking not working with transform applied

I'm trying to apply mask to transformed svg element (it's simplified, I'm trying to do it with path, but structure is same). If mask is applied to element outside of transformed group, it works as expected. If I try to do the same inside , element just disappears.
HTML:
<svg width="350pt" height="100pt" >
<defs>
<pattern id="circleFill" patternUnits="userSpaceOnUse" width="5" height="5" >
<circle cx="2" cy="2" r="2" fill="red"></circle>
</pattern>
<mask id="circleMask">
<rect x="0" y="0" width="100%" height="100%" fill="url(#circleFill)" />
</mask>
</defs>
<g transform="translate(0,150) scale(.1,-.1)">
<rect class="holder" x="300" y="300" height="1000" width="1000"/>
<rect class="main t" x="350" y="350" height="400" width="400" />
</g>
<rect x="300" y="50" height="50" width="50" class="main masked o" />
</svg>
CSS:
.holder {
fill: darkgray;
stroke: black;
stroke-width: 2px;
}
.o{ fill: red; }
.t{ fill: purple; }
.masked{ mask: url(#circleMask); }
If I add "masked" class to second rect (with classes "main t"), it just disappears.
The following structure works:
<g class="masked">
<g transform="...">
<rect ... />
</g>
</g>
I can't use it because I have more than 50 elements in image that should have the same transform and only some of them should be masked (and there are 5 different masks).
Here's the fiddle: Fiddle
What I'm doing wrong? Is it possible to mask element inside transformed group?

How to use SVG clipPath with Pattern via CSS clip-path property?

The initial SVG figure with pattern:
<svg width="200" height="200" viewBox="0 0 100 100">
<defs>
<pattern id="img-dotted-dots" x="0" y="0" height=".08" width="7.69%">
<circle cx="2" cy="2" fill="white" r="0.8"></circle>
</pattern>
<mask id="img-dotted-mask">
<rect width="100" height="100" fill="url(#img-dotted-dots)"></rect>
</mask>
</defs>
<path d="M0 0 H 100 V 100 H 0 Z" mask="url(#img-dotted-mask)" fill="#1063B1"></path>
</svg>
Need to achieve:
One instance of the SVG figure with pattern for refferencing with CSS as clip-path.
I have tried to create SVG clipPath element and bind to CSS clip-path by this way
.figure {
width: 300px;
height: 300px;
clip-path: url(#img-dotted-clip-path);
background-color: #1063B1;
}
<div class="figure"></div>
<svg width="0" height="0" viewBox="0 0 100 100">
<defs>
<clipPath
clipPathUnits="objectBoundingBox"
id="img-dotted-clip-path">
<pattern
patternUnits="objectBoundingBox"
patternContentUnits="objectBoundingBox"
x="0" y="0" height="0.1" width="0.1">
<circle cx="0" cy="0" fill="white" r="0.5"></circle>
</pattern>
</clipPath>
</defs>
</svg>
Nothing happens.
Expected result - the same as the previous snippet.
For comparing:
If I use SVG rect - CSS clip-path works.
If pattern - doesn't
.figure {
width: 300px;
height: 300px;
clip-path: url(#img-dotted-clip-path);
background-color: #1063B1;
}
<div class="figure"></div>
<svg width="0" height="0" viewBox="0 0 100 100">
<defs>
<clipPath
clipPathUnits="objectBoundingBox"
id="img-dotted-clip-path">
<rect width="1" height="1"></rect>
</clipPath>
</defs>
</svg>
The only things that are valid inside a clip path are:
Shape elements (‘circle’, ‘ellipse’, ‘line’, ‘path’, ‘polygon’, ‘polyline’, ‘rect’)
‘text’
‘use’
Plus you can use animation elements etc to animate the clip path. However, only the shapes of those elements are used. Effects such as patterns, filters, etc are ignored.
The only way you could get the effect you want to work as a clipping path would be to add numerous <circle> elements to your <clipPath>.
<clipPath>
<circle>
<circle>
<circle>
<circle>
... etc ...
</clipPath>
But you could use a mask instead. Masks allow patterns.
.figure {
width: 300px;
height: 300px;
-webkit-mask: url(#img-dotted-mask);
mask: url(#img-dotted-mask);
background-color: #1063B1;
}
<p>This only works in Firefox</p>
<div class="figure"></div>
<svg width="0" height="0">
<defs>
<pattern id="img-dotted-pattern"
viewBox="0 0 1 1"
patternUnits="userSpaceOnUse" x="0" y="0" width="20" height="20">
<rect width="1" height="1" fill="black"/>
<circle cx="0.5" cy="0.5" fill="white" r="0.15"></circle>
</pattern>
<mask id="img-dotted-mask">
<rect width="2000" height="2000" fill="url(#img-dotted-pattern)"/>
</mask>
</defs>
</svg>
However inline SVG masks applied to HTML elements, like my example above, only work in Firefox. To get an SVG mask to work in Chrome, you would need to use mask or mask-image with an external or Data URL (as Temani has done in their answer).
You can recreate the same thing using mask combined with radial-gradient
.figure {
width: 300px;
height: 300px;
background:linear-gradient(to right,red,#1063B1);
/*radius here size here*/
-webkit-mask:radial-gradient(3px, #fff 97%,transparent 100%) 0 0/20px 20px;
mask:radial-gradient(3px, #fff 97%,transparent 100%) 0 0/20px 20px;
}
body {
background:#f2f2f2;
}
<div class="figure"></div>
Or consider the SVG inside the mask property. Make sure to escape the # and correctly set the viewbox and width/height to have a perfect repeat
.figure {
width: 300px;
height: 300px;
background:linear-gradient(to right,red,#1063B1);
-webkit-mask:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="200" height="192" viewBox="0 0 100 90"><defs><pattern id="img-dotted-dots" x="0" y="0" height=".08" width="7.69%"><circle cx="2" cy="2" fill="white" r="0.8"></circle></pattern><mask id="img-dotted-mask"><rect width="100" height="100" fill="url(%23img-dotted-dots)"></rect></mask></defs><path d="M0 0 H 100 V 100 H 0 Z" mask="url(%23img-dotted-mask)" fill="%231063B1"></path></svg>');
mask:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="200" height="192" viewBox="0 0 100 90"><defs><pattern id="img-dotted-dots" x="0" y="0" height=".08" width="7.69%"><circle cx="2" cy="2" fill="white" r="0.8"></circle></pattern><mask id="img-dotted-mask"><rect width="100" height="100" fill="url(%23img-dotted-dots)"></rect></mask></defs><path d="M0 0 H 100 V 100 H 0 Z" mask="url(%23img-dotted-mask)" fill="%231063B1"></path></svg>');
}
body {
background:#f2f2f2;
}
<div class="figure"></div>

SVG mask not clipping in firefox

I have a svg mask made of two dots cutting two holes out of a rectangle. This effect works great in webkit browsers, but in firefox I just get a solid rectangle. Firefox is meant to support svg mask - any ideas where I have gone wrong?
body {background:pink}
#overlay {
position: relative;
z-index: 99;
position: absolute;
width: 50vw;
height: 100vh;
}
svg { position:absolute;width: 100%;height:100%}
<div id="overlay">
<svg>
<mask id="mymask" >
<rect class="svg-bg" x="0" y="0" width="100%" height="100%" fill="white"/>
<circle id="hole-1" cx="50%" cy="37vh" r="12vh" fill="#000000"/>
<circle id="hole-2" cx="50%" cy="63vh" r="12vh" fill="#000000"/>
</mask>
<rect id="hole-bg" x="0" y="0" width="100%" height="100%" mask="url(#mymask)"/>
</svg>
</div>

How does SVG image pattern work with preserving aspect ratio?

I have the following svg:
<svg height="100%" width="100%" viewBox="0 0 100 100" preserveAspectRatio="none" style="display: block; position: absolute; top: 0;">
<defs>
<pattern id="img1" patternUnits="objectBoundingBox" width="100%" height="100%">
<image xlink:href="https://media.npr.org/assets/img/2016/06/22/gettyimages-467390112_custom-e8fa0c9a7224b7172555577fde25a08949bde2d2-s900-c85.jpg" x="0" y="-20" width="100" height="100"/>
</pattern>
</defs>
<polygon points="0 100, 50,50 100,100" id="abajo" style="stroke-width:0" fill="url(#img1)"/>
</svg>
It's not working as expected because it enlarge te face of the people on the image as follows:
But it should look like this:
Does having a triangular polygon affects the image? How can I solve it, I need 4 triangle figures with images inside to be clickables.
Well this is working as intended. You specify a pattern whose unit should fill the bounding box of the container, and then specify a 2:1 container - so it stretches the image. There are lots of permutations that preserve the aspect ratio of the image - it depends on exactly what behavior you want.
This is one version that preserves the aspect ratio of the SVG itself even when it's asked to fill a larger space.
<svg height="100%" width="100%" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice" style="display: block; position: absolute; top: 0;">
<defs>
<pattern id="img1" patternUnits="objectBoundingBox" width="100%" height="100%">
<image xlink:href="https://media.npr.org/assets/img/2016/06/22/gettyimages-467390112_custom-e8fa0c9a7224b7172555577fde25a08949bde2d2-s900-c85.jpg" x="0" y="-20" width="100" height="100"/>
</pattern>
</defs>
<polygon points="0 100, 50,50 100,100" id="abajo" fill="url(#img1)" />
</svg>
Or if you want to adjust the pattern itself, you can double the height of the pattern and offset it in Y to adjust for the 2:1 ratio of your container:
<svg height="100%" width="100%" viewBox="0 0 100 100" style="display: block; position: absolute; top: 0;">
<defs>
<pattern id="img1" patternUnits="objectBoundingBox" y="-100%" width="100%" height="200%">
<image xlink:href="https://media.npr.org/assets/img/2016/06/22/gettyimages-467390112_custom-e8fa0c9a7224b7172555577fde25a08949bde2d2-s900-c85.jpg" x="0" y="0" width="100" height="100" preserveAspectRatio="xMidYMax meet"/>
</pattern>
</defs>
<polygon points="0 100, 50,50 100,100" id="abajo" fill="url(#img1)" />
</svg>
This is another version that uses a filter to fill in the image.
<svg height="100%" width="100%" viewBox="0 0 100 100" style="display: block; position: absolute; top: 0; background:grey">
<defs>
<filter id="img1" x="0%" y="0%" width="100%" height="100%" >
<feImage xlink:href="https://media.npr.org/assets/img/2016/06/22/gettyimages-467390112_custom-e8fa0c9a7224b7172555577fde25a08949bde2d2-s900-c85.jpg" x="0" y="0" width="100" height="100" preserveAspectRatio="xMidYMax meet"/>
<feComposite operator="in" in2="SourceGraphic"/>
</filter>
</defs>
<polygon points="0 100, 50,50 100,100" id="abajo" filter="url(#img1)" />
</svg>

Resources