Discover clipped elements - javascript

If I clip a bunch of SVG elements, is there some way to use the SVG API to determine whether each of those elements is affected by the clip?
In other words, given the following:
<svg>
<defs>
<clipPath id="aClip">
<rect x="10" y="10" width="90" height="90"/>
</clipPath>
</defs>
<circle cx="50" cy="50" r="10" clip-path="url(#aClip)" />
<circle cx="150" cy="50" r="10" clip-path="url(#aClip)" />
<circle cx="150" cy="150" r="10" clip-path="url(#aClip)" />
</svg>
..is there any way I can tell which circle elements are clipped without resorting to drawing the elements and using canvas to check for raster overlap?

Related

SVG - Draw shapes along the circle path

How to draw shapes as a stroke for Circle in SVG ?
Something like this:
Try this
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" stroke="blue" stroke-width="5" stroke-dasharray="3" fill="transparent" />
Sorry, your browser does not support inline SVG.
</svg>
Adjust the stroke-width and stroke-dasharray

Expanding A Mask in Javascript

I have a circular, image mask set up in HTML to cover an image.
Here is that code for reference:
<div id="group-focus">
<svg height="800" viewbox="0 0 1000 800">
<defs>
<mask id="text-mask" maskUnits="userSpaceOnUse"
maskContentUnits="userSpaceOnUse">
<circle cx="600" cy="400" r="400" fill="white">
</mask>
</defs>
<!-- this is the image that I masked -->
<g mask="url(#text-mask)">
<image id="text-focus" width="2560" height="1440"
y="0" x="0" xlink:href="img/Asset13x.png" />
</g>
</svg>
</div>
Because I have the mask size set in HTML to the size I want, I am unsure of how to go about expanding the mask to a different size. Can you animate a mask in Javascript? This is for a motion graphic project I am working on currently.
Thanks!

What is the best approach for overlapping SVG elements area fill?

I am studying some basic image manipulations with SVG and trying to find optimal approach for the following challenge:
We have one SVG file which has various SVG elements (circles, rectangle, triangle). They all are overlapping each other creating new "areas" of different forms (see pic).
So filling actual Elements - no problem there. But what if I want to fill with color only specific intersect area?
My current thinking was:
Consider drawing all elements as Paths, then see if I can treat overall composition as One large path and then play with fill-rule.
Consider calculating the area shape and drawing a new shape on top of it, then fill it.
Consider something else?
Michael's filter method is cool and tricky, but perhaps a little hard to understand.
You can also do it with masks.
<svg width="391" height="400">
<defs>
<!-- define the shapes in the image, which we will use for the outlines
and for creating intersection masks -->
<rect id="square" x="92" y="48" width="218" height="218"/>
<polygon id="triangle" points="54,366 277,366 165,142"/>
<circle id="circle" cx="256" cy="264" r="85"/>
<!-- the masks -->
<!-- white parts are visible, black parts are invisible -->
<mask id="square-minus-triangle">
<!-- square with triangle cut out of it -->
<use xlink:href="#square" fill="white"/>
<use xlink:href="#triangle" fill="black"/>
</mask>
<mask id="triangle-minus-square">
<!-- triangle with square cut out of it -->
<use xlink:href="#triangle" fill="white"/>
<use xlink:href="#square" fill="black"/>
</mask>
</defs>
<!-- background -->
<rect width="100%" height="100%" fill="#e5e4da"/>
<!-- the intersection shapes (yellow) -->
<!-- first draw the circle, but use the square-minus-triangle mask.-->
<use xlink:href="#circle" fill="#e4e400" mask="url(#square-minus-triangle)"/>
<!-- draw the circle again, but use the triangle-minus-square mask.-->
<use xlink:href="#circle" fill="#e4e400" mask="url(#triangle-minus-square)"/>
<!-- draw the outlined shapes -->
<g fill="none" stroke="black" stroke-width="6">
<use xlink:href="#square"/>
<use xlink:href="#triangle"/>
<use xlink:href="#circle"/>
</g>
</svg>
You can do this with filters. An easy way to do is to use near transparent fill and then use a filter to dial the non-overlapping areas to fully transparent and the overlapping areas to fully opaque. It makes the stroke a little crispy though.
<svg height="600px" width="800px">
<defs>
<filter id="opacitychange">
<feComponentTransfer>
<feFuncA type="linear" intercept="-.05"/>
</feComponentTransfer>
<feComponentTransfer>
<feFuncA type="gamma" amplitude="4" exponent=".4"/>
</feComponentTransfer>
</filter>
</defs>
<g filter="url(#opacitychange)">
<circle stroke="black" fill="blue" fill-opacity="0.05" cx="150" cy="150" r="100"/>
<rect stroke="black" x="200" y="100" width="100" height="300" fill="blue" fill-opacity="0.05"/>
<polygon stroke="black" points="50,50 50,400 300,400" fill="blue" fill-opacity="0.05"/>
</g>
</svg>

Animated SVG Mask Wipe

Here's a storyboard of the CSS/JS/SVG animation I'm trying to accomplish. Two triangle masks enter from either side, then intersect resulting in a negative mask:
The point where the triangles intersect is where it gets tricky. When I export the mask for panel 4 to SVG, it looks like this:
<svg width="416px" height="289px" viewBox="0 0 416 289" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path d="M211.503681,65.6626347 L507.009604,-138.787586 L507.009604,425.787586 L211.507182,221.339788 L-84,425.792431 L-84,-138.787586 L211.503681,65.6626347 Z M211.503681,65.6626347 L99,143.5 L211.507182,221.339788 L324.01001,143.502422 L211.503681,65.6626347 Z" id="path-1"></path>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<rect id="Rectangle-1-Copy-3" fill="#F6A623" x="0" y="0" width="416" height="289"></rect>
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="Combined-Shape" fill="#000000" xlink:href="#path-1"></use>
<rect id="Rectangle-1-Copy-2" fill="#4990E2" mask="url(#mask-2)" x="0" y="0" width="416" height="289"></rect>
</g>
</svg>
It looks like it's basically drawing two shapes, the negative-space diamond mask in the center and the remainder of the outer triangles.
So the static mask itself appears to be possible with SVG, but I don't know how to animate it. Is there a library that can simplify this kind of SVG transition/tweening, or a fancy math equation that can calculate the paths dynamically?
Or am I looking at this the wrong way entirely and there's a much easier way to do it altogether?
So the solution was to make it both more simple AND more complicated.
Instead of two layers on top of each other with one mask, I needed three layers. One on the bottom to show behind the first mask, the second to be masked by the incoming triangles, and a third layer above that, duplicate to the first, where a diamond-shaped mask is applied.
<svg width="500" height="300" viewbox="0 0 500 300">
<defs>
<clipPath id="triangles">
<path id="left" d="M-250,-150 L250,150 L-250,450 Z" fill="black" />
<path id="right" d="M250,150 L750,-150 L750,450 Z" fill="black" />
</clipPath>
<clipPath id="diamond">
<path id="diamond-path" d="M250,0 L500,150 L250,300 L0,150 Z" fill="black" />
</clipPath>
</defs>
<!-- bottom -->
<g id="bottom">
<rect fill="darkorange" x="0" y="0" width="500" height="300" />
<text x="50%" y="65%" text-anchor="middle" class="text">Text</text>
</g>
<!-- middle/triangles -->
<g id="middle" clip-path="url(#triangles)">
<rect fill="dodgerblue" x="0" y="0" width="500" height="300" />
<text x="50%" y="65%" text-anchor="middle" class="text">Text</text>
</g>
<!-- top/diamond -->
<g id="top" clip-path="url(#diamond)">
<rect fill="darkorange" x="0" y="0" width="500" height="300" />
<text x="50%" y="65%" text-anchor="middle" class="text">Text</text>
</g>
</svg>
The top layer with the diamond path starts out scaled to 0, making it invisible. The two triangle clip paths are animated in towards each other, showing the bottom layer underneath. When the two triangle points meet, the diamond clip path on the top layer is scaled up, revealing the top layer which is a duplicate of the bottom.
I also switched to clip paths instead of masks because they're a) better supported and b) allow for multiple paths.
Here's a Codepen using CSS for the animations (only works in WebKit for the moment).
UPDATE: Here's a Codepen using GSAP that works in all browsers: http://s.codepen.io/kgrote/debug/mPxzZY

SVG and cross reference with javascript/jQuery

Imagine this situation:
<svg height="0px">
<defs>
<g id="img">
<circle id="cir1" cx="10" cy="10" r="5"/>
<circle id="cir2" cx="30" cy="10" r="5" />
<rect id="rect1" x="50" y="5" width="20" height="10" />
</g>
</defs>
</svg>
<div id="div1">
<div id="div2" style="width:100px; height: 50px; border: 1px solid black">
hey
</div>
</div>
<svg height="20px"><use id="img1" xlink:href="#img"/></svg>
<svg height="20px"><use id="img2" xlink:href="#img"/></svg>
<svg height="20px"><use id="img3" xlink:href="#img"/></svg>
<svg height="20px">
<circle id="cir5" cx="10" cy="10" r="5"/>
</svg>
It's possible to change the color ONLY of the first circle of the image with id=img1 using jQuery/javascript?
Something like
$("#img1 #cir1").css("fill","red");
I tried but it doesn't work.
If can be helpful here's the fiddle: http://jsfiddle.net/MaxMarkson/q6Wep/
That's not possible. Think of the <use> as being paint the referenced item here. If you alter the referenced item then all the <use> instances will change.
The authors of the SVG specification have noticed that people often want to do this sort of thing and there is a SVG parameterisation proposal which may become part of SVG 2. The examples in the parameterisation proposal are created using javascript so you could do it that way right now if you copy the mechanism there.

Categories

Resources