Creating a SVG image tooltip - svg

hi guys i need some help i need to create a tooltip with an image inside it however this is for an svg map so i cant use divs like in css and html.I have managed to create an image tooltip .However only one image can appear when i hover on all elements how can i make different images appear for different svg elements ? this is the code i have used for my tooltip:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="init(evt)" width="380" height="100">
<style>
.caption{
font-size: 14px;
font-family: Georgia, serif;
}
.tooltip{
font-size: 12px;
}
.tooltip_bg{
fill: white;
stroke: black;
stroke-width: 1;
opacity: 0.85;
}
</style>
<script type="text/ecmascript">
<![CDATA[
function init(evt)
{
if ( window.svgDocument == null )
{
svgDocument = evt.target.ownerDocument;
}
tooltip = svgDocument.getElementById('tooltip');
tooltip_bg = svgDocument.getElementById('tooltip_bg');
}
function ShowTooltip(evt, mouseovertext)
{
tooltip.setAttributeNS(null,"x",evt.clientX+11);
tooltip.setAttributeNS(null,"y",evt.clientY+27);
tooltip.setAttributeNS(null,"visibility","visible");
length = tooltip.getComputedTextLength();
tooltip_bg.setAttributeNS(null,"width",length+8);
tooltip_bg.setAttributeNS(null,"x",evt.clientX+8);
tooltip_bg.setAttributeNS(null,"y",evt.clientY+14);
tooltip_bg.setAttributeNS(null,"visibility","visibile");
}
function HideTooltip(evt)
{
tooltip.setAttributeNS(null,"visibility","hidden");
tooltip_bg.setAttributeNS(null,"visibility","hidden");
}
]]>
</script>
<text class="caption" x="10" y="35">Mouseover a square</text>
<text class="caption" x="10" y="50">to display a tooltip</text>
<rect id="rect1" x="160" y="10" width="60" height="60" fill="blue"
onmousemove="ShowTooltip(evt)"
onmouseout="HideTooltip(evt)"/>
<rect id="rect2" x="240" y="10" width="60" height="60" fill="green"
onmousemove="ShowTooltip(evt)"
onmouseout="HideTooltip(evt)"/>
<rect class="tooltip_bg" id="tooltip_bg"
x="0" y="0" rx="4" ry="4"
width="55" height="17" visibility="hidden"/>
<image xlink:href="Blooper-icon.png" class="tooltip" id="tooltip"x="0" y="0"height="50px"width="50px"visibility="hidden"/>
</svg>

in HTML
<div class="svgTooltip"></div>
<svg>
<path class="tempClass" .......>
</path>
</svg>
in CSS
.svgTooltip {
pointer-events: none;
position: absolute;
font-size: 15px;
text-align: center;
background: white;
padding-bottom: 5px;
padding-left: 5px;
padding-right: 5px;
z-index: 5;
height: 30px;
line-height: 30px;
margin: 0 auto;
color: #21669e;
border-radius: 5px;
box-shadow: 0 0 0 1px rgb(122, 92, 92);
display: none;
}
.svgTooltip::after {
content: "";
position: absolute;
left: 50%;
top: 100%;
width: 0;
height: 0;
margin-left: -10px;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid rgb(122, 92, 92);
}
.active {
display: block;
}
in JS
$(function() {
$tooltip = $(".svgTooltip");
$(".tempClass").hover(
function() {
$tooltip.addClass("active");
$tooltip.html($(this).attr("title"));
},
function() {
$tooltip.removeClass("active");
}
);
});
$(document).on("mousemove", function(e) {
$tooltip.css({
left: e.pageX - 30,
top: e.pageY - 70
});
});

Related

Hover on nested elements using SASS and BEM

I try to use hover for button element and for SVG within button. But in here piece of code https://codepen.io/asssel/pen/wvrojOd It doesn't work for SVG. Help me how to implement it.
.tag {
width: 120px;
padding: 6px 12px;
border: 1px solid #1F1F1F;
border-radius: 18px;
cursor: pointer;
color: #1F1F1F;
background-color: white;
&_label {
font-size: 12px;
line-height: 12px;
letter-spacing: 1.2px;
text-transform: uppercase;
}
&_remove {
border: none;
background-color: transparent;
}
&:hover, &_icon path {
background-color: #1F1F1F;
color: white;
stroke: white;
}
}
<div class='tag'>
<span class='tag_label'>default tag</span>
<button class='tag_remove'>
<svg class='tag_icon' width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.5 1.5L1.5 8.5M8.5 8.5L1.5 1.5" stroke="#404040" stroke-width="2" stroke-linecap="square"/>
</svg>
</button>
</div>
First of all I changed your CSS to plain CSS to make it work in the snippet.
I guess that the main problem is the hover effect. To change the stroke of the <path> your CSS selector need to start from the element that is hovered. So, replace &_icon path with &:hover &_icon path.
And then you also make sure that you use fill and stroke properties for SVG elements.
.tag {
width: 120px;
padding: 6px 12px;
border: 1px solid #1F1F1F;
border-radius: 18px;
cursor: pointer;
color: #1F1F1F;
background-color: white;
display: flex;
align-items: center;
}
.tag_label {
font-size: 12px;
letter-spacing: 1.2px;
text-transform: uppercase;
white-space: nowrap;
}
.tag_icon path {
stroke: #1F1F1F;
}
.tag_remove {
border: none;
background-color: transparent;
}
.tag:hover,
.tag:hover .tag_icon path {
background-color: #1F1F1F;
color: white;
stroke: white;
}
<div class='tag'>
<span class='tag_label'>default tag</span>
<button class='tag_remove'>
<svg class='tag_icon' width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.5 1.5L1.5 8.5M8.5 8.5L1.5 1.5" stroke-width="2" stroke-linecap="square"/>
</svg>
</button>
</div>

Pure svg pie chart, text align center

How to place the value text inside each pie chart without framework d3.js.
i have tried using some javascript to get the width. It is the default
getBBox()); // get the SVG width.
I use stroke-dasharray to expand the pie space.
Which way i can get the correct stroke-dasharray size from javascript?
figure {
background-color: #eee;
display: block;
height: 0;
margin: 0 auto;
position: relative;
font-size:16px;
font-size:1vw;
width: 40em;
padding-bottom: 40em;
}
svg {
display: block;
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
overflow: visible;
}
circle {
fill:transparent;
stroke-width:31.8309886184;
stroke-dasharray: 0,0,0,100;
stroke-dashoffset: 25;
animation: pie1 4s ease both;
}
.pie1 {
stroke:pink;
}
.pie2 {
stroke: green;
-webkit-animation-name: pie2;
animation-name: pie2;
}
.pie3 {
stroke: aqua;
-webkit-animation-name: pie3;
animation-name: pie3;
}
#keyframes pie1 {
50%,100% {stroke-dasharray: 40,60,0,0;}
}
#keyframes pie2 {
50%,100% {stroke-dasharray: 0,40,30,30;}
}
#keyframes pie3 {
50%,100% {stroke-dasharray: 0,70,30,0;}
}
<body>
<figure>
<svg class="chart" viewBox="0 0 63.6619772368 63.6619772368">
<circle class="pie1" cx="31.8309886184" cy="31.8309886184" r="15.9154943092" />
<circle class="pie2" cx="31.8309886184" cy="31.8309886184" r="15.9154943092" />
<circle class="pie3" cx="31.8309886184" cy="31.8309886184" r="15.9154943092" />
</svg>
</figure>
</body>
You can't. The getBBox() gets the bounds of the shape. In your case, the shapes are circles centred on the middle of the graph. You would need to use trigonometry to calculate the position for your text.
makeLabel('Pink', 340, 15.9);
makeLabel('Green', 110, 15.9);
makeLabel('Cyan', 210, 15.9);
function makeLabel(text, angle, radius)
{
const chart = document.getElementById("chart");
const label = document.createElementNS(chart.namespaceURI, "text");
label.classList.add("label");
label.setAttribute("x", 31.83 + Math.cos(angle * Math.PI/180) * radius);
label.setAttribute("y", 31.83 + Math.sin(angle * Math.PI/180) * radius);
label.textContent = text;
chart.appendChild(label);
}
figure {
background-color: #eee;
display: block;
height: 0;
margin: 0 auto;
position: relative;
font-size:16px;
font-size:1vw;
width: 40em;
padding-bottom: 40em;
}
svg {
display: block;
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
overflow: visible;
}
circle {
fill:transparent;
stroke-width:31.8309886184;
stroke-dasharray: 0,0,0,100;
stroke-dashoffset: 25;
animation: pie1 4s ease both;
}
.pie1 {
stroke:pink;
stroke-dasharray: 40,60,0,0;
}
.pie2 {
stroke: green;
stroke-dasharray: 0,40,30,30;
}
.pie3 {
stroke: aqua;
stroke-dasharray: 0,70,30,0;
}
.label {
font: 3px sans-serif;
text-anchor: middle;
}
<body>
<figure>
<svg id="chart" class="chart" viewBox="0 0 63.6619772368 63.6619772368">
<circle class="pie1" cx="31.8309886184" cy="31.8309886184" r="15.9154943092" />
<circle class="pie2" cx="31.8309886184" cy="31.8309886184" r="15.9154943092" />
<circle class="pie3" cx="31.8309886184" cy="31.8309886184" r="15.9154943092" />
</svg>
</figure>
</body>
BTW, that approach for doing pie graphs works most of the time. And may be alright for your case. But in general it is not recommended. Some browsers have trouble rendering circles drawn that way. You might want to consider switching to drawing proper circular sectors.

SVG Animated Graph Arrow

This is my first time using SVG and I want to know if it is possible to create an animated line graph with an arrow. I have found multiple examples of animated line graphs without arrows, non-animated line graphs with arrows, and animated straight lines with arrows, but not exactly what I am looking for. I have attached some codepen examples I've been playing around with below. Does anyone know if this is possible/have a solution? It would be greatly appreciated!
Animated line missing arrow (needs arrow):
http://codepen.io/alexandraleigh/pen/jVaObd
# HTML
<div class="graph__wrapper">
<svg width="315px" height="107px" viewBox="0 0 315 107" version="1.1">
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<path d="M2.10546875,95.75 L40.5546875,68.3476562 L55.2109375,81.1796875 L65.2148437,76.3945312 L96.1835937,86.8320312 L131.023438,19.9414062 L142.15625,23.7226562 L183.605469,2.1953125 L211.007812,22.3320312 L234.320312,71.5664062 L234.667969,83.0039062 L244.019531,83.0039062 L247.105469,88.8320312 L312.695312,104.839844" id="Path-1" stroke="white" stroke-width="4" sketch:type="MSShapeGroup" class="path"></path>
</g>
</svg>
</div>
# CSS(Less)
#import "lesshat";
#darkgrey: #303030;
*{
box-sizing: border-box;
}
body{
background: #darkgrey;
}
.graph__wrapper{
width: 400px;
margin: 30px auto;
position: relative;
svg{
position: absolute;
margin: 36px 0px 0px 15px;
}
}
.path {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: dash 3s ease-in forwards;
animation-iteration-count: 1;
animation-delay: 1s;
}
#keyframes dash {
to {
stroke-dashoffset: 0;
}
}
.description{
font-family: "Roboto";
color:lighten(#darkgrey, 50%);
text-align: center;
margin: 40px 0px;
}
Animated straight line with arrow (needs to stop at multiple points on path):
http://codepen.io/alexandraleigh/pen/yVPYrY
I tried adding the path descriptions from #1 to #2 and it has the desired final graph, just no animations:
http://codepen.io/alexandraleigh/pen/pNdgWR
I also tried adding the arrow marker from #2 to #1, but the arrow doesn't animate:
http://codepen.io/alexandraleigh/pen/aBVdVY
I'm also open to using a plugin such as http://snapsvg.io/, but haven't seen any working examples that help my situation.
you can do this with offset-motion(old syntax: motion-path).
Be aware that this is a heighly experimental feature. it currently only works in Chrome. More to the point i use the "old" syntax here as that is what currently works in chrome, but it will soon switch to the new systax...
* {
box-sizing: border-box;
}
body {
background: #303030;
}
.graph__wrapper {
width: 400px;
margin: 30px auto;
position: relative;
svg {
position: absolute;
margin: 36px 0px 0px 15px;
}
}
.path {
stroke-dasharray: 428;
stroke-dashoffset: 428;
animation: dash 3s ease-in forwards;
animation-iteration-count: 1;
animation-delay: 1s;
}
#keyframes dash {
to {
stroke-dashoffset: 0;
}
}
#keyframes pm {
from {
motion-offset: 0%;
}
to {
motion-offset: 100%
}
}
#arrow {
animation: pm 3s ease-in forwards;
animation-iteration-count: 1;
animation-delay: 1s;
motion-path: path('M2.10546875,95.75 L40.5546875,68.3476562 L55.2109375,81.1796875 L65.2148437,76.3945312 L96.1835937,86.8320312 L131.023438,19.9414062 L142.15625,23.7226562 L183.605469,2.1953125 L211.007812,22.3320312 L234.320312,71.5664062 L234.667969,83.0039062 L244.019531,83.0039062 L247.105469,88.8320312 L312.695312,104.839844');
motion-rotation: auto;
motion-anchor: center;
}
.description {
font-family: "Roboto";
color: lighten(#darkgrey, 50%);
text-align: center;
margin: 40px 0px;
}
<div class="graph__wrapper">
<svg width="315px" height="107px" viewBox="0 0 315 107" version="1.1" style="overflow:visible">
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<path d="M2.10546875,95.75 L40.5546875,68.3476562 L55.2109375,81.1796875 L65.2148437,76.3945312 L96.1835937,86.8320312 L131.023438,19.9414062 L142.15625,23.7226562 L183.605469,2.1953125 L211.007812,22.3320312 L234.320312,71.5664062 L234.667969,83.0039062 L244.019531,83.0039062 L247.105469,88.8320312 L312.695312,104.839844"
id="Path-1" stroke="white" stroke-width="4" sketch:type="MSShapeGroup" class="path"></path>
<polyline id="arrow" points="0,-5 10,0 0,5 1,0" fill="white" />
</g>
</svg>
</div>
you can also do this with animateMotion, but svg animations are soon to be depricted. You will have to rewrite your code in any way sooner or later :-(
* {
box-sizing: border-box;
}
body {
background: #303030;
}
.graph__wrapper {
width: 400px;
margin: 30px auto;
position: relative;
svg {
position: absolute;
margin: 36px 0px 0px 15px;
}
}
.path {
stroke-dasharray: 428;
stroke-dashoffset: 428;
animation: dash 3s linear forwards;
animation-iteration-count: 1;
animation-delay: 1s;
}
#keyframes dash {
to {
stroke-dashoffset: 0;
}
}
.description {
font-family: "Roboto";
color: lighten(#darkgrey, 50%);
text-align: center;
margin: 40px 0px;
}
<div class="graph__wrapper">
<svg width="315px" height="107px" viewBox="0 0 315 107" version="1.1" style="overflow:visible">
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<path d="M2.10546875,95.75 L40.5546875,68.3476562 L55.2109375,81.1796875 L65.2148437,76.3945312 L96.1835937,86.8320312 L131.023438,19.9414062 L142.15625,23.7226562 L183.605469,2.1953125 L211.007812,22.3320312 L234.320312,71.5664062 L234.667969,83.0039062 L244.019531,83.0039062 L247.105469,88.8320312 L312.695312,104.839844"
id="Path-1" stroke="white" stroke-width="4" sketch:type="MSShapeGroup" class="path"></path>
<polyline id="arrow" points="0,-5 10,0 0,5 1,0" fill="white">
<animateMotion rotate="auto" begin="1s" dur="3s" repeatCount="1" fill="freeze">
<mpath xlink:href="#Path-1" />
</animateMotion>
</polyline>
</g>
</svg>
</div>

SVG Responsive Text

I have an SVG within a web page, it consists of images + text
<object data="/infographic/timeline.svg" type="image/svg+xml">
<img src="/infographic/timeline.svg" alt="Timeline">
</object>
All the images are responsive, but the text isn't, so the text becomes really, REALLY small.
snippet of SVG (its massive)
<defs>
<style>
.cls-1 {
font-size: 60.014px;
}
.cls-1, .cls-10 {
opacity: 0.69;
}
.cls-1, .cls-10, .cls-4, .cls-5, .cls-7, .cls-8, .cls-9 {
fill: #ffffff;
}
.cls-1, .cls-10, .cls-3, .cls-4, .cls-5, .cls-6, .cls-7, .cls-9 {
text-anchor: middle;
}
.cls-1, .cls-3, .cls-6 {
font-family: "Roboto";
}
.cls-2 {
font-size: 32.014px;
}
.cls-3 {
font-size: 14.089px;
}
.cls-3, .cls-6 {
fill: #db7426;
}
.cls-4, .cls-6 {
font-size: 32px!important;
}
.cls-10, .cls-4, .cls-5, .cls-7, .cls-8, .cls-9 {
font-family: Roboto;
}
.cls-5 {
font-size: 24px;
}
.cls-5, .cls-8, .cls-9 {
font-weight: 400;
}
.cls-6 {
font-weight: 600;
}
.cls-10, .cls-7 {
font-size: 18.75px;
font-weight: 300;
}
.cls-7 {
opacity: 0.4;
}
.cls-8, .cls-9 {
font-size: 22px;
}
</style>
</defs>
<text id="Who_are_you_what_do_you_do_what_s_your_why_What_s_been_keepi" data-name="Who are you, what do you do, what’s your why? What’s been keepi" class="cls-8" x="397.706" y="535.325">Who are you, what do you do, what’s your why?<tspan x="397.706" dy="26.4">What’s been keeping you lying awake at night. </tspan></text>
Is there anyway I can get the text size to increase as the SVG/screen width gets smaller?
Any help would be greatly appreciated.
It's not possible with pure SVG (at least not yet). The only solution would be to either:
inline the SVG and manipulate the size of the text with javascript.
inline the SVG and control the size of the text with media queries (see below).
Add CSS to the SVG and use media queries there (see below).
use media queries to switch SVGs when the page gets small
Example of option 2: Using media queries with inlined SVGs
text {
font-size: 10px;
}
#media (max-width: 400px) {
text {
font-size: 20px;
}
}
<svg viewBox="0 0 100 100" width="100%" height="100%">
<circle cx="50" cy="50" r="50" fill="orange"/>
<text x="50" y="60" text-anchor="middle">Testing</text>
</svg>
Example of option 3: Using media queries in CSS in the SVGs
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100%" height="100%">
<style>
text {
font-size: 10px;
}
#media (max-width: 400px) {
text {
font-size: 20px;
}
}
</style>
<circle cx="50" cy="50" r="50" fill="orange"/>
<text x="50" y="60" text-anchor="middle">Testing</text>
</svg>
This is possible using the foreignObject svg element in a html context and some adjustment of the viewBow.
On this demos, the text stay selectable:
.demo {
overflow: auto;
resize: both;
border:1px black solid;
width: 230px;
height: 130px
}
.svgtext {
font-size: 28rem;
height:100%;
width:100%
}
<div class="demo">
<svg x="0" y="30" viewBox="0 0 100 100" width="100%" height="100%">
<foreignObject x="12" y="23" height="100%" width="100%">
<div class"svgtext">
Hello world!
</div>
</foreignObject>
</svg>
</div>
Use preserveAspectRatio to control the resizing behavior:
.demo {
overflow: auto;
resize: both;
border:1px black solid;
width: 230px;
height: 130px
}
.svgtext {
font-size: 28rem;
height:100%;
width:100%
}
<div class="demo">
<svg preserveAspectRatio="none" x="0" y="30" viewBox="0 0 100 100" width="100%" height="100%">
<foreignObject x="12" y="23" height="100%" width="100%">
<div class"svgtext">
Hello world!
</div>
</foreignObject>
</svg>
</div>

Animate SVG Hamburger menu icon on click and keep it in :active state

I have a SVG hamburger menu icon that is animated when clicked. The goal is to transform it in to a "close" button when you activate the side-push menu. I need some help achieving that:
http://jsfiddle.net/a6ysa9zk/
HTML:
<div class="toggle-menu menu-right push-body">
<svg class="inline-svg" width="42px" height="42px" viewBox="0 0 42 42" enable-background="new 0 0 32 22.5" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.0.4 (8054) - http://www.bohemiancoding.com/sketch -->
<title>Group</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g class="svg-menu-toggle" sketch:type="MSLayerGroup">
<circle class="round" fill="#3B3B41" sketch:type="MSShapeGroup" cx="21" cy="21" r="21"></circle>
<rect class="bar" fill="#F2F2F2" sketch:type="MSShapeGroup" x="12" y="26" width="18" height="4"></rect>
<rect class="bar" fill="#F2F2F2" sketch:type="MSShapeGroup" x="12" y="19" width="18" height="4"></rect>
<rect class="bar" fill="#F2F2F2" sketch:type="MSShapeGroup" x="12" y="12" width="18" height="4"></rect>
</g>
</svg>
</div>
CSS:
.svg-menu-toggle {
fill: #fff;
pointer-events: all;
cursor: pointer;
}
.svg-menu-toggle .round {
transition: fill .4s ease-in-out;
}
.svg-menu-toggle .bar {
-webkit-transform: rotate(0) translateY(0) translateX(0);
transform: rotate(0) translateY(0) translateX(0);
opacity: 1;
-webkit-transform-origin: 20px 10px;
transform-origin: 20px 10px;
-webkit-transition: -webkit-transform 0.4s ease-in-out, opacity 0.2s ease-in-out, fill .4s ease-in-out;
transition: transform 0.4s ease-in-out, opacity 0.2s ease-in-out, fill .4s ease-in-out;
}
.svg-menu-toggle .bar:nth-of-type(1) {
-webkit-transform-origin: 20px 10px;
transform-origin: 20px 10px;
}
.svg-menu-toggle .bar:nth-of-type(3) {
-webkit-transform-origin: 20px 20px;
transform-origin: 20px 20px;
}
.svg-menu-toggle:active .bar:nth-of-type(1) {
-webkit-transform: rotate(-45deg) translateY(-10px) translateX(-8px);
transform: rotate(-45deg) translateY(-10px) translateX(-8px);
fill: #3B3B41;
}
.svg-menu-toggle:active .bar:nth-of-type(2) {
opacity: 0;
}
.svg-menu-toggle:active .bar:nth-of-type(3) {
-webkit-transform: rotate(45deg) translateY(6px) translateX(0px);
transform: rotate(45deg) translateY(6px) translateX(0px);
fill: #3B3B41;
}
.svg-menu-toggle:active .round {
fill: #F2F2F2;
}
Javascript for menu toggle:
jQuery(document).ready(function ($) {
$('.toggle-menu').jPushMenu();
});
Instead of using the :active pseudo-element, its easier to add a class to the group (.svg-menu-toggle).
Unfortunately it isn't possible to use toggleClass from jQuery.
// CSS
.svg-menu-toggle:active become .svg-menu-toggle.active
// JS
$('.toggle-menu').on('click', function(e) {
var $toggle = $(this).find('.svg-menu-toggle');
// toggleClass with addClass & removeClass
});

Resources