Click event coordinates in SVG - javascript

This HTML containing SVG:
<div class="container">
<div class="spacer"></div>
<svg>
<g id="polygonGroup" transform="translate(80, 50)">
<polygon points="-60,-10 -35,-30 -10,-10 -10,30 -60,30"></polygon>
<polygon points="10,-10 35,-30 60,-10 60,30 10,30"></polygon>
<polygon class="origin" points="-4,0 0,4 4,0 0,-4"></polygon>
</g>
<g id="textGroup" transform="translate(80, 50)">
<text x="-35" y="10">Text</text>
<text x="35" y="10">Text</text>
</g>
</svg>
</div>
and this simple jQuery click event handler:
function clicked(event) {
console.log(event.offsetX, event.offsetY);
}
$('svg').click(clicked);
as seen here: https://jsfiddle.net/1ht0L8y6/6/ have different behaviors in different browsers:
Chrome: The coordinates are based on the top left of the SVG element, no matter where I click inside the SVG. This is the behavior I want.
Firefox: The coordinates are based on the top left of whatever element I'm in, which may be SVG, polygon, or text.
IE and Edge:
When in the SVG but not in any of its sub-elements, the coordinates
are based on the SVG element.
When in a polygon, the coordinates are
based on the origin of the <g> group, with its translate offset
(i.e., the black diamond). Negative coordinates are possible this way,
unlike in Chrome or Firefox.
I have observed a different behavior for
text elements in these browsers: They would give coordinates based on
the bottom middle of the text element. But I couldn't manage to
reproduce this in the fiddle; in the fiddle text elements behave
the same as polygons in these browsers.
What is a reliable cross-browser way to get the coordinates of the click?

I've added to your code a function to detect the mouse position in SVG.
let svg = document.querySelector('svg')
function clicked(event) {
let m = oMousePosSVG(event);
console.log(m.x,m.y);
}
svg.addEventListener("click", clicked)
function oMousePosSVG(e) {
var p = svg.createSVGPoint();
p.x = e.clientX;
p.y = e.clientY;
var ctm = svg.getScreenCTM().inverse();
var p = p.matrixTransform(ctm);
return p;
}
svg{border:1px solid}
<div class="container">
<div class="spacer"></div>
<svg>
<g id="polygonGroup" transform="translate(80, 50)">
<polygon points="-60,-10 -35,-30 -10,-10 -10,30 -60,30"></polygon>
<polygon points="10,-10 35,-30 60,-10 60,30 10,30"></polygon>
<polygon class="origin" points="-4,0 0,4 4,0 0,-4"></polygon>
</g>
<g id="textGroup" transform="translate(80, 50)" fill="red">
<text x="-35" y="10">Text</text>
<text x="35" y="10">Text</text>
</g>
</svg>
</div>
To read more about mouse detection in SVG I recommend this book: Using SVG with CSS3 and HTML5: Vector Graphics for Web Design
I hope it helps.

Related

SVG Textpath - animate startOffset (text to slide down SVG path) - in JS

How can I animate the SVG textpath startOffset parameter in WebAnimation/JS (NOT CSS!):
I want to let the text slide down the path...
I tried numbers,%, px with no success.
<svg id="text-on-path-svg" width="400" height="400" style="border:1px solid #00f">
<path id="myPathforText" fill="none" stroke="#000" d="M90,90C90,160 250,160 300,300"/>
<text >
<textpath id="slideText" xlink:href="#myPathforText" startOffset="50%" >Text laid out along a path.</textpath>
</text>
<script type="text/ecmascript">
<![CDATA[
var slideText=document.getElementById("slideText");
var slideTextPlayer=slideText.animate(
[{startOffset:'0%'},
{startOffset:'100%'}],
{duration:3000,delay:0,iterations:Infinity});
]]>
</script>
</svg>
JSFiddle: https://jsfiddle.net/509c8pmj/
Help would be much appreciated.
One way is by placing an animate element inside your textpath element, like this:
<textpath id="slideText" xlink:href="#myPathforText" startOffset="50%" >
Text laid out along a path.
<animate attributeName="startOffset" from="0%" to ="100%" begin="0s" dur="3s" repeatCount="indefinite"/>
</textpath>
You can use repeatCount="indefinite" if you want it to keep looping.
I've been learning some of the SVG + SMIL syntax from articles on https://css-tricks.com (but their site was down for me as I'm writing this.)

How to animate entire "path" element of svg?

I have read this documentation http://www.w3.org/TR/SVG/animate.html about svg animation and i know how to animate rectangle,circle etc,but this document doesn't contains any info on how to animate entire svg "path" element.
I am creating bow and arrow game and i want to animate the "path" element to the right when user clicks on a button. i just want to know how to animate entire "path" element??
In the below code i want to animate second "path" element to the right...
<svg width="500" height="500">
<path d="M150,150 l0,150 q80,-50 0,-150 M220,230 l-120,0 m120,0 l-20,10 m20,-10 l-20,-10" style="stroke:black;stroke-width:5;fill:red;"/>
<path d="M220,230 l-120,0 m120,0 l-20,10 m20,-10 l-20,-10" style="stroke:orange;width:5" />
</svg>
After some trail and error i finally resolve my issue.Below is the code for the same.
<svg width="500" height="500">
<path d="M150,150 l0,150 q80,-50 0,-150 M220,230 l-120,0 m120,0 l-20,10 m20,-10 l-20,-10" style="stroke:black;stroke-width:5;fill:red;"/>
<path d="M220,230 l-120,0 m120,0 l-20,10 m20,-10 l-20,-10" style="stroke:orange;width:5">
<animateMotion
path="M0,0 l300,0"
begin="0s" dur="5s" repeatCount="1"
/>
</path>
</svg>

Is it possible to run two different animations on one SVG element?

I'm using Snap.svg to do this animation. Basically, I want to rotate an element around a point but I want the element to still face the same way when it's rotating. Please check this http://jsfiddle.net/mabotofu/MpEu4/6/
<svg id="test">
<circle transform="translate(200,200)" r="10" fill="transparent" stroke="#aaa" />
<g>
<circle cx="0" cy="50" r="10" />
<circle cx="0" cy="150" r="10" />
<text x="0" y="100" fill="red">TEST</text>
</g>
</svg>
var paper = Snap(test),
container = paper.select("g");
container
.attr({
fill: "transparent",
stroke: "#aaa",
transform: "translate(200,200)"
})
.animate({
transform: "t200,200r720,0,0"
}, 6000);
In this example, I need the "TEST" text to still stay horizontally even when it's rotating.
toransform="rotate()" is already applied to the element so I can't use rotate again on the lement but I don't know how I can rotate around the center point then also rotate the text itself so it stays horizontally. Please help! Thank you
You can apply the rotation in the opposite direction to the text element:
...
container = paper.select("g");
text = container.select("text");
...
text.animate({transform: "t0,0r-720"}, 6000);
See: JSFiddle

D3 transition not working

I have the following SVG element:
<svg id='svgTest' xmlns="http://www.w3.org/2000/svg" version="1.1">
<g id="test">
<rect height="20" width="50" fill="blue"/>
</g>
</svg>
I want to add a transition for the blue rectangle. I tried with the following code with D3:
var rect = d3.select("#test");
rect.transition().duration(5000).attr('height',200);
But it doesn't seem to do anything. What's wrong?
You need to select the 'rect' element. Try this:
var rect = d3.select("#test rect");
rect.transition().duration(5000).attr('height',200);
If you want to update multiple elements, use d3.selectAll().

Mult-line Svg tooltip

I have created numerous polygon shapes in SVG format. and grouped them together.
When the user hovers over the group a tooltip box appear. I have used ecmascript.
What i am looking to do is make the tooltip box a multiline box.
Any ideas how to do this?
<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+17);
tooltip.setAttributeNS(null,"y",evt.clientY+14);
tooltip.firstChild.data = mouseovertext;
tooltip.setAttributeNS(null,"visibility","visible");
length = tooltip.getComputedTextLength();
tooltip_bg.setAttributeNS(null,"width",length+8);
tooltip_bg.setAttributeNS(null,"x",evt.clientX+14);
tooltip_bg.setAttributeNS(null,"y",evt.clientY+1);
tooltip_bg.setAttributeNS(null,"visibility","visibile");
}
function HideTooltip(evt)
{
tooltip.setAttributeNS(null,"visibility","hidden");
tooltip_bg.setAttributeNS(null,"visibility","hidden");
}
]]>
</script>
<SVG>
<g onmousemove="ShowTooltip(evt, 'GHANA 2000')" onmouseout="HideTooltip(evt)">
<path fill="#EEEEEE" d="M250,0c47,0,85.183,10.506,125,33.494L250,250V0z"/>
<path id="score" d="M250,57c36.284,0,65.761,8.11,96.5,25.857L250,250V57z"/>
<path fill="none" stroke="#FFFFFF" stroke-width="2" stroke-miterlimit="10" d="M250,0c47,0,85.183,10.506,125,33.494L250,250V0z"/>
<text transform="matrix(1 0 0 1 283.9883 92.0024)" fill="#FFFFFF" font-family="'WalkwayBlack'" font-size="16">62</text>
</g>
<rect class="tooltip_bg" id="tooltip_bg" x="0" y="0" width="55" height="17" visibility="hidden"/>
<text class="tooltip" id="tooltip" x="0" y="0" visibility="hidden">Tooltip</text>
<SVG>
You could create more <text> elements or <tspan> elements within the existing text element, put subsequent lines of text in the additional elements and then position each text/tspan below the previous ones by giving them the same x attribute value and increase the y attribute by the height of the bounding box of the previous line.
Alternatively and more simply, just create <title> elements as children of the polygon shape elements and put the multiline text directly within that and the tooltips will be shown by most UAs as multiline tooltips, it certainly works in Firefox and Opera. Here's a html example but it should work just as well with SVG except that SVG has a title element rather than a title attribute.

Categories

Resources