How I can set auto height to svg element? - javascript

I have svg element and 4 rect in it.
<svg class="quarterly-graph">
<rect y="0" width="100%" height="5" transform="translate(0,0)" style="fill: #ffffff;"></rect>
<rect y="5" width="100%" height="90" transform="translate(0,0)" style="fill: #e7f0f5;"></rect>
<rect y="95" width="100%" height="5" transform="translate(0,0)" style="fill: #ffffff;"></rect>
<rect y="100" width="100%" height="5" transform="translate(0,0)" style="fill: #e7f0f5;"></rect>
</svg>
I have simple css for it:
.quarterly-graph {
height : auto;
border: 1px #000000 solid;
}
How I can set svg height equal height of 4 rects?
jsfiddle example: http://jsfiddle.net/CpZQY/

AFAIK you cannot do this with pure CSS. Your SVG does not specify all required attributes and thus default sizes will be used instead. You will have to specify the viewport/size at the SVG element. This should be no problem, because you have hard coded values in the rects, too. If you add a width="105px" to your svg element you do not need the CSS height directive anymore.

Related

Center elements inside SVG relative to each other-

Couldn't find it anywhere else to I might ask here :
I have svg rectangle which inside has other rectangles.
What I want to achieve is to center each of these rectangles in the centre of it's parent and in relation to each other.
If I drag rectangle 1 down I want the other one to move up to keep both of them centered - and same thing happening if I drag the other element down (should push upper one up).
Problem here is that I might have different width/heights and there would be 2 or more elements. Is there any mathematical equationfor that? Or a name that I can look for?
I would put the 3 rects inside a group and use the group as in the following example
svg{
border:1px solid;
width: 30vh;
}
<svg viewBox="0 0 100 280">
<defs>
<g id="rects">
<rect width="80" height="80" />
<rect width="60" height="25" x="10" y="10" />
<rect width="60" height="25" x="10" y="45" />
</g>
</defs>
<use xlink:href="#rects" x="10" y="10" stroke="black" fill="none" />
<use xlink:href="#rects" x="10" y="100" stroke="black" fill="none" />
<use xlink:href="#rects" x="10" y="190" stroke="black" fill="none" />
</svg>

Hover events for a dashed line in an SVG

An SVG with a line (or path) which uses stroke-dasharray only seems to trigger CSS and JS hover events when the user hovers over the solid parts of the dashed line: https://codepen.io/anon/pen/YeXoZy
Is there a simple way to make both the JS and CSS events trigger when the solid or invisible parts of the line are hovered?
My current plan is to draw a second, invisible line following the same path and use it to detect mouse events. https://codepen.io/anon/pen/BYNgRR This seems heavy handed and I'm hoping there's a cleaner way I'm missing.
I'm not sure how to do it without the second "detector" line, but a less heavy handed way is at least possible without the JS.
Switch the order of the lines, then you can use the hover selector as usual for the dashed line, then use + in a selector for the detector line to change the properties of the line immediately following it:
https://codepen.io/RyanGoree/pen/LQVKBV
This can be solved somewhat by using a rect instead of line and using SVG transforms with patterns.
An example can be seen at this CodePen.
It essentially bubbles down to:
<svg height="210" width="500">
<defs>
<pattern id="pattern1"
width="10" height="10"
patternUnits="userSpaceOnUse"
patternTransform="rotate(0 60 60)">
<line stroke="green" stroke-width="12px" y2="10"/>
</pattern>
<pattern id="pattern2"
width="10" height="10"
patternUnits="userSpaceOnUse"
patternTransform="rotate(0 60 60)">
<line stroke="red" stroke-width="12px" y2="10" stroke="transparent"/>
</pattern>
</defs>
<g transform="rotate(45 60 60)">
<rect x="0" y="0" width="500" height="5"/>
</g>
</svg>
And the following CSS:
rect {
fill: url(#pattern1)
}
rect:hover {
fill: url(#pattern2)
}
This is an old topic I know. But found the answer on Css hover sometimes doesn't work on svg paths
If you want to trigger the event only on stroke/visible, use pointer-events: stroke; or pointer-events: visible; (only the stroke) and pointer-events: all; (on both)
Here is a code example:
<body>
<div id="donut-score" class="svg-item" style="display: block;">
<svg width="100%" height="100%" viewBox="0 0 40 40" class="donut">
<circle class="donut-hole" cx="20" cy="20" r="15.91549430918954" fill="#fff"></circle>
<circle class="donut-ring" cx="20" cy="20" r="15.91549430918954" fill="transparent" stroke-width="3.5"></circle>
<circle id="donut-score-part-1" class="donut-segment donut-segment-1" onmousemove="this.style.stroke ='orange';" onmouseout="this.style.stroke = '#ff8197';" cx="20" cy="20" r="15.91549430918954" fill="transparent" stroke-width="3.5" stroke-dasharray="20 80" stroke-dashoffset="25"></circle>
<g class="donut-text-item donut-text-item">
<text y="50%" transform="translate(0, 2)">
<tspan id="donut-score-text" x="50%" text-anchor="middle" class="donut-text">Score </tspan>
<tspan id="donut-score-aantal" x="50%" Y="65%" text-anchor="middle" class="donut-text">0 </tspan>
</text>
</g>
</svg>
</div>
</body>
ccs:
.donut-segment {
stroke: #ff8197;
}
.svg-item {
width:200px;
font-size: 16px;
margin: 0 auto;
}
.donut-text {
font-size: 0.35em;
line-height: 1;
transform: translateY(0.5em);
font-weight: bold;
}
If you add pointer-events: stroke; to the class .donut-segment then it only works on the stroke. If you use non or pointer-events: all it works on both. I tested it in codepen.

How to use enter(), exit() and update with horizontal "stacked" chart

I have a pseudo-stacked, horizontal chart. I saw pseudo because it mimics a stacked chart but is not really multiple stacked values, but rather 3 different values that add up to a total of 100%. I'm not sure what the name of this kind of chart is.
Anyways, I'm trying to figure out how to get the enter() and exit() and updating to work for the chart when the data changes. I have this jsfiddle as an example
http://jsfiddle.net/Uhrgt/
The svg structure starts like this:
<svg class="chart" width="756" height="50">
<g transform="translate(0,0)" width="73.6">
<rect height="50" width="224" style="fill: rgb(0, 0, 255);"></rect>
<text x="113" y="25" dy=".35em">30%</text>
</g>
<g transform="translate(75,0)" width="451">
<rect height="50" width="451" style="fill: rgb(255, 0, 0);"></rect>
<text x="226" y="25" dy=".35em">60%</text>
</g>
<g transform="translate(529.2000122070312,0)" width="224.8">
<rect height="50" width="73" style="fill: rgb(128, 0, 128);"></rect>
<text x="37" y="25" dy=".35em">10%</text>
</g>
</svg>
And after the data changes, it looks like this:
<svg class="chart" width="756" height="50">
<g transform="translate(0,0)" width="73.6">
<rect height="50" width="224" style="fill: rgb(0, 0, 255);"></rect>
<text x="113" y="25" dy=".35em">30%</text>
<rect height="50" width="73" style="fill: rgb(0, 0, 255);"></rect>
<text x="37" y="25" dy=".35em">10%</text>
</g>
<g transform="translate(75,0)" width="451">
<rect height="50" width="451" style="fill: rgb(255, 0, 0);"></rect>
<text x="226" y="25" dy=".35em">60%</text>
<rect height="50" width="451" style="fill: rgb(255, 0, 0);"></rect>
<text x="226" y="25" dy=".35em">60%</text>
</g>
<g transform="translate(529,0)" width="224.8">
<rect height="50" width="73" style="fill: rgb(128, 0, 128);"></rect>
<text x="37" y="25" dy=".35em">10%</text>
<rect height="50" width="224" style="fill: rgb(128, 0, 128);"></rect>
<text x="113" y="25" dy=".35em">30%</text>
</g>
</svg>
The rects and texts are getting created again, and the old ones are not being removed. There are two problems here:
The rects are being duplicated for some reason. I'm not sure why the exit() isn't working for them.
The texts are being duplicated because I have text.exit().remove() commented out at the moment, but uncommenting it results in an error for some reason.
What the proper way to use the enter, update and exit functions for when you create a chart and then later update the data for them? I have been following many online examples and thought I was using the correct syntax but it's not working properly obviously.
The source of the issues you're seeing is that you have your text and rect elements grouped in g elements. You need to handle enter, update and exit selections only for the g elements. Everything else hangs off of that. This implies that you need to save the enter selection for the g elements and then append the other elements to that.
The structure would look like this:
var barEnter = bar.enter().append('g');
barEnter.append("rect");
barEnter.append("text");
For the update selection:
bar.transition()...
bar.select("rect").transition()...
bar.select("text").transition()...
For the exit selection, you just need to remove the g elements because that will also remove everything contained within them:
bar.exit().remove();
Complete demo here.

Fill complete image in svg container

I am new on stackoverflow.
I face a problem in svg code. I want to draw a container with a background image but when I set an image it breaks into 4 parts and gives a white space in mid of container.
This is my SVG code:
<svg id="do-as-cards" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" viewbox="0,0,320,340" preserveAspectRatio="xMidYMin">
<defs>
<pattern id="imgDo" preserveAspectRatio="true" patternUnits="userSpaceOnUse" y="0" x="0" width="240" height="120" >
<image xlink:href="http://s22.postimg.org/ekd89tb8x/image.png" x="0" y="0" width="407px" height="220px" />
</pattern>
<pattern id="imgAs" preserveAspectRatio="true" patternUnits="userSpaceOnUse" y="0" x="0" width="240" height="120" >
<image xlink:href="http://s22.postimg.org/72zfguwc1/image.png" x="0" y="0" width="407px" height="220px" />
</pattern>
</defs>
<g transform="translate(160,86)">
<g id="doCard" class="animatedCard" transform="matrix(1 0 0 1 0 0)" onclick="spin()">
<path class="cardOutline" d="m -150,-60 c 0,-10 10,-20 20,-20 l260,0 c 10,0 20,10 20,20 l 0,120 c 0,10 -10,20 -20,20 l -260,0 c -10,0 -20,-10 -20,-20 l 0,-120 z" />
<foreignObject id="do" class="cardFace" x="-120" y="-60" width="240" height="120"></foreignObject>
</g>
</g>
<g transform="translate(160,253)">
<g id="asCard" class="animatedCard" transform="matrix(1 0 0 1 0 0)" onclick="spin()">
<path class="cardOutline" id="as_path" d="m -150,-60 c 0,-10 10,-20 20,-20 l260,0 c 10,0 20,10 20,20 l 0,120 c 0,10 -10,20 -20,20 l -260,0 c -10,0 -20,-10 -20,-20 l 0,-120 z"/>
<foreignObject id="as" class="cardFace" x="-120" y="-60" width="240" height="120"></foreignObject>
</g>
</g>
</svg>
You can see this code in running stage by using this url
I have already tried the following:
How to set a SVG rect element's background image?
Fill SVG path element with a background-image
Using a <pattern> may not be the best way to do what you want. It can be done though.
If you are using a pattern, stick to the default patternUnits (objectBoundingBox), and set width and height to 1. Then set the width and height of your image to the max width or height of the region you are trying to fill. In the case of your example shapes, that appears to be 300. Then adjust the x and y of the <image> so it is centred in your shape.
<pattern id="imgDo" y="0" x="0" width="1" height="1" >
<image xlink:href="http://s22.postimg.org/ekd89tb8x/image.png" x="0" y="-75" width="300" height="300" />
</pattern>
Demo: http://jsfiddle.net/TRLa7/1/
Personally, I would use a <clipPath> for this situation. Use your path shape as the clipPath for the image. You will need to add an additional copy of the <path> to apply your stroke effects etc. You can define your card(s) in the <defs> section and then use a <use> to instantiate each card.
Demo: http://jsfiddle.net/TRLa7/2/

How to add image into center of svg circle?

I am trying to add an image into the center of a SVG circle.
I tried with patterns
<pattern id="image_birds" x="0" y="0" patternUnits="userSpaceOnUse" height="100" width="100">
<image x="0" y="0" xlink:href="birds.png" height="50" width="50"></image>
</pattern>
But it does not center the image. I am working with Javascript.
Clipping should do what you are looking for: https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Clipping_and_masking
Something like:
<clipPath id="cut-off-bottom">
<circle cx="100" cy="100" r="50" />
</clipPath>
<image x="25" y="25" xlink:href="http://placehold.it/150.png" height="150" width="150" clip-path="url(#cut-off-bottom)" ></image>
You can see the result of this example here: http://jsbin.com/EKUTUco/1/edit?html,output
Up to you to center the images in javascript according to their sizes, via x and y attributes.
Ok I found the answer. What I did is adding a filter to my svg:
<filter id = "i1" x = "0%" y = "0%" width = "100%" height = "100%">
<feImage xlink:href = "birds.png"/>
</filter>
and in the circle add attribute:
circle.setAttribute('filter','url(#i1)');

Categories