reusable parameters/ variables for svg graphic - svg

For a study project I'm asked to write an easy customizable svg graphic.
Is there any concept of variables?
The best I came up with so far is the following:
<g id="box">
<rect x="0" y="0" width="25" height="20" rx="3" ry="3" style="fill:transparent;stroke-width:1;stroke:rgb(0,0,0)">
</g>
<g id="month">
<!-- first row -->
<g transform="translate(50 40)">
<use xlink:href='#box'/>
<text x="5" y="15" fill="grey">Monday</text>
</g>
<g transform="translate(75 40)">
<use xlink:href='#box'/>
<text x="5" y="15" fill="grey">Tuesday</text>
</g>
<g transform="translate(100 40)">
<use xlink:href='#box'/>
<text x="5" y="15" fill="grey">Wednesday</text>
</g>
<g transform="translate(125 40)">
<use xlink:href='#box'/>
<text x="5" y="15" fill="grey">Thursday</text>
</g>
<g transform="translate(150 40)">
<use xlink:href='#box'/>
<text x="5" y="15" fill="grey">Friday</text>
</g>
<g transform="translate(175 40)">
<use xlink:href='#box'/>
<text x="5" y="15" fill="grey">Saturday</text>
</g>
<g transform="translate(200 40)">
<use xlink:href='#box'/>
<text x="5" y="15" fill="grey">Sunday</text>
</g>
....
</g>
Now the problem is, that if I change the the width of the box I need to adjust the translate parameter for each element in the month group.
Would be great to have something like this:
<param name="box-height" value="20" />
<param name="box-width" value="25" />
<g id="box">
<rect x="0" y="0" width="box-width" height="box-height" rx="3" ry="3" style="fill:transparent;stroke-width:1;stroke:rgb(0,0,0)">
</g>
<g id="month">
<!-- first row -->
<g transform="translate(2*box-width 40)">
<use xlink:href='#box'/>
<text x="5" y="15" fill="grey">Monday</text>
</g>
<g transform="translate(3*box-width 40)">
<use xlink:href='#box'/>
<text x="5" y="15" fill="grey">Tuesday</text>
</g>
...
</g>
But I didnt find anything so far. Does something like this exist, or any other helpful ideas.
Thank you.

The answer is no.
Parameters have been suggested in the past, and have even had draft specs written, but haven't made it to any implementation of SVG AFAIK.
However you can create and manipulate SVG elements with Javascript. You can use plain old JS, or one of the specialty libraries like d3 or Raphaels.

Related

Alter coordinates system by flipping X axis (start at top right corner)

I'm looking for a simple way to make the coordinate system in a given svg element start from the top right corner, instead of the top left. This means the X axis is flipped, thus increasing the x attribute of an element renders it further to the left, and increasing the y attribute renders it further to the bottom as usual.
I've played around with scale and viewBox, however:
scale almost solves the problem, but it doesn't really work for my use case because it also flips the text I've got rendered
viewBox doesn't seem work with height="100%" and width="100%". For my use case I don't think I can hard code the height and width of the SVG because I need it to be usable across many different resolutions and screen sizes.
This question says it solves the same problem for the Y axis with a matrix transformation. I looked around and tried to calculate the equivalent for the X axis, but with no success.
Here is an example of what I'm trying to achieve:
<svg style="border: 1px black solid;" height="100%" width="100%">
<g>
<g>
<rect fill="#F0BC40" width="70" height="12" x="0" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="35" y="29">7</text>
</g>
<g>
<rect fill="orange" width="50" height="12" x="72" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="97" y="29">5</text>
</g>
<g>
<rect fill="orange" width="40" height="12" x="124" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="144" y="29">4</text>
</g>
<g>
<rect fill="red" width="50" height="12" x="166" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="191" y="29">5</text>
</g>
<rect fill="#52575E" width="2" height="16" x="70" y="28"></rect>
<rect fill="#52575E" width="2" height="16" x="122" y="28"></rect>
<rect fill="#52575E" width="2" height="16" x="164" y="28"></rect>
</g>
</svg>
As you can see I'd like this stacked bar to be rendered from the right, with the red bar being the furthest to the left (so essentially the stacked bar would be flipped)
Also I'm doing this in Elm, so I can't access the DOM to check widths, heights or coordinates of elements (I'm calculating everything in a functional way).
If anyone could help me achieve this I'd be greatly thankful.
The way I would think about this is drawing your bars from x="0" to the left, and then setting the viewBox with a negative x value and a width that lets it end at x="0".
For the text elements, add a negative sign to the x value. For the rects, set the x value as x -> -x - width.
Define a viewBox such that the lowest x value is still inside, or whatever is appropriate.
<svg style="border: 1px black solid;" height="100%" width="100%" viewBox="-500 0 500 100">
<g>
<g>
<rect fill="#F0BC40" width="70" height="12" x="-70" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="-35" y="29">7</text>
</g>
<g>
<rect fill="orange" width="50" height="12" x="-122" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="-97" y="29">5</text>
</g>
<g>
<rect fill="orange" width="40" height="12" x="-164" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="-144" y="29">4</text>
</g>
<g>
<rect fill="red" width="50" height="12" x="-216" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="-191" y="29">5</text>
</g>
<rect fill="#52575E" width="2" height="16" x="-72" y="28"></rect>
<rect fill="#52575E" width="2" height="16" x="-124" y="28"></rect>
<rect fill="#52575E" width="2" height="16" x="-166" y="28"></rect>
</g>
</svg>
This will scale the text and the bars; if you need to avoid that, there is a trick. You can surround the content with two <svg> elements and use the inner one to move everything 100% to the right. overflow="visible" (or style="overflow:visible") makes sure the content is visible although it is formally outside the viewport of the inner <svg>.
<svg style="border: 1px black solid;" height="100%" width="100%">
<svg x="100%" overflow="visible">
<g>
<g>
<rect fill="#F0BC40" width="70" height="12" x="-70" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="-35" y="29">7</text>
</g>
<g>
<rect fill="orange" width="50" height="12" x="-122" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="-97" y="29">5</text>
</g>
<g>
<rect fill="orange" width="40" height="12" x="-164" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="-144" y="29">4</text>
</g>
<g>
<rect fill="red" width="50" height="12" x="-216" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="-191" y="29">5</text>
</g>
<rect fill="#52575E" width="2" height="16" x="-72" y="28"></rect>
<rect fill="#52575E" width="2" height="16" x="-124" y="28"></rect>
<rect fill="#52575E" width="2" height="16" x="-166" y="28"></rect>
</g>
</svg>
</svg>
As you said, scale "almost works". You can use scale again to unflip the text. Use nested transforms to get the flipping style working correctly with horizontal text placement. If you want to switch back to the unflipped version just change the -1 in the scale to a 1 (or get rid of the transform in the flipping style).
<head>
<style TYPE="text/css">
<!--
.flipped {
transform: scale(-1,1);
}
-->
</style>
</head>
<svg class=flipped style="border: 1px black solid;" height="100%" width="100%">
<g>
<g>
<rect fill="#F0BC40" width="70" height="12" x="0" y="30"></rect>
<g transform="translate(35,29)">
<g class=flipped >
<text fill="black" font-size="10px" text-anchor="middle" >7</text>
</g>
</g>
</g>
<g>
<rect fill="orange" width="50" height="12" x="72" y="30"></rect>
<g transform="translate(97,29)">
<g class=flipped >
<text fill="black" font-size="10px" text-anchor="middle" >5</text>
</g>
</g>
</g>
<g>
<rect fill="orange" width="40" height="12" x="124" y="30"></rect>
<g transform="translate(144,29)">
<g class=flipped >
<text fill="black" font-size="10px" text-anchor="middle" >4</text>
</g>
</g>
</g>
<g>
<rect fill="red" width="50" height="12" x="166" y="30"></rect>
<g transform="translate(191,29)">
<g class=flipped >
<text fill="black" font-size="10px" text-anchor="middle" >5</text>
</g>
</g>
</g>
<rect fill="#52575E" width="2" height="16" x="70" y="28"></rect>
<rect fill="#52575E" width="2" height="16" x="122" y="28"></rect>
<rect fill="#52575E" width="2" height="16" x="164" y="28"></rect>
</g>
</svg>

What is the data-value attribute in SVG?

I was looking at this article
And particularly this code,
<svg version="1.2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="graph" aria-labelledby="title" role="img">
<title id="title">A line chart showing some information</title>
<g class="grid x-grid" id="xGrid">
<line x1="90" x2="90" y1="5" y2="371"></line>
</g>
<g class="grid y-grid" id="yGrid">
<line x1="90" x2="705" y1="370" y2="370"></line>
</g>
<g class="labels x-labels">
<text x="100" y="400">2008</text>
<text x="246" y="400">2009</text>
<text x="392" y="400">2010</text>
<text x="538" y="400">2011</text>
<text x="684" y="400">2012</text>
<text x="400" y="440" class="label-title">Year</text>
</g>
<g class="labels y-labels">
<text x="80" y="15">15</text>
<text x="80" y="131">10</text>
<text x="80" y="248">5</text>
<text x="80" y="373">0</text>
<text x="50" y="200" class="label-title">Price</text>
</g>
<g class="data" data-setname="Our first data set">
<circle cx="90" cy="192" data-value="7.2" r="4"></circle>
<circle cx="240" cy="141" data-value="8.1" r="4"></circle>
<circle cx="388" cy="179" data-value="7.7" r="4"></circle>
<circle cx="531" cy="200" data-value="6.8" r="4"></circle>
<circle cx="677" cy="104" data-value="6.7" r="4"></circle>
</g>
</svg>
And I was wondering what data-value attribute was. When I tried googling for some documentation I only found this page, which said:
The data-* SVG attributes are called custom data attributes. They let SVG markup and its resulting DOM share information that standard attributes can't, usually for scripting purposes. Their custom data are available via the SVGElement interface of the element the attributes belong to, with the SVGElement.dataset property.
And since I'm new at SVG, I wasn't sure what this meant. If someone could elucidate me on what data-value is that would be great!

why the text path are not rendered?

I really got puzzled why these two text are not displayed along the line and path. Could someone point me out?
<svg width="300px" height="300px">
<line id="ok" x1="10" y1="20" x2="100" y2="100" stroke="red" stroke-width=10>
<text>
<textPath stroke="black" xlink:href="#ok">OHHHHSUHDIAU</textPath>
</text>
</line>
<path id="io" d="M10,10 L100,10" stroke="blue" stroke-width=10>
<text>
<textPath stroke="black" xlink:href="#io">io</textPath>
</text>
</path>
</svg>
you can only do a <textPath> on a <path>
placing the <text> inside the <line> or <path> elements were causing them not to be rendered.
here is my best guess at what you're trying to accomplish, I hope this helps
<svg width="300px" height="300px">
<defs>
<path id="io" d="M10,10 L100,10" />
<path id="ok" d="M10,20 L100,100" />
</defs>
<use xlink:href="#io" stroke-width="10" stroke="blue" />
<use xlink:href="#ok" stroke-width="10" stroke="red" />
<text>
<textPath stroke="black" xlink:href="#io">io</textPath>
<textPath stroke="black" xlink:href="#ok">OHHHHSUHDIAU</textPath>
</text>
</svg>

Cut off half of the SVG's text element

How can I make this
to look like this
So I want to halve the text element. I don't want to hide half of the text outside of SVG. Hiding it outside of g would be ok, but haven't found solution.
<svg width="500" height="500">
<g transform="translate(50,50)">
<rect width="80" height="50" style="fill:rgb(0,0,255);"/>
<text font-size="40" x="0" y="15" fill="black">SVG</text>
</g>
</svg>
JSFIDDLE:
http://jsfiddle.net/64nkLcdy/
Use the clip-path property :
<svg width="500" height="500">
<defs>
<clipPath id="myClip">
<rect width="80" height="50" />
</clipPath>
</defs>
<g transform="translate(50,50)">
<rect width="80" height="50" style="fill:rgb(0,0,255);" />
<text font-size="40" x="0" y="15" fill="black" clip-path="url(#myClip)">SVG</text>
</g>
</svg>
Use an <svg> element rather than a <g> as the svg element will clip its contents by default. The overflow property controls clipping i.e overflow="visible" doesn't clip but overflow="hidden" does.
<svg width="500" height="500">
<svg transform="translate(50,50)" width="80" height="50" overflow="hidden">
<rect width="80" height="50" style="fill:rgb(0,0,255);"/>
<text font-size="40" x="0" y="15" fill="black">SVG</text>
</svg>
</svg>

SVG Text and Rect position

I have this code:
<g pointer-events="default">
<g>
<g x="0" y="0" width="145" height="47" regroup="false">
<text x="0" y="0">
<tspan x="0" y="0">some text</tspan>
</text>
</g>
<g x="0" y="0" width="80" height="60" regroup="false">
<rect x="0" y="0" width="80" height="60" fill="white" />
</g>
</g>
</g>
There is one css rule box-sizing: border-box;which is apply to all elements.
It produce that:
The grid is coming from a sliding element from the first <g>.
I don't understand why the text element and the rect are not displayed at the same y.
Does anyone have any idea?

Resources