I'm creating a small stacked bar graph, with 3 bar items (rendered with a coloured <rect> item). This is all done in a React component (I build these up depending on some of the inputs I get). The render function for the component looks something like this:
<React.Fragment>
<g key={this.props.id}>
<rect
width={`${
this.props.value === 0 ? 2 : this.calculatePercentage(this.props.value)
}%`}
height={`15px`}
x={`${this.getPosition()}%`}
style={{ fill: this.props.color }}
className={Styles.bar}
/>
<text
y={25}
x={`${this.getPosition()}%`}
transform={`translate(${this.getTextPosition()}, 0)`}
>
<a
onClick={this.onClick}
className={
this.props.value === 0
? Styles.noResults
: this.props.isSelected
? Styles.selectedText
: Styles.filterText
}
>
{this.props.label}
</a>
</text>
</g>
<text
id={"percentage"}
className={Styles.barText}
x={`${this.getPosition() + 1}%`}
y={11}
transform={`translate(${0}, 0)`}
>
{this.calculatePercentage(this.props.value)}%
</text>
<use xlinkHref="#percentage" />
</React.Fragment>
Ultimately, for a result-set I have, the output from this component looks like this:
.container {
display: flex;
flex-direction: column;
}
.bar {
overflow: visible;
}
.barText {
fill: #000;
color: #000;
font-size: 10px;
overflow: visible;
}
.noResults {
fill: #bcbcbc;
font-size: 10px;
}
.noResults:hover {
cursor: default;
}
.selectedText {
fill: #0078d7;
font-size: 10px;
text-decoration: underline !important;
text-decoration-color: #0078d7;
text-decoration-thickness: 1px;
font-weight: bold;
}
.filterText {
fill: #0078d7;
font-size: 10px;
text-decoration: none;
}
.filterText:hover {
cursor: pointer;
text-decoration: underline !important;
text-decoration-color: #0078d7;
text-decoration-thickness: 1px;
}
<svg xmlns="http://www.w3.org/2000/svg" class="container">
<g>
<rect class="bar" style="fill: #2a7c4f;" x="0%" width="2%" height="15px" />
<text transform="translate(0)" x="0%" y="25"><a class="noResults">Complete: 0</a></text>
</g>
<text id="percentage" class="barText" transform="translate(0)" x="1%" y="11">0%</text>
<g>
<rect class="bar" style="fill: #fec42e;" x="2%" width="2%" height="15px" />
<text transform="translate(53.91)" x="2%" y="25"><a class="noResults">Draft: 0</a></text>
</g>
<text id="percentage" class="barText" transform="translate(0)" x="7%" y="11">48%</text>
<g>
<rect class="bar" style="fill: #D3D3D3;" x="4%" width="100%" height="15px" />
<text transform="translate(253.91)" x="2%" y="25"><a class="noResults">Empty: 0</a></text>
</g>
<text id="percentage" class="barText" transform="translate(0)" x="91%" y="11">50%</text>
<use xlink:href="#percentage"/>
</svg>
Now as you can see, the second 0% isn't visible, what I want is for all the % value fields to be visible on top of the bar itself. Is there any way to go about this? It obviously works if the particular section of the bar has a larger width, but I want it to work regardless of the width of the rect.
I tried copying my SVG into my HTML and defining it as a clipPath, but it doesn't display the shape the right way. Can I define clipPath using a file path?
<div class="gradient">
</div>
<svg height="0" width="0">
<defs>
<clipPath id="Camera">
<style>
.cls-1, .cls-2 {
fill: #363636;
}
.cls-1, .cls-3 {
stroke: #363636;
}
.cls-1 {
stroke-width: 1px;
fill-rule: evenodd;
}
.cls-3 {
fill: none;
stroke-width: 50px;
}
</style>
<path class="cls-1" d="M566.282,395.982s-121.771,16.243-155.258,35.532-93.7,51.606-135.978,123.854c-1.285-10.084-1.014-8.122-1.014-8.122v-33.5a319.278,319.278,0,0,1,20.3-80.2c15.223-37.882,41.848-78.09,77.121-99.489,55.447,0,87.691,5.262,142.067,27.411C565.1,395.035,566.282,395.982,566.282,395.982Zm-136.671,44.24S382.787,553.845,382.741,592.5s-2.176,106.981,39.225,179.738c-9.372-3.929-7.538-3.182-7.538-3.182l-29-16.751a319.037,319.037,0,0,1-59.278-57.684c-25.181-32.13-46.675-75.3-47.563-116.562,27.724-48.04,48.4-73.345,94.761-109.381C428.2,440.773,429.611,440.222,429.611,440.222Zm-34.372,138.5s74.972,97.311,108.424,116.665,91.55,55.336,175.261,55.844c-8.09,6.151-6.526,4.936-6.526,4.936l-29.01,16.739a319.273,319.273,0,0,1-79.6,22.5c-40.418,5.748-88.553,2.786-124.725-17.061-27.733-48-39.3-78.549-47.321-136.692C395.011,580.218,395.239,578.721,395.239,578.721ZM501.768,677.28s121.722-16.3,155.2-35.605,93.676-51.652,135.971-123.924c1.28,10.084,1.011,8.121,1.011,8.121l-0.015,33.5a319.666,319.666,0,0,1-20.323,80.215c-15.233,37.892-41.864,78.115-77.131,99.532-55.422.025-87.649-5.222-141.989-27.348C502.95,678.227,501.768,677.28,501.768,677.28Zm138.679-42.488s46.752-113.61,46.78-152.27,2.126-106.987-39.29-179.768c9.37,3.933,7.536,3.185,7.536,3.185l29,16.765a319.457,319.457,0,0,1,59.277,57.715c25.185,32.144,46.688,75.329,47.594,116.593C763.65,545.042,743,570.339,696.672,606.357,641.857,634.242,640.447,634.792,640.447,634.792ZM672.715,493.3s-74.971-97.311-108.423-116.665S472.741,321.3,389.031,320.789c8.089-6.151,6.525-4.936,6.525-4.936l29.01-16.739a319.289,319.289,0,0,1,79.6-22.5c40.418-5.748,88.552-2.786,124.725,17.061,27.733,48.005,39.3,78.549,47.321,136.692C672.943,491.8,672.715,493.3,672.715,493.3Z"/>
<circle class="cls-2" cx="176" cy="176" r="60"/>
<rect id="Camera_Body" data-name="Camera Body" class="cls-3" x="38" y="38" width="1001" height="1001" rx="100" ry="100"/>
</clipPath>
Will display this
https://codepen.io/TVsVeryOwn/pen/yjwaoy
I'm trying to get something resembling this (I know my gradient is backwards):
< clipPath > only uses the fill of the shapes.
If you remove < rect id="Camera_Body" > part from your SVG code - you’ll see it’s working as you wanted without this rect element. The rect doesn’t have a fill - only a stroke - and the clipping doesn’t work on stroke.
This may help.
I am currently drawing a svg circle from a database and it's label (text). I want the stroke width of the circle to increase on hover of the circle as well as it's text at the same time, meaning if the circle is hovered on and it's stroke width increases the size of the text should increase as well. Would I need to create a subclass in css, I am new at this..............................................
<circle class="circles"cx=',row[1],' cy=',row[2],' r="0.2"></circle>
<text class="text" x=',row[1],'y=',row[2],' transform="translate(0',move,')scale(-1,1) rotate(180)">',row[0],'</text>')
.text {
font-size: 0.8px;
font-family: Verdana;
fill: peachpuff;
}
.text:hover {
font-size: 2px;
}
.circles{
fill: cyan;
}
.circles:hover{
stroke: cyan;
stroke-width: 0.4;
}
Here's a demonstration:
Wrap your circle and text in a single SVG container or seperate classes as per the requirement.
Use the stroke-width attribute of circle and font-size for the text, and change their values accordingly on hover of the container.
.circleS:hover circle{
stroke-width:5;
}
.circleS:hover text{
font-size:18px;
}
<svg height="100" width="100" class="circleS">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
<text x="25" y="50" fill="white">Random</text>
</svg>
I have a following html:
<div id="divVis2" class="divVis">
<svg width="1540" height="345">
<defs>
<marker id="normal" viewBox="0 -5 10 10" refX="15" refY="-1.5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M0,-5L10,0L0,5"></path>
</marker>
<marker id="anomaly" viewBox="0 -5 10 10" refX="15" refY="-1.5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M0,-5L10,0L0,5"></path>
</marker>
</defs>
<g>
<path class="anomaly" marker-end="url(#anomaly)" d="M908.3739002256449,176.0182689704716L661.9527686239043,249.64760217208658"></path>
<path class="normal" marker-end="url(#normal)" d="M660.4045373167714,246.37428873149702L879.5700343222044,98.59473202412175"></path>
<path class="normal" marker-end="url(#normal)" d="M878.0019325543491,95.25420149730667L631.216835426003,167.4248240636326"></path>
</g>
<g>
<g transform="translate(889.5195255254339,91.88595979689137)">
<circle class="normal" r="12"></circle>
<text x="0" y="4" class="normal">133</text>
</g>
<g transform="translate(619.6992424549181,170.7930657640479)">
<circle class="normal" r="12"></circle>
<text x="0" y="4" class="normal">134</text>
</g>
<g transform="translate(650.4550461135419,253.0830609587274)">
<circle class="anomaly" r="12"></circle>
<text x="0" y="4" class="normal">137</text>
</g>
<g transform="translate(919.8716227360072,172.5828101838308)">
<circle class="normal" r="12"></circle>
<text x="0" y="4" class="normal">136_1</text>
</g>
</g>
</svg>
</div>
Its corresponding css is:
#divVis2 path {
fill: none;
/* stroke: #666; */
stroke-width: 0.5px;
}
#divVis2 path.normal {
stroke: #808080;
}
#divVis2 path.anomaly {
stroke: red;
stroke-width: 1.5px;
}
/* for the marker */
#divVis2 #normal {
fill: black;
stroke-width: 0.5px;
}
#divVis2 #anomaly {
fill: red;
stroke-width: 1.5px;
}
#divVis2 circle.normal {
fill: #ccc;
stroke: #ffffff;
stroke-width: 0.5px;
}
#divVis2 circle.anomaly {
fill: #ff0000;
stroke: #ffffff;
stroke-width: 0.5px;
}
#divVis2 text.normal {
font: 7px sans-serif;
pointer-events: none;
fill: black;
text-anchor:middle;
}
#divVis2 text.label {
font: 9px sans-serif;
pointer-events: none;
fill: blue;
text-anchor:middle;
}
The corresponding output in browser is:
Why are the arrows not getting displayed at the end of each path? I am unable to find out the problem in css selectors.
Here is a jsfiddle: http://jsfiddle.net/onh7t53o/
#divVis2 path {
fill: none;
/* stroke: #666; */
stroke-width: 0.5px;
}
has a higher specificity for the markers than
#divVis2 #normal {
fill: black;
stroke-width: 0.5px;
}
so the marker paths are fill="none" and the stroke-width is so thin because the markers are small that you can't see it.
I had this problem in an angular app that was using a <base> tag. In the context of a rich web app like one built on Angular, where you need to set the <base> tag to make HTML5-style navigation work, it can get messy to try to fix that in a permanent way.
In my case, the app I was working on was showing a SVG-based interactive diagram builder that would change the app url as I selected elements therein.
What I did was to add a global event handler that would fix all url(#...) inline styles in any <path> element found in the page:
$rootScope.$on 'fixSVGReference', ->
$('path').each ->
$path = $ this
if (style = $path.attr 'style')?
$path.attr 'style', style.replace /url\([^)#]*#/g, "url(#{location.href}\#"
Then trigger this handler in key places, like when the app state changes (I'm using ui-router)
$rootScope.$on '$stateChangeSuccess', ->
$timeout (-> $rootScope.$emit 'fixSVGReference'), 5
As well as anywhere where I know there'd be new/updated paths like these. Here, the $timeout thing is to account for the fact that the DOM nodes really are changed asynchronously sometime after the $stateChangeSuccess event is triggered.
I have 2 SVG paths and I would like them to change fill color when users rollover their parents did. I can get the hover working but only when users hover on the svg. I know it is easy with JS but I would prefer to stick with CSS.
<div class="button">
<svg width="100px" height="100px">
<circle cx="30" cy="30" r="20" style="stroke: black;"/>
</svg>
</div>
<div class="button">
<svg width="100px" height="100px">
<circle cx="30" cy="30" r="20" style="stroke: black;"/>
</svg>
</div>
CSS:
.button{
background-color:gray;
margin-bottom: 20px ;
}
svg{
fill:green;
}
svg:hover{
fill:blue;
}
Demo: http://jsfiddle.net/69g7K/
We can do this, by using parent:hover as selector to vary the CSS attributes of child1 and child2 which are within their respective parents..
Use the following for the CSS :
.button:hover .svg1{
fill:blue;
}
.button:hover .svg2{
fill:yellow;
}
Demo : jsFiddle
here is a trick if you have a more complex svg element, for instance if you have multiple paths, do the following:
<div class="your-class">
<svg [svg content...]
<path ...>
<path ...>
<path ...>
</div>
use css to look for paths not only something inside a specific path:
.your-class{
/* code without rover */
transition: 0.3s ease-in-out;
}
.your-class:hover path{
stroke: #C4C4C4; /* use stroke to color svg lines*/
/* use fill to color the inside */
also (maybe worth mentioning) if you your div to be only around the svg you can use the width: fit-content; for your div
hope it helps you out
svg {
fill: #444;
}
just add a class to each SVG and use the css above something like this:
svg.svg1:hover {
fill: #666;
}
svg.svg2:hover {
fill: #666;
}
remove style="fill: yellow" for example from each SVG path otherweise it will overwrite your css
<svg class=svg1 width=150px height=150px>
<circle cx=64 cy=64 r=20>
</svg>
<svg class=svg2 width=150px height=150px>
<circle cx=64 cy=64 r=20>
</svg>
Demo:http://jsfiddle.net/GwWk5/
svg {
fill: red;
}
svg.svg1:hover {
fill: blue;
}
svg.svg2:hover {
fill: green;
}