How to create a clickable grid of triangles using html, svg? - html

I have already created a grid of triangles like so:
svg {
margin-left: 0px;
margin-right: -60px;
padding: 0;
}
<div data-bind="foreach: Grid">
<div data-bind="foreach: $data.rowData">
<!-- ko if: $data.owner() === 0 && ($data.pos[0] + $data.pos[1])%2 === 0-->
<svg height="103.92" width="120">
<polygon class="" points="60,0 0,103.92 120,103.92" style="fill:grey;" data-bind="click: $root.test.bind($data, $data)" />
</svg>
<!-- /ko -->
<!-- ko if: $data.owner() === 0 && ($data.pos[0] + $data.pos[1])%2 === 1-->
<svg height="103.92" width="120">
<polygon class="" points="0,0 120,0 60,103.92" style="fill:grey;" data-bind="click: $root.test.bind($data, $data)" />
</svg>
<!-- /ko -->
</div>
</div>
My problem is that only the left half of the triangles is clickable. I think this is due to the (still rectangular) shape of the svg-element. But I have no idea how to fix this. Is there any way to make every triangle clickable in its whole area?

At the moment, all your individual SVGs are overlapping one another and any click that misses a triangle will be swallowed by the parent <svg> element.
The cleanest solution would be to put all your polygons in one big SVG. However there is another way around your problem using the pointer-events property.
Set pointer-events="none" on your <svg> elements so that clicks will pass through them. But you'll also need to set an explicit pointer-events="fill" on your polygons, since otherwise they'll inherit the "none" from their parent SVGs.
var output = document.getElementById("output");
document.getElementById("red").addEventListener("click", function(e) {
output.textContent = "red";
});
document.getElementById("green").addEventListener("click", function(e) {
output.textContent = "green";
});
svg {
position: absolute;
top: 0;
left: 0;
pointer-events: none;
}
polygon {
pointer-events: fill;
}
#output {
margin-top: 120px;
}
<svg width="100px" height="100px">
<polygon points="0,0,100,0,100,100" fill="red" id="red"/>
</svg>
<svg width="100px" height="100px">
<polygon points="0,0,100,100,0,100" fill="green" id="green"/>
</svg>
<div id="output"></div>

You should use one svg tag with both polygons inside it. This way the Square svg elements won't overlap each other:
polygon {
fill: grey;
}
polygon:hover {
fill: #000;
}
<svg height="103.92" width="185">
<polygon points="60,0 0,103.92 120,103.92" />
<polygon points="65,0 185,0 125,103.92" />
</svg>

Related

I would like to put an image inside svg shape and hide the overflow parts

.container{
position: relative;
width: 692px;
}
.image{
position: absolute;
width: 403px;
height: 602px;
top: 91px;
left: 92px;
}
<html>
<body>
<div class="container">
<svg width="581" height="692" viewBox="0 0 581 692" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M526.636 489.523C598.467 361.569 590.666 251.284 551.879 107.757C538.582 58.5517 506.556 -37.4658 444.069 -103.204C320.276 -233.438 122.218 -189.737 6.51981 -180.688C-109.178 -171.639 -138.103 -67.5724 -164.924 3.12491C-191.745 73.8223 -123.378 416.563 -84.461 503.097L-84.2626 503.538C-45.3885 589.978 0.49324 692 167.445 692C334.682 692 444.781 635.333 526.636 489.523Z"
fill="green"/>
</svg>
<div class="image">
<img src="https://dummyimage.com/403x602/000/efefef" width={403} height={602}/>
</div>
</div>
</body>
</html>
Please don't mind the white background of image.
As you can see, I would like to remove the bottom-right overflow parts. The green area is the svg. I tried with z-index and svg clip-path. Unfortunately those methods didn't work for me somehow. Help is much appreciated. Thanks.
As I've told you in the comment: you can put the image inside the svg and clip the image with the path.
<svg width="581" height="692" viewBox="0 0 581 692" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="thePath" d="M526.636 489.523C598.467 361.569 590.666 251.284 551.879 107.757C538.582 58.5517 506.556 -37.4658 444.069 -103.204C320.276 -233.438 122.218 -189.737 6.51981 -180.688C-109.178 -171.639 -138.103 -67.5724 -164.924 3.12491C-191.745 73.8223 -123.378 416.563 -84.461 503.097L-84.2626 503.538C-45.3885 589.978 0.49324 692 167.445 692C334.682 692 444.781 635.333 526.636 489.523Z" fill="green" />
<clipPath id="cp">
<use href="#thePath" />
</clipPath>
<image clip-path="url(#cp)" href="https://dummyimage.com/403x602/000/efefef" width="403" x="100" y="100" />
</svg>

How can I make a <svg> parent container adapt to the size of its <svg> element? [duplicate]

This question already has answers here:
Image inside div has extra space below the image
(10 answers)
Closed last year.
There are two containers, myapp-icon (green) and myapp-svg-icon (blue), containing an SVG element (red).
Screenshot
I would expect the blue box to have the same size as the red box, but it's not. What am I doing wrong?
Sandbox: https://jsfiddle.net/ja1vnop9/
Minimal example:
<html>
<style>
myapp-icon {
background: green;
}
myapp-svg-icon {
background: blue;
}
svg {
background: red;
}
</style>
<body>
<myapp-icon>
<myapp-svg-icon>
<svg height="80" viewBox="0 0 67 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M52.3737 11.0954H51.8242C50.1613 7.38468 47.3573 4.31697 43.8301 2.34953C40.303 0.382096 36.2417 -0.37969 32.2516 0.177742C28.2616 0.735173 24.5565 2.58197 21.6887 5.44281C18.8209 8.30365 16.944 12.0253 16.3378 16.053C14.7917 15.4659 13.143 15.2054 11.4935 15.2877C9.84392 15.37 8.22856 15.7932 6.74701 16.5314C5.26547 17.2695 3.94917 18.3069 2.87933 19.5795C1.80948 20.852 1.00879 22.3328 0.526636 23.9305C0.0444866 25.5282 -0.10889 27.2089 0.0759685 28.8688C0.260827 30.5288 0.780001 32.1328 1.60146 33.5819C2.42292 35.0311 3.52923 36.2946 4.85216 37.2946C6.17508 38.2946 7.68655 39.0098 9.29332 39.3961C10.429 39.7743 11.6146 39.9767 12.8101 39.9963H52.3737C56.1628 39.9963 59.7967 38.4739 62.476 35.7639C65.1553 33.0539 66.6606 29.3784 66.6606 25.5458C66.6606 21.7133 65.1553 18.0378 62.476 15.3278C59.7967 12.6178 56.1628 11.0954 52.3737 11.0954Z"
fill="#FFDA33" _ngcontent-wsq-c51=""></path>
</svg>
</myapp-svg-icon>
</myapp-icon>
</body>
</html>
Add display: block; to your svg CSS...
<html>
<style>
myapp-icon {
background: green;
}
myapp-svg-icon {
background: blue;
}
svg {
background: red;
display: block;
}
</style>
<body>
<myapp-icon>
<myapp-svg-icon>
<svg height="80" viewBox="0 0 67 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M52.3737 11.0954H51.8242C50.1613 7.38468 47.3573 4.31697 43.8301 2.34953C40.303 0.382096 36.2417 -0.37969 32.2516 0.177742C28.2616 0.735173 24.5565 2.58197 21.6887 5.44281C18.8209 8.30365 16.944 12.0253 16.3378 16.053C14.7917 15.4659 13.143 15.2054 11.4935 15.2877C9.84392 15.37 8.22856 15.7932 6.74701 16.5314C5.26547 17.2695 3.94917 18.3069 2.87933 19.5795C1.80948 20.852 1.00879 22.3328 0.526636 23.9305C0.0444866 25.5282 -0.10889 27.2089 0.0759685 28.8688C0.260827 30.5288 0.780001 32.1328 1.60146 33.5819C2.42292 35.0311 3.52923 36.2946 4.85216 37.2946C6.17508 38.2946 7.68655 39.0098 9.29332 39.3961C10.429 39.7743 11.6146 39.9767 12.8101 39.9963H52.3737C56.1628 39.9963 59.7967 38.4739 62.476 35.7639C65.1553 33.0539 66.6606 29.3784 66.6606 25.5458C66.6606 21.7133 65.1553 18.0378 62.476 15.3278C59.7967 12.6178 56.1628 11.0954 52.3737 11.0954Z"
fill="#FFDA33" _ngcontent-wsq-c51=""></path>
</svg>
</myapp-svg-icon>
</myapp-icon>
</body>
</html>

Cropped SVG with Clip-path changes Height on zooming in and out [duplicate]

I wanted a cylindrical container containing liquid and this liquid changes color and its amount in that container, So I used SVG for this purpose (SVG is used for liquid in a cylindrical container).
Here is the source code along with SVG
function changeCol(col) {
document.querySelector('path').style.setProperty('fill', col, '!important');
document.querySelector('ellipse').style.setProperty('fill', col, '!important');
//Its not working I dont know why.
}
function changeHeight(vol) {
//Some Code to change its height.
}
.container {
width: fit-content;
border: solid red;
}
.liquid {
width: 200px;
}
.liquid svg * {
fill: red !important;
}
<div class="container">
<div class="liquid">
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 216.66 325.25">
<title>liquid_RBt</title>
<path d="M216.66,28V297.25c0,15.47-48.5,28-108.33,28S0,312.72,0,297.25V28C0,43.46,48.5,56,108.33,56S216.66,43.46,216.66,28Z" style="fill:#fff;stroke:#fff;stroke-miterlimit:10;opacity:0.7000000000000001"/>
<ellipse cx="108.33" cy="28" rx="108.33" ry="28" style="fill:#fff;stroke:#fff;stroke-miterlimit:10;opacity:0.8"/>
</svg>
</div>
</div>
<div class="controller">
<div class="color-change">
<button class="col-btn" onclick="changeCol('red');">Red</button>
<button class="col-btn" onclick="changeCol('blue');">Blue</button>
<button class="col-btn" onclick="changeCol('green');">green</button>
</div>
<div class="change-amount">
<input type="number" id="amountInp" onchange='changeHeight(this.value)' placeholder="(in ml)">
</div>
</div>
I've clipped the path with a clipPath that I then move about to hide the parts of the polygon that need to disappear.
I don't know the volume of the cylinder either so you might want to scale the number.
I also fixed the colouring.
function changeCol(col) {
document.querySelector('path').style.setProperty('fill', col);
document.querySelector('ellipse').style.setProperty('fill', col);
}
function changeHeight(vol) {
// not sure how much 100ml is supposed to fill up
document.querySelector('ellipse').cy.baseVal.value = 300 - vol;
document.querySelector('rect').y.baseVal.value = 300-vol;
}
.container {
width: fit-content;
border: solid red;
}
.liquid {
width: 200px;
}
<div class="container">
<div class="liquid">
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 216.66 325.25">
<title>liquid_RBt</title>
<defs>
<clipPath id="cp">
<rect x="0" y="0" width="230" height="400"/>
</clipPath>
</defs>
<path d="M216.66,28V297.25c0,15.47-48.5,28-108.33,28S0,312.72,0,297.25V28C0,43.46,48.5,56,108.33,56S216.66,43.46,216.66,28Z" style="fill:red;stroke:#fff;stroke-miterlimit:10;opacity:0.7000000000000001;clip-path: url(#cp)"/>
<ellipse cx="108.33" cy="28" rx="108.33" ry="28" style="fill:red;stroke:#fff;stroke-miterlimit:10"/>
</svg>
</div>
</div>
<div class="controller">
<div class="color-change">
<button class="col-btn" onclick="changeCol('red');">Red</button>
<button class="col-btn" onclick="changeCol('blue');">Blue</button>
<button class="col-btn" onclick="changeCol('green');">green</button>
</div>
<div class="change-amount">
<input type="number" id="amountInp" onchange='changeHeight(this.value)' placeholder="(in ml)">
</div>
</div>
Set the preserve aspect ratio to none.
<svg preserveAspectRatio="none" /* here are your other attributes */>

Use SVG image on website with rounded corners - showing white for rounded area

I am creating a very simple React page with an SVG image on it. That SVG image has round corners. I can open it up in GIMP and see the rounded corners shown.
Now I add it to my website like this:
import cardBackR from '../img/cards/2B.svg'
...
<img className='card' src={cardBackR} />
And then when I view the page with the card over a background image, the rounded corners show as white:
Here is the full SVG code of that image.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" class="card" face="2B" height="3.5in" preserveAspectRatio="none" viewBox="-120 -168 240 336" width="2.5in">
<defs>
<pattern id="B2" width="6" height="6" patternUnits="userSpaceOnUse">
<path d="M3 0L6 3L3 6L0 3Z" fill="red"></path>
</pattern>
</defs>
<rect width="239" height="335" x="-119.5" y="-167.5" rx="12" ry="12" fill="white" stroke="black"></rect>
<rect fill="url(#B2)" width="216" height="312" x="-108" y="-156" rx="12" ry="12"></rect>
</svg>
I've tested this in both Firefox and Chrome. Any ideas what is causing the rounded corners to fail?
SVG in an IMG src should work fine, provided you escape the # with %23
<style>
body{
background:green;
}
</style>
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'
class='card' face='2B' height='3.5in' preserveAspectRatio='none' viewBox='-120 -168 240 336' width='2.5in'>
<defs><pattern id='B2' width='6' height='6' patternUnits='userSpaceOnUse'>
<path d='M3 0L6 3L3 6L0 3Z' fill='red'></path></pattern></defs>
<rect width='239' height='335' x='-119.5' y='-167.5' rx='12' ry='12' fill='white' stroke='black'></rect>
<rect fill='url(%23B2)' width='216' height='312' x='-108' y='-156' rx='12' ry='12'></rect>
</svg>">
Figured out the issue. I unfortunately picked a poor name for my class. That is a special class in Bootstrap and that was adding the following CSS:
.card {
position: relative;
display: flex;
flex-direction: column;
min-width: 0;
word-wrap: break-word;
background-color: #fff;
background-clip: border-box;
border: 1px solid rgba(0, 0, 0, 0.125);
border-radius: 0.25rem;
}

Style SVG loaded to HTML as content tag with CSS

I have 3 files:
index.html
<!DOCTYPE html>
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<i class="logo myRed" aria-hidden="true"></i>
</body>
</html>
style.css
.logo:before {
content: url("logo.svg");
}
.myRed {
color: #ff2000;
}
logo.svg
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="300" height="100">
<rect id="logo" width="300" height="100" />
</svg>
How to style the SVG that is pointed out in the CSS content property? (eg. color, font-size, ...) - like in FontAwesome.
You can't.
CSS content: url(image.ext) is similar to loading your image in a <img> tag. And loading an image in a <img> is under the hood loading it in an isolated document, inaccessible for anyone, and which can't access anything.
FontAwesome doesn't load icons like that, they build font-faces, and then call corresponding characters in the content property, e.g something like "\f07b".
So for the browser, FontAwesome icons are just text, and you can style it like any other text.
To style an SVG through CSS, it needs to be in the same document as your stylesheet (or cloned through <use>).
Ok, there is one hack, which may help you, but I can't tell how well it is nor will be supported:
Lea Verou demonstrated that we can (ab)use the :target CSS selector along with the #elem_id fragment identifier to show specific nodes of an SVG Element or apply specific rules.
In you svg's <style> you can create rules like these ones :
#elem_id_1:target ~ #elem_to_color{
fill: red;
}
#elem_id_2:target ~ #elem_to_color{
fill: green;
}
Then in your markup, you just need to have some empty elements placed before #elem_to_color with corresponding ids.
<g id="elem_id_1"></g>
<g id="elem_id_2"></g>
<rect id="elem_to_color"/>
Now when you will load your svg as yourfile.svg#elem_id_1, the first rule will apply and #elem_to_color will be red. If you load it as yourfile.svg#elem_id_2, then #elem_to_color will be green.
This hack allows to have a single svg file, on which we can externally control the rendered styles.
/* a single file for all colors */
.logo::after {
content: url(https://dl.dropboxusercontent.com/s/2pkolmx0d9pebgl/logo.svg);
}
.logo.green::after {
content: url(https://dl.dropboxusercontent.com/s/2pkolmx0d9pebgl/logo.svg#green);
}
.logo.red::after {
content: url(https://dl.dropboxusercontent.com/s/2pkolmx0d9pebgl/logo.svg#red);
}
<!-- logo.svg content
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="30" height="30">
<style>
#green:target ~ #elem_to_color{
fill: green;
}
#red:target ~ #elem_to_color{
fill: red;
}
</style>
<g id="red"></g>
<g id="green"></g>
<rect id="elem_to_color" width="30" height="30"/>
</svg>
-->
<i class="logo"></i>
<i class="logo green"></i>
<i class="logo red"></i>
Use these CSS properties:
fill: /* color */
font-size: /* font-size */
It will override the original SVG values, as demonstrated below.
.logo svg {
fill: #eee;
}
.logo svg text {
font-size: 30px;
}
.myRed {
color: #ff2000;
}
<div class="logo myRed" aria-hidden="true">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect id="logo" width="300" height="100" />
<text style=" stroke:black; fill:red;" x="30" y="50" font-size="8">Text Here</text>
</svg>
</div>
A more simplified solution would be the following. The first line of css sets the text color (fill), the second line sets the font properties for the text element and the third line targets the rectangle id (logo) to set the fill.
.logo svg {
fill: #ff0000;
}
.logo svg text {
font-size: 45px;
font-face:Arial,Helvetica;
font-weight:bold
}
#logo {
fill:#eee;
}
<div class="logo" aria-hidden="true">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect id="logo" width="300" height="100" />
<text x="30" y="50">Text Here</text>
</svg>
</div>