SVG change cursor from `cursor:wait` into e.g. `cursor:help` after hovering n seconds (loading time for tooltip) without scripting? - css

There has been a question about changing the cursor using before on this site, but it asked for a solution using Javascript, and it wasn't specific about when to trigger the action to change the cursor.
My question is about SVG and CSS/SMIL without the use of other scripting languages such as Javascript.
When hovering over a certain object, how to change the cursor from cursor:wait into e.g. cursor:help? The change should be triggered after an exact amount of seconds of being hovered over the object.
The use-case is clearly presented in a minimal snippet below.
MWE SNIPPET
#MOUSE_OVER_THESE{
cursor:wait;
}
<svg id="SVG"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="250"
height="175"
viewBox="0 0 250 175">
<text font-size="10" x="10" y="20">
<tspan
x="10" dy="0">Hover over the objects below. Can the cursor</tspan><tspan
x="10" dy="12">change from "cursor:wait" into e.g. "cursor:help"</tspan><tspan
x="10" dy="12.5">after about 1 second, (which will be right</tspan><tspan
x="10" dy="12.5">about when the tooltip appears on certain</tspan><tspan
x="10" dy="12.5">browsers) without using any scripting language?</tspan></text>
<g id="MOUSE_OVER_THESE">
<rect x="50" y="100" width="60" height="50" fill="red">
<title>This is a tooltip.</title>
</rect>
<rect x="150" y="100" width="60" height="50" fill="blue">
<title>This is another tooltip.</title>
</rect>
</g>
</svg>
I can not afford to use scripting languages such as Javascript, so I am wondering if there is a more native SVG with CSS/SMIL approach.

Here is a trick using transition and a hidden element.
UPDATE
The mouse need to be moved slightly in order to see the cursor change
.hide {
transition:1s visibility 1s;
cursor:wait;
}
.hide:hover {
visibility:hidden;
}
#MOUSE_OVER_THESE {
cursor:help;
}
#MOUSE_OVER_THESE:hover + .hide {
display:none;
}
<svg id="SVG"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="250"
height="175"
viewBox="0 0 250 175">
<text font-size="10" x="10" y="20">
<tspan
x="10" dy="0">Hover over the objects below. Can the cursor</tspan><tspan
x="10" dy="12">change from "cursor:wait" into e.g. "cursor:help"</tspan><tspan
x="10" dy="12.5">after about 1 second, (which will be right</tspan><tspan
x="10" dy="12.5">about when the tooltip appears on certain</tspan><tspan
x="10" dy="12.5">browsers) without using any scripting language?</tspan></text>
<g id="MOUSE_OVER_THESE">
<rect x="50" y="100" width="60" height="50" fill="red">
<title>This is a tooltip.</title>
</rect>
<rect x="150" y="100" width="60" height="50" fill="blue">
<title>This is another tooltip.</title>
</rect>
</g>
<rect class="hide" x="50" y="100" width="160" height="50" fill="transparent"></rect>
</svg>

Related

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?

Responsive SVG Mask

I have looked at several other answers on Stack:
Responsive SVG Clip Path or Mask Image
Responsive SVG image mask
But none seem to work for me. I have an SVG mask based on a path. I want it to expand to fill all available space (or contract) whilst keeping the aspect ratio of the path.
svg {
width: 100%;
height: 100%;
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="0 0 237.859 264.582" preserveAspectRatio="xMinYMin meet">
<defs>
<pattern id="triangle-image" patternUnits="userSpaceOnUse" width="3918" height="3918">
<image xlink:href="images/aspirational-photos/christian-buehner-JQFHdpOKz2k-unsplash.jpg" x="0" y="0" width="100%" height="100%" />
</pattern>
<pattern id="triangle-pattern" width="100%" height="100%" patternUnits="userSpaceOnUse">
<path id="triangle-path" d="M237.844,32.946c-0.001-9.981-4.42-19.279-12.121-25.512c-7.82-6.331-17.85-8.78-27.518-6.721
c-3.373,0.717-6.639,1.979-9.707,3.751l-129.11,74.56l-42.942,24.8C6.147,109.771-0.001,120.42,0,132.312
c0,11.892,6.149,22.541,16.449,28.487l84.623,48.833l87.457,50.486c7.179,4.143,15.193,5.435,23.174,3.736
c15.41-3.279,26.166-16.532,26.156-32.222L237.844,32.946z"
fill="#fff" fill-rule="evenodd" width="100%" height="100%" />
</pattern>
<mask id="triangle-mask" width="100%">
<rect x="0" y="0" width="100%" height="100%" fill="url(#triangle-pattern)" />
</mask>
</defs>
<rect x="0" y="0" width="100%" height="100%" fill="url(#triangle-image)" mask="url(#triangle-mask)"/>
</svg>
The SVG seems to obey the path values no matter what I do. Is there a way to make it expand or contract like an image would?
I've simplified your code in the sense that I'm applying the mask to the image instead of using patterns. Also the mask is the path. I'm not using width="100%" since the width af an svg element will take all the space available i.e 100%.
I would like to understand why you need it height="100%"
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 240 265">
<defs>
<mask id="triangle-mask">
<path d="M237.844,32.946c-0.001-9.981-4.42-19.279-12.121-25.512c-7.82-6.331-17.85-8.78-27.518-6.721
c-3.373,0.717-6.639,1.979-9.707,3.751l-129.11,74.56l-42.942,24.8C6.147,109.771-0.001,120.42,0,132.312
c0,11.892,6.149,22.541,16.449,28.487l84.623,48.833l87.457,50.486c7.179,4.143,15.193,5.435,23.174,3.736
c15.41-3.279,26.166-16.532,26.156-32.222L237.844,32.946z"
fill="#fff" />
</mask>
</defs>
<image xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/beagle400.jpg" mask="url(#triangle-mask)"/>
</svg>
Alternatively if you need all those patterns please remove width="100%"for the mask in your code.

How do I get filters to work on nested SVGs?

I'm trying to get a hover effect for some svgs. The code I'm working on is basically icons contained in an svg so they're all positioned on top of a background (it looks like a map - I want individual icons on the map to highlight on hover).
The problem is filters don't seem to have any effect on nested svg elements. I've tried putting the filter directly in the nested element and it doesn't change anything.
Here's a simple example of the code that I would like to work.
.icon:hover{
filter: sepia(100%);
}
<html>
<body>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg x="10" class="icon">
<rect x="10" y="10" height="100" width="100" style="fill: #0000ff"/>
</svg>
<svg x="200">
<rect x="10" y="10" height="100" width="100" style="fill: #0000ff"/>
</svg>
</svg>
</body>
</html>
You can use svg filters. The sepiatone filter is from https://gist.github.com/jorgeatgu/5b338cc1a4e0df901348
svg{border:1px solid}
.icon:hover{
filter: url(#sepiatone);
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<filter id="sepiatone">
<feColorMatrix type="matrix" values=".343 .669 .119 0 0 .249 .626 .130 0 0 .172 .334 .111 0 0 .000 .000 .000 1 0"/>
</filter>
</defs>
<svg x="10" class="icon">
<rect x="10" y="10" height="100" width="100" style="fill: #0000ff"/>
</svg>
<svg x="200">
<rect x="10" y="10" height="100" width="100" style="fill: #0000ff"/>
</svg>
</svg>

svg - flip upside down ex. graph

I'm trying to work out a simple svg example - creating bar graph.
However, I don't have clear grasp of how it works. I rotated an existing graph
upside down but seems like there is a small offset. Corresponding jsfiddle here - http://jsfiddle.net/rhvP8/2/
<div style="width:300px;height:300px;">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="width:100%;height:100%" viewBox="0 0 300 300">
<g>
<rect width="14.55" height="40%" x="0" y="0" fill="black"></rect>
<rect width="14.55" height="20%" x="50" y="0" fill="green"></rect>
<rect width="14.55" height="80%" x="100" y="0" fill="red"></rect>
<rect width="14.55" height="90%" x="150" y="0" fill="yellow"></rect>
<rect width="14.55" height="10%" x="200" y="0" fill="pink"></rect>
<rect width="14.55" height="60%" x="250" y="0" fill="orange"></rect>
</g>
</svg>
</div>
<div style="width:300px;height:300px;">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="width:100%;height:100%" viewBox="0 0 300 300">
<g transform="rotate(180)">
<rect width="14.55" height="40" x="-50" y="-300" fill="black"></rect>
<rect width="14.55" height="20" x="-100" y="-300" fill="green"></rect>
<rect width="14.55" height="35" x="-150" y="-300" fill="red"></rect>
<rect width="14.55" height="90" x="-200" y="-300" fill="yellow"></rect>
<rect width="14.55" height="10" x="-250" y="-300" fill="pink"></rect>
<rect width="14.55" height="60" x="-300" y="-300" fill="orange"></rect>
</g>
</svg>
</div>
The thing you need to remember is that the rotate() transform will rotate an object about the coordinates (0,0), which in this case is the top left corner of the graph. Since the graph is 300p wide and 300px tall, rotating through 180° causes the graph to spin off beyond the top left corner. A translate transform can be used to readjust the coordinates so that the drawing appears within the viewbox again. Hopefully this illustration will explain:
Here's an updated JSfiddle with a few other fixes: http://jsfiddle.net/rhvP8/4/
An alternative to squeamish's solution is just to use the version of rotate that takes the rotation origin as well: rotate(angle x y).
Since you know your graph is 300x300, using rotate(180 150 150) works fine.
Demo here
Easy way: the scaleY() CSS function, defines a transformation that resizes an element along the y-axis (vertically).
svg {
transform: scaleY(-1);
}
View browser compatibility here: https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scaleY()#browser_compatibility

Different Viewbox behaviour for inline vs embedded svg

I have an SVG image that I would like to keep as a separate file to my main html file. I am trying to make it work as an embed tag but have problems with different view box behaviour.
Below is the code that works as I would like. The viewbox takes up as much space as possible without overflowing the window
<!DOCTYPE html>
<body style="overflow:hidden; margin:0" bgcolor="#E6E6FA">
<div>
<!-- <embed src="example.svg" type="image/svg+xml" /> -->
<svg
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
viewBox="0 0 400 600">
<g stroke-width="2">
<rect height="600" width="400" stroke="#FF0" y="0" x="0" fill="#808080"/>
<rect height="80" width="100" stroke="#808080" y="80" x="40" fill="#F60"/>
<rect height="120" width="160" stroke="#808080" y="250" x="160" fill="#FC0" onclick="alert('one')"/>
</g>
</svg>
</div>
</body>
When I replace this with the embed tag that references this exact same text. The viewbox fills the width so that overflows the vertical dimension of the window.
I have worked out the answer. By moving from a width attribute to setting the width in the style attribute the problem is resolved.
html file contains a div and embed with style set widths.
<body style="overflow:none; margin:0" bgcolor="#E6E6FA">
<div style="height:100%">
<embed src="example.svg" type="image/svg+xml" style="height:100%;width:100%"/>
</div>
</body>
And the SVG file contains the view box
<svg
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
viewBox="0 0 400 600">
<g stroke-width="2">
<rect height="600" width="400" stroke="#FF0" y="0" x="0" fill="#808080"/>
<rect height="80" width="100" stroke="#808080" y="80" x="40" fill="#F60"/>
<rect height="120" width="160" stroke="#808080" y="250" x="160" fill="#FC0" onclick="alert('one')"/>
</g>
There are still some odd behaviours when shrinking the window (it only resizes properly when the width is changed with the height) so if anyone has a better answer I would be keen to hear it

Resources