I have been trying to implement the following requirements.
1. SVG path to have multiple colors on different sections (eg - red color the curves and rest of it, in black color)
2. Only allow mouse event- click on those colored areas (curves)
I have tried with plain javascript and snap.svg
Plain html & Javascript
[Codepen using HTML & Js][1]
SNAP.svg
[Codepen using SNAP.svg][2]
[1]: https://codepen.io/sanathko1234/pen/vvMQQZ
[2]: https://codepen.io/sanathko1234/pen/OrGoRa
How can this be achieved?
One solution would be to use the path twice: first the green one and next the one using stroke-dasharray. The dashes are only over the curves. If you don't like the position or the length of the dashes change them to what you need. The gaps are not sensitive to mouse events, only the dashes are.
In css I've added #gold:hover{cursor:pointer} so that you can see that only the dashes are sensitive to the mouse.
I hope it helps.
svg{border:1px solid}
use{fill:none;stroke-width:18;}
#gold:hover{cursor:pointer}
<svg viewBox="-10 50 580 360" width="580" height="360" xmlns="http://www.w3.org/2000/svg">
<defs>
<path id="svg_1" d="m555,272c1,0.76736 4,85.76736 -71,97.76736c-75,12 -387,-39 -388,-39.76736c0,-0.23264 -29,-1.23264 -45,-21.23264l-42,-124.76736c-3,-11.23264 -3,-21.23264 3,-26.23264c6,-5 46,-67 69,-69.76736l474,184z" />
</defs>
<g>
<title>background</title>
<rect fill="#fff" id="canvas_background" height="360" width="580" x="-10" y="50"/>
</g>
<g>
<title>Layer 1</title>
<use xlink:href="#svg_1" stroke="green" />
<use xlink:href="#svg_1" stroke="gold" stroke-dasharray ="130 370 110 60 90 40 90 400 52.45" id="gold" pointer-events="stroke" />
</g>
</svg>
Observation: the sum of the dashes and the gaps is 1342.45 which is also the total path length.
I have an svg rect like this:
<svg class="legend-square">
<defs>
<pattern id="pattern1" width="3"
height="3" patternunits="userSpaceOnUse" patterntransform="rotate(-45)">
<rect width="2" height="3" transform="translate(0,0)" fill="purple"></rect>
</pattern>
</defs>
<rect width="12" height="12" fill="url(#pattern1)"></rect>
</svg>
When I inspect the second rect with Chrome it has no width and height. There are no CSS rules applying to it. Why doesn't it get affected by width and height?
One of the reasons why SVG file is rendered on front-end with zero height and width is missing <svg> tag attributes "height" and "width".
Incorrect:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 49 30">
Correct:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 49 30" width="49" height="30">
It works fine.
If the snippet works individually but size of div containing it in you code appears 0x0 then look into : Why is my div's height zero
Its usually caused when float is set.
<div>
<svg class="legend-square">
<defs>
<pattern id="pattern1" width="3" height="3" patternunits="userSpaceOnUse" patterntransform="rotate(-45)">
<rect width="2" height="3" transform="translate(0,0)" fill="purple"></rect>
</pattern>
</defs>
<rect width="12" height="12" fill="url(#pattern1)"></rect>
</svg>
</div>
You really haven't provided enough information. For instance, what is the parent element of your SVG?
Just because your <rect> has a width and hight, it doesn't mean your SVG does. SVG is not like HTML, where elements expand to fit their children. SVG is like the <canvas> element. You have to make sure it either explicitly (or implicitly) has a size.
You have not specified width or height attributes for your <svg> element, so they are both defaulting to "100%". What they are 100% of depends on what size the SVG's parent element is. Hence my first question above.
For an 'inline' SVG element you have to apply the styles, inside the svg element itself.
inside the <defs></defs> tags. Since it has its Own DOM[Document Object Model], Css Apllied to it from Outside, will have no effect.
You have Several different options for embeding an SVG, You can use it inline as in your example where you declare the <svg></svg> inside of your html/php document or you can use one of the many other methods listed below;
embed an: ..............................................<img src="../pathtoyourSvg"></img>
embed as an img with a fallback option: <img src="logo.png" srcset="logo.svg" alt="My logo">
use an: ....................................................<object type="image/svg+xml" data="image.svg">
<!-- Your fall back here -->
<img src="image.svg" />
</object>
use: .........................................................<embed type="image/svg+xml" src="image.svg" />
use an: ....................................................<iframe></iframe>
embed the Svg inside of a canvas element using Javascript:
var img = new Image();
img.onload = function() {
ctx.drawImage(img, 0, 0);
}
img.src = "path2your.svg";
You may Also Embed the Svg using Css Background image,
ie:
.mySvgContainer{
background-image:url('PathToMySvg');
}
But from the comments & Questions I have read, this need to be either Url or Base64 encoded, which seems a bit Hacky and not very convenient.
each of them have their own advantages and disadvantages.
Because of security reasons, some SVG embedding methods will block access to external resources including CSS, fonts and javascript. Especially when we have multiple images, ideally our embedding method should be able to refer to a single CSS, font or javascript file (to save resources) and be able to manipulate our embedded SVG.
Also worth mentioning that if you have display:flex; attached to an elemnet or its parent then the width and height values will have no effect on the flex items. So It may appear as 0, 0, in the console.
Some Useful Information & related questions:
Svg Coords & Units w3.org
Svg Width - Height
Applying Styles to an embedded Svg
You can wrap your svg element inside the html5 object element.
<style type="text/css">
object{
width:300px;
height:200px;
}
object svg{
width:100%;
height:100%;
}
</style>
<object>
<svg class="legend-square">
<defs>
<pattern id="pattern1" width="3"
height="3" patternunits="userSpaceOnUse" patterntransform="rotate(-45)">
<rect width="2" height="3" transform="translate(0,0)" fill="purple"></rect>
</pattern>
</defs>
<rect width="12" height="12" fill="url(#pattern1)"></rect>
</svg>
</object>
You can set height and width on the object element just link any other html element while you can set height width to 100% for SVG element. It will work. But first, test your SVG by opening the file directly in chrome.
I have an svg element in my page with several polygons that together create a sort of "map", I'd like to put an <img> element in these polygon so I can have access to its parent Id (the polygon owner) and know how many images I have inside a polygon.
How can I do it?
<div id="Div-mappa" >
<svg id="Mappa" version="1.1" xmlns="http://www.w3.org/2000/svg">
<polygon
class="regione"
id="Area1"
onclick="attiva(this.id)"
points="1,0,1,110,6,107,14,103,19,103,24,109,29,113,31,116,35,119,37,121,44,119,51,116,53,112,60,110,63,106,65,99,64,90,64,85,64,77,66,73,68,68,69,64,72,64,74,65,76,67,76,69,78,71,81,68,86,62,91,59,99,57,107,56,114,54,126,52,129,46,132,40,134,37,131,31,127,27,126,21,126,17,127,12,127,7,127,4,127,2,128,0"/>
<polygon
class="regione"
id="Area2"
onclick="attiva(this.id)"
points="129,1,129,11,128,18,129,23,132,30,134,36,138,40,147,43,149,46,149,51,159,53,168,55,172,55,170,60,168,64,168,68,170,73,174,78,175,82,174,86,174,92,175,98,178,104,186,107,198,106,206,107,217,103,224,103,232,99,239,97,240,92,238,88,244,90,249,92,255,97,256,98,258,93,263,88,265,84,263,79,258,71,257,65,258,60,261,57,261,53,260,46,263,42,265,40,265,35,264,32,261,27,261,24,262,20,265,16,265,13,263,9,263,6,263,4,262,2,261,0"/>
</svg>
</div>
The idea is pretty simple:
I have an SVG path and an Rect,
I need to make the path carve through the Rect, the resulting "hole" should be see-through.
Here's jsfiddle with a copy of how it's looking right now:
https://jsfiddle.net/9u0jyhr7/embedded/result/
current HTML example:
<div id="container">
<svg id="theSVG" xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect id="theRect" width="100%" height="100%" fill="#ffffff"></rect>
<path id="thePath" d="M7 25.69305419921875L7 25.6875L7.00505256652832 25.6875L293.9971923828125 25.6875L294 25.6875L294 25.709388732910156L294 90.67454528808594L294 90.6875L294.0021667480469 90.6875L321.85845947265625 90.6875L321.8607482910156 90.6875L294 183.69180297851562L294 206.421142578125L294 206.42408752441406L294 206.42701721191406L294 228.93441772460938L294 228.936279296875L294 228.93814086914062L294 248.68634033203125L294 248.6875L294.0007629394531 248.6875L304.7754211425781 248.6875L304.7763671875 248.6875L304.7773132324219 248.6875L306.581298828125 248.6875L306.581298828125 248.6875L306.582275390625 248.6875L306.582275390625 248.6875L306.583251953125 248.6875L306.583251953125 248.6875L324.73028564453125 248.6875L324.7316589355469 248.6875L324.7330017089844 248.6875L330.1683044433594 248.6875L330.1697998046875 248.6875L330.1712951660156 248.6875L357.22027587890625 248.6875L357.22265625 248.6875L357.2250061035156 248.6875L360.99749755859375 248.6875L361 248.6875L507 172.48577880859375L507 342.3311767578125L507 342.3337097167969L502.9844665527344 341.6875L436.00836181640625 341.6875L436 341.6875L436 341.6893615722656L436 378.0494079589844L436 378.051513671875L436 378.0536193847656L436 406.68511962890625L507 448.48748779296875L507 448.4908447265625L507 578.6819458007812L507 578.6875L506.9949951171875 578.6875L479.0045166015625 578.6875L479 578.6875L289.9993591308594 341.6875L279.00048828125 341.6875L279 341.6875L278.99951171875 341.6875L273.92425537109375 341.6875L273.9237976074219 341.6875L273.92333984375 341.6875L270.4071350097656 341.6875L270.4067077636719 341.6875L270.4062805175781 341.6875L265.60040283203125 341.6875L265.6000061035156 341.6875L265.5995788574219 341.6875L264.8004150390625 341.6875L264.79998779296875 341.6875L264.7995910644531 341.6875L263.8423156738281 341.6875L263.8419189453125 341.6875L263.84149169921875 341.6875L263.2403869628906 341.6875L263.239990234375 341.6875L263.2395935058594 341.6875L253.1584930419922 341.6875L253.15809631347656 341.6875L253.15769958496094 341.6875L251.40040588378906 341.6875L251.39999389648438 341.6875L251.39959716796875 341.6875L245.081787109375 341.6875L245.0813446044922 341.6875L245.08090209960938 341.6875L223.00071716308594 341.6875L223 341.6875L9.995001792907715 578.6875L7.00505256652832 578.6875L7 578.6875L7 578.6819458007812 " fill="#000000"></path>
</svg>
</div>
Here's an image of what it would probably look like if we can carve that hole:
http://i.stack.imgur.com/5fjBR.png
The Path is dynamically generated and can be quite complex, so I can't really eyeball the result.
It has to be done in javascript (or with some very clever usage of styles).
I need the result to be a DOM node that I can eventually move between z-indexes (could be grouped? a resulting "difference" path calculated in js?).
Performance and experimental features are not an issue, this is aimed at nwjs app.
Some other notes:
I'm already using jQuery, svg.js and a bunch of other libraries, so adding
new libraries is not a problem.
The rect could also be replaced by just a color filled div, if that helps solve the problem.
Ive already tried masks and clips but couldnt come to a working solution.
Any help appreciated, Thank you in advance.
A mask is what you need. I'm not sure what you tried before, but it should do what you want.
Just create a mask like so:
<defs>
<mask id="theMask">
<rect width="100%" height="100%" fill="white"/>
<path id="thePath" d="..." fill="#000000"></path>
</mask>
</defs>
Either move the original path into the mask, or copy it and hide the original.
Then apply the mask to the rect
#theRect {
mask: url(#theMask);
}
Demo fiddle here
Is it possible to have multiple SVGs that are next to each other horizontally. I know that when you append a SVG in D3, it appends in below the previous SVG. But now I have the previous SVG on half the page, and I want to translate this SVG from below the previous SVG to the right of the previous SVG. I tried using the transform-->translate attribute on the second svg but it did not work:
var secondSVG= d3.select("#div1").append("svg").attr("width",960).attr("transform"),"translate(500, -500)");
In Chrome 24, IE10, and FF17 this jsFiddle worked as expected. The key seemed to be setting the width and height stylesheet properties.
HTML:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="190" id="svg1">
<polygon points="100,10 40,180 190,60 10,60 160,180"
style="fill:lime;stroke:purple;stroke-width:5;fill-rule:evenodd;">
</svg>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="190" id="svg2">
<polygon points="100,10 40,180 190,60 10,60 160,180"
style="fill:lime;stroke:purple;stroke-width:5;fill-rule:evenodd;">
</svg>
CSS:
svg
{
width: 190px;
height: 190px;
}
Awhile back I wanted to do something similar, but I eventually settled on using a single svg element with two internal g elements, one of them transformed to the right. You can see the eventual finished product here.
General idea: Wrap each SVG in a div element that is displayed as inline-block.
This works with the following approach that I personally like anyway.
Set the width and height attributes of the SVGs to 100%.
"Inner impact": Specify the size of the drawing area (which the units of the elements in the SVGs, like circle, relate to) with the viewBox attribute; this typically goes together with the preserveAspectRatio attribute.
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio
"Outer impact": The SVGs will adapt to the size of their container. Style it (width and/or height) according to your wishes. Of course you need enough horizontal space.
Minimal example:
<div style="display: inline-block; width: 42%">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-80 -45 160 90" preserveAspectRatio="xMinYMin meet">
<circle cx="0" cy="0" r="39">
</svg>
</div>
<!-- Just a copy from above. Right of (not below) the previous SVG. -->
<div style="display: inline-block; width: 42%">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-80 -45 160 90" preserveAspectRatio="xMinYMin meet">
<circle cx="0" cy="0" r="39">
</svg>
</div>