Clipping/Masking Sub-Parts of SVG Linked Image - html

I have a massive image of a map embedded in an SVG, which is much larger than the browser window and centered on the screen.
<svg id='map' width='7192' height='3912' viewBox='0 0 7192 3912' version='1.1'>
<image width='7192' height='3912' x='0' y='0' preserveAspectRatio='none'
xlink:href='map.jpg' />
<!-------------------->
<!-- paths are here -->
<!-------------------->
</svg>
There are two paths. One path outlines a building. The other path outlines a sub-region on the map.
The user can click on these paths, at which point that specific path will gradually be centered in the middle of the screen using a transition.
Once the path is centered, what I would like to do is clip or mask everything outside of that path, so that the only visible part of the image/map is the path that was selected and centered.
Does anybody know how to do this?
I've tried using clipPath natively in HTML and also applying it to the SVG in CSS, both of which don't seem to work. Either that or I'm doing something wrong.
Here is a working demo of the project.
The building can be located near the top middle section of the map. The sub-region, which is easier to locate considering its size, is located in the bottom right hand corner of the map. If you mouseenter them, the paths will fill. If you click on them, they will be centered on the screen.

You can re-use the clip path content as a target area for pointer events if you combine sibling selectors with the right value for pointer-events. Setting this property will both define when CSS pseudo-classes apply and which mouse events will be captured. Your centering code could be triggered by a click event.
document.querySelectorAll('.highlight').forEach(use => {
use.addEventListener('click', e => {
alert(use.id + " was clicked.");
});
});
.highlight {
fill: none;
pointer-events: fill;
}
image {
pointer-events: none;
}
#h1:hover ~ image {
clip-path: url(#clip1);
}
#h2:hover ~ image {
clip-path: url(#clip2);
}
<svg width="500" height="331">
<clipPath id="clip1">
<rect id="path1" x="20" y="20" width="80" height="80" />
</clipPath>
<clipPath id="clip2">
<circle id="path2" cx="400" cy="200" r="80" />
</clipPath>
<!-- use elements must be direct siblings preceding the image -->
<use class="highlight" id="h1" xlink:href="#path1" />
<use class="highlight" id="h2" xlink:href="#path2" />
<image xlink:href="https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" width="500" height="331" />
</svg>

Related

is there a way to reference svg from page in the css?

I see that you can reference the svg by id in some css/svg properties, as in:
<!-- the logo svg -->
<svg id="rect-container" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- left squares -->
<rect fill="url(#rect-fill)"/>
</svg>
does anyone know if we can use a svg from the page, in a css bg for example? to avoid encoding it on the css.
Something like this, which I already tried but did not seem to work the same way.
.myel {
background-image: url(#rect-svg-image);
}
First, there is a misconception to clear up.
fill: url(#source);
does not reference arbitrary SVG content, but a paint server, namely a gradient or pattern. Other uses of the CSS url() notation in SVG include the clip-path, mask and marker-start|mid|end properties that all also can only reference specific elements.
Currently, background-image needs an actual self-contained image resource or a CSS gradient. Referencing a SVG paint server with url() does not work.
But the CSS Images Module Level 4 also defines a element() functional notation that can reference fragments inside the page.
If you look at the text of the specification, there are still a lot of open questions listed to solve before this can become mainstream. There currently is only a Firefox implementation with vendor prefix, -moz-element(). You can point it to paint servers; that means you can (mis)use a <pattern> element. Although experimenting, I found there are some tradeoffs to make:
patternContentUnits="objectBoundingBox" needs all content drawn into a 1px*1px square, but makes the content scalable. Preserving the aspect ratio is not supported.
patternContentUnits="userSpaceOnUse" gives you preservation of the aspect ratio, but scaling is not supported.
svg {
display: block;
width: 0;
height: 0;
}
div {
width: 200px;
height: 150px;
border: 1px solid black;
background-image: -moz-element(#image);
background-size: cover;
}
<svg>
<pattern patternContentUnits="objectBoundingBox"
preserveAspectRatio="xMidYMid meet"
width="100%" height="100%" id="image">
<rect width=".5" height=".5" fill="red"/>
<rect width=".5" height=".5" x=".5" fill="yellow"/>
<rect width=".5" height=".5" y=".5" fill="green"/>
<rect width=".5" height=".5" x=".5" y=".5" fill="blue"/>
<circle r=".5" cx=".5" cy=".5" fill="white" opacity=".5"/>
</pattern>
</svg>
<div>

Why is my SVG showing in Chrome, but not in other browsers?

I am trying to show an SVG with a bit of CSS in browsers like Edge and Firefox. In Chrome it is working as expected, but not in any other browsers. I have singled out the problem in the CodePen below. Don't mind the messy styling (in the original version there is a different font etc).
The problem is that the SVG is simply not shown at all in other browsers. When I inspect the element it does show the code needed, but nothing is there on the front-end. I am not very experienced with SVG.
I have tried: Adding a viewbox (though I am not sure if I did this correctly) and changing the size of the box around it. Neither did help.
CodePen
svg {
font-size: 260px;
}
.colortext .anim-shape:nth-child(1) {
fill: white;
}
.colortext .anim-shape:nth-child(2) {
fill: #19b5b3;
}
section.portfolio-page {
background-color: #252627;
min-height: calc(100vh - 120px)
}
<section class="portfolio-page">
<svg>
<!-- Clippath with text -->
<clipPath id="cp-text">
<text text-anchor="middle" x="50%" y="30%" dy=".38em" class="text--line">
RT
</text>
</clipPath>
<!-- Group with clippath for text-->
<g clip-path="url(#cp-text)" class="colortext">
<!-- Animated shapes inside text -->
<rect width="100%" class="anim-shape"></rect>
<rect width="23%" class="anim-shape blue-logo"></rect>
</g>
</svg>
</section>

Create an element modeled in SVG

I would like to create an HTML element modeled on an SVG.
I tried the following options:
<object>: The tag is working but is causing problems in the animation of the svg. (You can not move the item without generating bugs)
<svg>: The tag does not allow me to add other elements inside, which is forced me to do.
background-image: url (path); does not allow modeling but just to put the image of the svg in the background. The model does not apply and leaves the user activated "onclick" when he clicks on non-drawn edges.
There would be something that could make a tag modeled on the SVG, so that the event "onclick" does not fire if we click on the "square" of the Div but on the round?
Here is a small diagram that summarizes the situation
Well in reality, as you will understand it is not a round model that I want to set up, it's a kind of tab menu, here is an overview:
I use JQUERYUI to handle tab moves, and the tag causes bugs that make it impossible to use.
An imaginary code that could fulfill this function I would like it to exist
<div model="https://example.com/model.svg">
<span>A untitled tab</span>
</div>
A link element in SVG document
If i understand you right you want a clickable svg tab?
.menu-link polygon {
fill: #222;
stroke: #66e;
}
.menu-link:hover polygon {
fill: #eee;
stroke: #88f;
}
.menu-link:hover text {
fill: #222;
}
<svg viewBox="0 0 100 50">
<a class="menu-link" href="#">
<polygon points=" 15,15 20,5 40,5 45,15 15,15"></polygon>
<text x="20" y="12" fill="white" font-size="0.35em">Text here</text>
</a>
<a class="menu-link" href="#">
<polygon fill="#222" stroke="pink" points=" 50,15 55,5 80,5 85,15 55,15"></polygon>
<text x="56" y="12" fill="white" font-size="0.35em">Other text</text>
</a>
</svg>

Is it possible to use an image in place of the stroke of an SVG path?

First off, I know this question is very similar to this question, but I tried implementing that solution with an SVG PATH and it did not work.
I also know that another solution would be to loop the PATH and set the FILL of the PATH as mentioned here and elsewhere on the web.
However, I have animated the STROKE-DASHOFFSET of the PATH so that the stroke of the PATH, which is simply an irregular line, appears as if it is being drawn onto the page; This is the effect that I want to achieve without using a color as the STROKE but instead an image. In other words, it would appear to the user as if the image (and not a solid color) is being drawn onto the page as an irregular line.
As per requested, below is the HTML of the PATH that I am using and its corresponding CSS, an image of that PATH, and also the CSS of the animation itself:
<div id="container">
<svg>
<path d="
M0,5
L184,5
C202,5 202,5 202,36
L202,86
L327,85
L421,166
L460,166
L499,132
L588,211
L617,211
L712,134
L748,165
L780,165
L830,111
L913,212
L938,212
L1028,140
L1078,184
L1107,184
L1152,140
L1263,249
L1263,248"
/>
</svg>
</div>
Image of PATH
#container {
width:1263px; height:255px;
position:absolute;
}
#container svg {
width:100%; height:100%;
fill:none;
stroke:#008066; stroke-width:8;
stroke-dasharray:1628; stroke-dashoffset:1628.1;
stroke-linecap:square;
animation:polyline 3.15s linear 0.5s forwards;
}
#keyframes polyline {
to {
stroke-dashoffset:0;
}
}
Is this possible?
Is this possible by using the CLIPPATH element and then somehow animating it?
TIA
Update
Below is the code with the PATTERN and IMAGE element, and the corresponding CSS, which doesn't seem to produce a stroke.
<defs>
<pattern id="pattern" width="1600" height="800" patternUnits="userSpaceOnUse">
<image xlink:href="http://lorempixel.com/1600/800/nature" width="1600" height="800" />
</pattern>
</defs>
#container svg {
stroke:url(#pattern);
}
That's a Chrome/Safari bug you're relying on.
stroke:url(#pattern);
is actually shorthand for
stroke:url(<this file>#pattern);
but there's no pattern in the css file. Chrome gets this wrong, Firefox gets it right. If you fix the reference Firefox will work but unfortunately Chrome won't any longer. The most compatible solution would therefore be to move your CSS (at least the bit that references the pattern) into the SVG file itself within <style> tags.
It works fine on firefox. I am not sure what the problem is that you are having.
#container svg {
fill: none;
stroke-width: 10px;
stroke: url(#pattern);
stroke-dasharray:1628;
stroke-dashoffset:1628.1;
animation:polyline 3.15s linear 0.5s forwards;
}
#keyframes polyline {
to {
stroke-dashoffset:0;
}
}
<div id="container">
<svg>
<defs>
<pattern id="pattern" width="1600" height="800" patternUnits="userSpaceOnUse">
<image xlink:href="http://lorempixel.com/1600/800/nature" width="1600" height="800" />
</pattern>
</defs>
<path d="M0,5
L184,5
C202,5 202,5 202,36
L202,86
L327,85
L421,166
L460,166
L499,132
L588,211
L617,211
L712,134
L748,165
L780,165
L830,111
L913,212
L938,212
L1028,140
L1078,184
L1107,184
L1152,140
L1263,249
L1263,248"
/>
</svg>
</div>

SVG link a PNG bitmap image ignoring transparency (without path)

I'm having difficulties with an image map-like approach for linking an image but ignoring its transparent areas. Imagine that I have a PNG button with rounded corners (bad example for simplicity's sake, I know about CSS's border-radius), and I only want to have the cursor change on the button itself, ignoring its transparency.
Of course I could just do it like this:
<image width="438" height="189" xlink:href="button.png"></image>
<a xlink:href="//google.com/">
<path id="ab" d="M351.371,342.397c-55 …" />
</a>
But what if I want to do that dynamically e.g. having a JS function generating the markup for different-sized images using the same technique? Maybe using an SVG mask?
The following snippet of course links the whole image...
<a xlink:href="//google.com">
<image width="438" height="189" xlink:href="button.png"></image>
</a>
I have come across a couple of questions here on SO with png images in svg.
There seems to be little support for this in a couple of browsers. I don't have the time to test all major browsers atm.
But your trying to create a button with rounded corns that's only clickable on the painted area, not the transparent part?
Why not use svg rect to create that button?
svg text {
fill: white;
}
svg rect {
fill: firebrick;
stroke: gray;
}
svg a:active rect {
stroke: black;
}
svg a:active text {
text-shadow: 2px 2px 2px black;
}
<svg viewBox="0 0 100 100" width="50%">
<a xlink:href="#">
<rect x="20" y="30" width="70" rx="5" height="30" />
<text x="30" y="50">Submit</text>
</a>
</svg>