Force SVG tooltip appear when mouse over unfilled area - svg

Here is a simple SVG code with a tooltip embedded:
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 100 100" enable-background="new 0 0 100 100"
xml:space="preserve">
<g>
<title>Blue Frame</title>
<path
fill="#2E3192"
d="M75,25v50H25V25H75 M100,0H0v100h100V0L100,0z"
/>
</g>
</svg>
It draws blue frame and does nothing more.
The problem is tooltip appears only when the mouse pointer is over the frame. When it moves to unfilled center of the SVG image, then tooltip disappears.
Moving <title> tag over the <g> tag leads to no tooltip at all.
What have I missed to make tooltip appear always when the mouse pointer is over any point of this SVG, not just over filled parts?
It is just a quick and short preview to show the problem. For example it is very difficult to catch the tooltip on any large image with only a few thin lines.
I know I can place a rectangle that will cover all available SVG space and put anything over it. But this rectangle also needs some color while I need transparent parts of my SVGs to remain strictly transparent.

You could always put a hidden rect in the background to catch those mouse events you'd otherwise miss like so:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 100 100" xml:space="preserve">
<g>
<title>Blue Frame</title>
<rect width="100%" height="100%" visibility="hidden" pointer-events="all"/>
<path
fill="#2E3192"
d="M75,25v50H25V25H75 M100,0H0v100h100V0L100,0z"
/>
</g>
</svg>

I would also suggest to define X and Y positions to the rectangle offered by Mr.Longson. Otherwise the rectangle may appear outside of your drawing partially or completely and you would have to catch the tooltip again.
You may get X and Y values at the <svg> tag's viewBox parameter, they are the first two groups of digits, the very first one is for the X and the second one is Y. Other two describes the initial size of the SVG and not needed for this case.
According to your example you don't need to define either X or Y as they are both equal to 0:
<rect x="0" y="0" width="100%" height="100%" visibility="hidden" pointer-events="all"/>
But as soon as they are for example viewBox="-123 456 100 100" you'll immediately notice that some parts of your SVG still don't show any tooltip. In such case the <rect> tag should look like this:
<rect x="-123" y="456" width="100%" height="100%" visibility="hidden" pointer-events="all"/>

Related

How to automatically create the minimal size of the viewbox which fits for the complete content?

I have a simple or complex SVG graphic. For example a rotated rectangle.
Without calculating you cannot know the minimal size of the viewbox, where the graphic fits into completely.
<svg viewBox="0 0 30 30">
<rect x="20" y="0" width="100" height="20" transform="rotate(45)" fill="black" />
</svg>
The result is, that the graphic does not fit into the viewbox.
Is there any method, how to get an the minimal size of the viewbox, where the graphic is shown completely?
Ideally I do not want to declare a size/ratio of a viewbox. I just want that the minimal size is a result of the content of the SVG graphics.
Is there any disadvantage, when I do not declare the viewBox attribute at all?
Thanks for your help.
One way to do it is wrapping the transformed rectangle in a <g> element and then get the value of the bounding box for theG. Next you use the values of the bounding box (BB) to reset the viewBox of theSVG. I hope it helps.
// the bounding box for the wrapping g
let BB = theG.getBBox();
theSVG.setAttributeNS(null, "viewBox", `${BB.x} ${BB.y} ${BB.width} ${BB.height}`)
svg{border:1px solid}
<svg id="theSVG" viewBox="0 0 30 30" width="300">
<g id="theG">
<rect x="20" y="0" width="100" height="20" transform="rotate(45)" fill="black" />
</g>
</svg>

An SVG having only definitions for another scaling SVG still needs to scale?

My SVG is width="1200" height="600" viewBox="0 0 1200 600". It uses a clipPath from defs of another SVG.
<svg class="svg-def">
<defs>
<clipPath id="clip-1"> ...
</defs>
</svg>
<svg width="1200" height="600" viewBox="0 0 1200 600">
<g clip-path="url(#clip-1)">
...
</g>
</svg>
Demo
When .svg-def does not have width="1200" height="600" viewBox="0 0 1200 600" (the first image), on window width narrower than 1200, the right side is clipped. This is not desired.
I want the second image -- the clip is just the size of the SVG. The second image is good because the <clipPath> being used is from an <svg> element with the same width="1200" height="600" viewBox="0 0 1200 600"
<svg class="svg-def">
<defs>
<clipPath id="clip-1"> ...
</defs>
</svg>
<svg class="svg-def" width="1200" height="600" viewBox="0 0 1200 600">
<defs>
<clipPath id="clip-2"> ...
</defs>
</svg>
Questions
1) In <clipPath> <rect width="100%" height="100%"/>, what is 100% relative to?
2) The first clip's display width varies with window width (when the latter is narrow than 1200px). Narrower window width = narrower display width. What is the display width relative to?
3) So if I have an SVG which has only <defs>, its <svg> tag still has to have viewbox values, so that the other SVG which uses the definitions (and which scales with window width) can have definitions in correct sizes?

Why does the SVG preserveAspectRatio attribute work strangely?

I've created a simple example https://jsfiddle.net/7mupweLe/
<svg style="background:yellow"
height="200" width="200" viewBox="0 0 100 200"
preserveAspectRatio="xMidYMid meet">
<rect class="rect" x="0" y="0" width="200" height="200" />
</svg>
Why is the black rectangle offset to the right this case. As I understand it, it must be in the exactly in the middle because I have xMidYMid.
We've an area 200 x 200 px (the width and height of the <svg> element) in which we want to display something that's 100 x 200 (the viewBox)
The meet of preserveAspectRatio says make sure we display everything and have space on either the sides or the top (in this case the side). xMidYMid means make the space even.
So to the left and right of the viewBox we'll see the background except that the SVG contains a shape - a rect which is bigger than the viewBox 200 x 200 against the 100 x 200 of the viewBox and so it overflows the viewBox to the right hand side.
If we make the rect the same size as the viewBox, everything is symmetrical.
<svg style="background:yellow"
height="200" width="200" viewBox="0 0 100 200"
preserveAspectRatio="xMidYMid meet">
<rect class="rect" width="100" height="200" />
</svg>

Rotate an object in SVG

I am just getting started with SVG and am now trying out rotating objects.
I have the initial canvas and have created my own drag and drop function so on mousedown the drag is initialized and mouseup it stops. The problem i'm having is when I rotate an object, it seems to change the x and y. This is visible when i'm trying to drag an object. Does anyone know how to get around this so the x and y get "normalized" in relation to the rotate angle?
Here's my code.
<svg version="1.1" width="900" height="400"><text x="10" y="10" id="text_0" width="200" height="40" transform="rotate(45, 0, 0)">SVG test</text></svg>
Thanks
rotate parameters give you the angle and the center of the rotation (see MDN for example). And what about the width and height attributes in your text anyways? This is not part of the standard as of here. If you want to change the size of your text, do so using font-size in the style.
If you want to rotate the text around its (the text element's) center you may use for example the following:
<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" width="900" height="400" xmlns="http://www.w3.org/2000/svg">
<text x="10" y="10" id="text_0" transform="rotate(45, 10, 10)" style="dominant-baseline: middle; text-anchor: middle;">
SVG test
</text>
</svg>

Scale uniform on X axis

I dynamically generate an svg, which can result in a very high height value. (It's a table.)
My aim is to have:
ratio on x axis
scrollbar to scroll the image down
I know I have to play with svg's height and width, viewBox and preserveAspectRatio, but to achieve my goal I'm using a dirty trick which leaves a lot of white space at the bottom: I set the height of the image to a very high value.
The problem is that I have no certainty that the table (image) will never exceed this value (and I don't want to end up setting it to something like 100000).
Can anybody help me?
Here's the example I'm working on to find a solution:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="100%"
height="2000"
viewBox="0 0 1366 768"
preserveAspectRatio="xMinYMin meet">
<rect
width="1359.5181"
height="42.065403"
x="3"
y="3"
id="rect2985"
style="fill:#ffff78;stroke:#000000;stroke-width:10" />
<rect
width="719.58691"
height="805.50775"
x="316.83304"
y="177.29433"
id="rect2987"
style="fill:#ffff78;stroke:#000000;stroke-width:10" />
<text
x="15"
y="30"
id="text2989"
style="font-size:23px">LOL</text>
</svg>
Yeah, I guess I should.
I'll use this for now (still gotta be fully tested):
function fixHeight()
{
node = document.getElementById("table");
node.setAttribute("height", node.getBBox().width);
}

Resources