Satisfying Chrome deprecation of # in url but breaking svg mask - javascript

svg {
width: 500px;
height: 500px;
}
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ev="http://www.w3.org/2001/xml-events" version="1.1"
viewBox="0 0 100 100"
>
<!-- MASK DEFINITION -->
<defs>
<mask id="mask" x="0" y="0" width="100" height="100">
<rect x="0" y="0" width="100" height="100" fill="#fff"/>
<rect class="rect"
x="10"
y="10"
width="20"
height="20"
>
</rect>
</mask>
</defs>
<!-- MASK DEF -->
<rect x="0" y="0" width="100" height="100" mask="url(%23mask)"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ev="http://www.w3.org/2001/xml-events" version="1.1"
viewBox="0 0 100 100"
>
<!-- MASK DEFINITION -->
<defs>
<mask id="mask" x="0" y="0" width="100" height="100">
<rect x="0" y="0" width="100" height="100" fill="#fff"/>
<rect class="rect"
x="10"
y="10"
width="20"
height="20"
>
</rect>
</mask>
</defs>
<!-- MASK DEF -->
<rect x="0" y="0" width="100" height="100" mask="url(#mask)"/>
</svg>
I have an svg with a mask. Another element uses the mask as such:
mask="url(#mask)"
While trying to satisfy this: Treat '#' as ending data URI body content
I changed my svg mask to "url(%23mask)", but that totally breaks the mask.
Does anyone know a solution to this issue? Is there a way to satisfy both chrome and the mask?
Code snippet below contains two identical svg's; the only difference is that one uses a # and the other uses %23 when defining their urls.

Related

Center elements inside SVG relative to each other-

Couldn't find it anywhere else to I might ask here :
I have svg rectangle which inside has other rectangles.
What I want to achieve is to center each of these rectangles in the centre of it's parent and in relation to each other.
If I drag rectangle 1 down I want the other one to move up to keep both of them centered - and same thing happening if I drag the other element down (should push upper one up).
Problem here is that I might have different width/heights and there would be 2 or more elements. Is there any mathematical equationfor that? Or a name that I can look for?
I would put the 3 rects inside a group and use the group as in the following example
svg{
border:1px solid;
width: 30vh;
}
<svg viewBox="0 0 100 280">
<defs>
<g id="rects">
<rect width="80" height="80" />
<rect width="60" height="25" x="10" y="10" />
<rect width="60" height="25" x="10" y="45" />
</g>
</defs>
<use xlink:href="#rects" x="10" y="10" stroke="black" fill="none" />
<use xlink:href="#rects" x="10" y="100" stroke="black" fill="none" />
<use xlink:href="#rects" x="10" y="190" stroke="black" fill="none" />
</svg>

Can I add a mask to an svg-element without using an id?

I want to assign a svg-mask to a svg-image. I can make this work using an id on the mask like this:
<svg id="svg1" width="5cm" height="5cm" viewBox="0 0 200 200"
xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<mask id="mask">
<circle cx="100" cy="100" r="100" fill="white"></circle>
</mask>
</defs>
<rect x="0" y="0" width="200" height="200" fill="red" mask="url(#mask)"></rect>
</svg>
However I want to load this svg multiple times, with a different id in the svg-tag. Therefore I will generate duplicates of the '#mask'-id. Using multiple id's is invalid code. So I want to use a class to refer to the appropriate mask. That means I cannot use the mask=url()-technique.
<svg id="svg2" width="5cm" height="5cm" viewBox="0 0 200 200"
xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<mask class="mask">
<circle cx="100" cy="100" r="100" fill="white"></circle>
</mask>
</defs>
<rect x="0" y="0" width="200" height="200" fill="red" mask="url(can't use this)"></rect>
</svg>
Is there a way I can apply a mask to the rect element if the mask has a class instead of id? Maybe using javaScript or some other way I didn't think of.
The full story/context:
I am actually making an svg image slider-module for Joomla with php. This php generates a module containing javascript, css and an svg. I use the javascript to animate the mask.
I do actually have it working with unique id's. I was just wondering if there is a way to assign a mask to an element without referring to id's. I may want to do this because my code is getting a bit more confusing to read, because I have to use some php in my javascript/svg and css for each unique id.
No. You can only reference masks via an id. You cannot reference SVG masks any other way.
According to your description I understand you have a identical grafical entity you want to mask with different forms, multiple times. Write that down DRY:
<!-- start with an invisible svg that only contains mask definitions -->
<svg width="0" height="0"
xmlns="http://www.w3.org/2000/svg">
<defs>
<!-- first, you have a circular mask -->
<mask id="circle-mask">
<circle cx="100" cy="100" r="80" fill="white" />
</mask>
<!-- then, you have a different mask, lets say a diamond -->
<mask id="diamond-mask">
<polygon points="100,20 180,100 100,180 20,100" fill="white" />
</mask>
</defs>
</svg>
<!-- further into your document, you want to mask a rectangle -->
<svg id="svg1" width="5cm" height="5cm" viewBox="0 0 200 200"
xmlns="http://www.w3.org/2000/svg">
<!-- reference the circle mask -->
<rect x="0" y="0" width="200" height="200" fill="red" mask="url(#circle-mask)" />
</svg>
<!-- with the circle again, as often as you want, nothing changes -->
<svg id="svg2" width="5cm" height="5cm" viewBox="0 0 200 200"
xmlns="http://www.w3.org/2000/svg">
<!-- the mask is the same, so no difference to above -->
<rect x="0" y="0" width="200" height="200" fill="red" mask="url(#circle-mask)" />
</svg>
<!-- and now with the diamond; that one is different -->
<svg id="svg3" width="5cm" height="5cm" viewBox="0 0 200 200"
xmlns="http://www.w3.org/2000/svg">
<!-- if the mask changes, you need to change the reference -->
<rect x="0" y="0" width="200" height="200" fill="red" mask="url(#diamond-mask)" />
</svg>
You could also reference the masks in a stylesheet and give your referencing elements a class according to the mask shape:
.masked.circular rect {
mask: url(#circle-mask);
}
.masked.diamond rect {
mask: url(#diamond-mask);
}
<svg width="0" height="0"
xmlns="http://www.w3.org/2000/svg">
<defs>
<mask id="circle-mask">
<circle cx="100" cy="100" r="80" fill="white" />
</mask>
<mask id="diamond-mask">
<polygon points="100,20 180,100 100,180 20,100" fill="white" />
</mask>
</defs>
</svg>
<svg id="svg1" class="masked circular" width="5cm" height="5cm" viewBox="0 0 200 200"
xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="200" height="200" fill="red" />
</svg>
<svg id="svg2" class="masked circular" width="5cm" height="5cm" viewBox="0 0 200 200"
xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="200" height="200" fill="red" />
</svg>
<svg id="svg1" class="masked diamond" width="5cm" height="5cm" viewBox="0 0 200 200"
xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="200" height="200" fill="red" />
</svg>

Include a png/svg inside a polygon?

I'm trying to think of the best way to include an image inside an SVG polygon element, like the below:
<svg id="graph" width="100%" height="400px">
<!-- pattern -->
<defs>
<pattern id="image" x="0%" y="0%" height="100%" width="100%"
viewBox="0 0 64 64">
<image x="0%" y="0%" width="64" height="64" xlink:href="https://cdn4.iconfinder.com/data/icons/imod/512/Software/labo.png"></image>
</pattern>
</defs>
<polygon stroke="red" stroke-width="2px" fill="url(#image)" points="300,150 225,280 75,280 0,150 75,20 225,20"></polygon>
</svg>
However, i also want to fill the polygon with a background colour fill, but as this is using the above pattern i'm not sure of the right approach.
Move your polygon into your defs, but take the fill out. Then make two copies with the use tag, the back one filled with your color and the front one filled with your image. You can also make multiple copies by including more images, changing the coordinates, etc.
<svg id="graph" width="100%" height="400px">
<!-- pattern -->
<defs>
<pattern id="image1" x="0%" y="0%" height="100%" width="100%" viewBox="0 0 64 64">
<image x="0%" y="0%" width="64" height="64" xlink:href="https://cdn4.iconfinder.com/data/icons/imod/512/Software/labo.png"></image>
</pattern>
<pattern id="image2" x="0%" y="0%" height="100%" width="100%" viewBox="0 0 64 64">
<image x="0%" y="0%" width="64" height="64" xlink:href="https://cdn4.iconfinder.com/data/icons/imod/512/Software/iPhoto.png"></image>
</pattern>
<polygon id="myShape" stroke="red" stroke-width="2px" points="300,150 225,280 75,280 0,150 75,20 225,20"></polygon>
</defs>
<use xlink:href="#myShape" fill="yellow"/>
<use xlink:href="#myShape" fill="url(#image1)"/>
<use xlink:href="#myShape" fill="orange" x="400"/>
<use xlink:href="#myShape" fill="url(#image2)" x="400"/>
</svg>

Changing SVG colors

I'm starting to learn JS and i have this (probably very easy) task that I'm having problems with.
So the main task is to make the lower green triangle change it's color depending on which color i click on upper object.
I made something like this:
<!DOCTYPE html>
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>SVG, JavaScript</title>
<script type="text/javascript">
function changeColor("triangle"){
document.getElementById("group").getAttributeNS("fill");
evt.target.setAttributeNS("fill");
}
</script>
</head>
<body>
<svg height="500" width="500">
<g id="group">
<rect x="0" y="0" width="200" height="200" style="fill:gray;stroke:none;stroke-width:0"/>
<rect id="red_triangle" x="0" y="0" width="100" height="100" style="fill:red;stroke:none;stroke-width:0"/>
<rect id="yellow_triangle"x="100" y="0" width="100" height="100" style="fill:yellow;stroke:none;stroke-width:0"/>
<rect id="blue_triangle"x="0" y="100" width="100" height="100" style="fill:blue;stroke:none;stroke-width:0v"/>
<rect id="green_triangle"x="100" y="100" width="100" height="100" style="fill:lime;stroke:none;stroke-width:0"/>
<ellipse cx="100" cy="100" rx="100" ry="100" style="fill:gray;stroke:none;stroke-width:0"/>
<polygon id="triangle" points="100,225 150,300 50,300" style="fill:lime;stroke:none;stroke-width:0" onclick="changeColor("triangle")"/>
</g>
</svg>
</body>
</html>
but obviously it's not working. Could somebody help me with some suggestion?
// the string instead of argument name raises Error: unexpected string
function changeColor("triangle"){
// you get the attribute but don't do anything with it.
// and the group doesn't even have a fill attribute
document.getElementById("group").getAttributeNS("fill");
// here you try to set an attribute but setAttributeNS requires 3 arguments: namespace, attribute and value
// simpler setAttribute would be enough, but the value would still be overwriten by style="fill:whatever"
// and evt.target is undefined, there's no evt object
evt.target.setAttributeNS("fill");
}
then in your SVG:
// the quotes are broken,
// and here you pass a string which I'd assume to be the ID of an element you want to change
onclick="changeColor("triangle")"
So, all in all:
The onclick should be on the source rectangles, not the target triangle: <rect onclick="changeColor('triangle', this)" /> where 'triangle' is the ID of element you want to change, and this is a reference to the clicked rectangle.
SVG:
<svg height="500" width="500">
<g id="group">
<rect x="0" y="0" width="200" height="200" style="fill:gray;stroke:none;stroke-width:0"/>
<rect id="red_triangle" x="0" y="0" width="100" height="100" style="fill:red;stroke:none;stroke-width:0" onclick="changeColor('triangle', this)"/>
<rect id="yellow_triangle"x="100" y="0" width="100" height="100" style="fill:yellow;stroke:none;stroke-width:0" onclick="changeColor('triangle', this)"/>
<rect id="blue_triangle"x="0" y="100" width="100" height="100" style="fill:blue;stroke:none;stroke-width:0v" onclick="changeColor('triangle', this)"/>
<rect id="green_triangle"x="100" y="100" width="100" height="100" style="fill:lime;stroke:none;stroke-width:0" onclick="changeColor('triangle', this)"/>
<ellipse cx="100" cy="100" rx="100" ry="100" style="fill:gray;stroke:none;stroke-width:0"/>
<polygon id="triangle" points="100,225 150,300 50,300" style="fill:lime;stroke:none;stroke-width:0" />
</g>
</svg>
JS:
function changeColor( target, source ){
var color = source.style.fill;
document.getElementById( target ).style["fill"] = color;
}
Fiddle: http://jsfiddle.net/harg5kyz/1/

SVG Gradient "Pie Slice"

Is it possible to shade in a corner of a shape using only gradients?
Below is an image of what I am trying to do, but had to use a circle and a path.
I know using a path is probably a better method, but I am curious if it can be accomplished with gradients.
Thank you.
Path is not the only method. Sometimes a 5 year old can outsmart me with basic shapes:-
<svg class="sheet" xmlns="http://www.w3.org/2000/svg"
xlink="http://www.w3.org/1999/xlink" version="1.1" width="200" height="200">
<pattern id="my_pattern" patternUnits="userSpaceOnUse"
width="200" height="200" viewbox="0 0 200 200">
<rect x="0" y="0" fill="#33ff33" width="200" height="200" />
<rect x="50" y="0" fill="red" width="50" height="50" />
</pattern>
<circle cx="50" cy="50" r="40" style="stroke:black; stroke-width: 2;
fill: URL(#my_pattern)"/>
</svg>
Not with a single gradient. No.

Categories