I need my SVG in a webpage to dynamically resize based on window size, or to have multiple hardcoded widths and heights.
I am using the D3 library.
My problem is that it isn't just the SVG tag that needs a different canvas size, it is the children elements such as a rect tag and g tag that also need to resize or be completely re-rendered
How would this be done?
I realize I could listen to window resizing with
d3.select(window).on('resize', resize);
with my resize function doing all the logic, but exactly how and what width/heights to choose (or calculate) is beyond me
<div class="svg-container">
<svg width="960" height="500" preserveAspectRatio="xMidYMid" class="svg-content">
<defs>
<clipPath id="clip-upper">
<rect id="rect-clip-upper" width="960" height="305" x="-480" y="-305"> </rect>
</clipPath>
<clipPath id="clip-lower">
<rect id="rect-clip-lower" width="960" height="195" x="-480" y="0"></rect>
</clipPath>
</defs>
<g clip-path="url(#clip-upper)" transform="translate(480,305)"></g>
<g clip-path="url(#clip-lower)" transform="translate(480,305)"></g>
</svg>
If you add a viewBox to the svg element e.g. viewBox="0 0 960 500" you won't need to resize any children.
Instead of hardcoding a width, make it dependent upon the width of the parent of the svg. E.g.
width = svgParent[0][0].clientWidth - margin.left - margin.right;
height = svgParent[0][0].clientHeight - margin.top - margin.bottom;
Make sure that all your widths, heights, and positions are either calculated from data (in which case d3 will handle it) or relate to width/height in some way. Then, in your resize handler, just call child.attr("width", newWidth), child.attr("x", newX), etc. on all elements you want to resize.
If you're using axes, set the range to your new width value and call the axis function again (i.e. svg.select(".x.axis").call(xAxis)). If you are using zoom or other similar features, you'll have to call them again.
Hi SVG it self suggest "Salable vector graphics" so it is responsive by nature so for that you just need to use "viewBox" attribute of <svg> element. with your perspective use.
Related
Say we have a single image tag, and we need to blur a specific part of it (for example, for censorship purposes). In the example, we'll say our target image is 100px by 100px, and we want to censor the rectangle at x=25, y=40 with width=20, height=35. How can this be done using CSS?
This is straightforward if you have a parent container, as you can simply render an offset portion of the same image, with a clip or a backdrop-filter applied. However, this is not reliable for my use case, as I cannot guarantee the positioning attributes of the parent and the image itself, so I may not be positioning the element correctly.
<div id="parent">
<img src="/path/to/img.png">
<!-- This -->
<img
id="blurred"
src="/path/to/img.png"
style="clip: rect(25, 40, 20, 35); filter: blur(8px);"
/>
<!-- Or this -->
<div style="left: 25px; top: 40px; width: 20px; height: 35px; backdrop-filter: blur(8px);" />
</div>
On the other hand, if you just have the image, with no access to the parent, CSS might be the only way. There is clip-path and mask.
With clip-path, you're removing everything outside the path, but we want to do the opposite by blurring everything inside the path. You can finesse the path clip the target "portion" while leaving the remainder of the image, but this doesn't seem to support the filter, you're left with an empty white block where you want your blur to be (I haven't had much luck figuring out how to apply the blur here). While this achieves the censorship purpose, it doesn't achieve the UX desired with a blur.
<!-- Reference SVG clip path -->
<svg height="100%" width="100%" viewBox="0 0 100 100">
<defs>
<clipPath id="clip">
<path d="M 0,0 l 100,0 0,100 -100,0 Z M 25,40 l 20,0 0,35 -20,0 Z" />
</clipPath>
</defs>
</svg>
<!-- Clipped image -->
<img src="/path/to/img.png" style="clip-path: url(#clip);" />
A mask has a similar constraint, as we are drawing the image through the mask, which means that we can create a mask of the filtered and blurred parts of the image, and "draw those through the mask" onto the target image. However, this more or less defeats the purpose, as we need to re-render the image in the SVG tag separately, and is brittle if the user resizes the page / image, for example.
Appreciate any suggestions. This has had me stumped for a few days now.
I created a radial with two tiers of options. I did in a way that isn't really dynamic and isn't really responsive to screen size. I now need it to be both of those things. Here is what it looks like when on the screen size I designed it for.
I created a working demo on sandbox that has the dimensions set how I need to use it on. This is what it looks like.
Here is link WORKING DEMO
any help is appreciated. Also keep in mind the outer tiers can have less or more options. it would be great if the blue toggle button would always align at the bottom of the radial like under the En of Energy Loss
I would consider using an SVG ViewBox in order to maintain consistency. What this basically does is create a consistent scalable SVG, mapping the size and coordinates of its container into a consistent range inside the SVG.
For example:
<div height="400px" width="400px">
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="100%" height="100%" stroke="red" fill-opacity="0"/>
<circle r="4" cx="10" cy="10"/>
</svg>
</div>
So it basicalley creates a mapping from the 400x400 dimensions of the div, into the 100x100 of the svg, so the circle positioned at (10, 10) inside the svg will actually be in coordinates (40, 40) of the div
I've a lot of SVG files (several graphics like, dogs, trees, birds, buildings etc.), and they are from different sources from web. I need to define height and width of these SVGs.
Example File:
<svg id="svg1" viewBox="0 0 36 33" xmlns="http://www.w3.org/2000/svg">
<path d="m18 0.0938-17.719 16.281h5.5625v15.531h24.312v-15.531h5.5625l-17.719-16.281z"/>
</svg>
I get the width and height of this:
var svg1 = document.getElementById('svg1');
console.log('client', svg1.clientWidth + 'x' + svg1.clientHeight);
And then modified the file with the results:
<svg width="630" height="577" viewBox="0 0 36 33" xmlns="http://www.w3.org/2000/svg">
<path d="m18 0.0938-17.719 16.281h5.5625v15.531h24.312v-15.531h5.5625l-17.719-16.281z"/>
</svg>
I am experienced in javascript and c#, but I don't know a way to achieve this.
P.S: The reason I need this: My wordpress custom product designer plugin uses SVG files to design custom products, but those SVG files must have width and height for my plugin to work properly.
if you are using SVG from material-ui, wrap it inside an IconButton (and define the height and width here). The svg takes the dimensions of the parent.
I have the following SVG of a phone:
<svg width="897px" height="452px" viewBox="0 0 897 452" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<g id="iphone" sketch:type="MSLayerGroup" stroke="#7E89A3" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M130,257.964 C130,266.797 122.809,273.956 113.938,273.956 L16.063,273.956 C7.192,273.956 0.001,266.797 0.001,257.964 L0.001,16.073 C0.001,7.24 7.192,0.081 16.063,0.081 L113.938,0.081 C122.809,0.081 130,7.24 130,16.073 L130,257.964 L130,257.964 Z"
id="bezel" stroke-width="2" fill="white" sketch:type="MSShapeGroup"></path>
<rect id="screen" fill="#ddd"
sketch:type="MSShapeGroup" x="9" y="36" width="111.93" height="199.084"></rect>
<path d="M77,25.746 C77,26.381 76.561,26.893 76.02,26.893 L55.918,26.893 C55.376,26.893 54.938,26.38 54.938,25.746 L54.938,23.166 C54.938,22.531 55.377,22.019 55.918,22.019 L76.02,22.019 C76.561,22.019 77,22.532 77,23.166 L77,25.746 L77,25.746 Z" id="speaker"
sketch:type="MSShapeGroup"></path>
<circle id="camera" sketch:type="MSShapeGroup" cx="66" cy="12" r="3"></circle>
<ellipse id="lock" sketch:type="MSShapeGroup" cx="65.04" cy="254.001" rx="10.04" ry="10.001"></ellipse>
</g>
</svg>
Which looks like following:
I will be using AngularJS to dynamically generate <ul> with elements on the phone screen, where generated elements will be interactive (users will be able to e.g. click on them).
The challenge however is, how to lock the size of my div element (which will hold the ul element), so that it always has the size of the screen? I want this phone to be center aligned on my page, but as far as I know, the SVG size will adapt to the actual window size.
Is there a way how to dynamically poisition my div element to be only on the phone's screen?
P.S. I can see that my SVG contains element with id screen so maybe somehow detect the position of this element?
I would recommend placing an absolutely positioned div over the SVG element. You can calculate the dimensions of the screen image by using the getBoundingClientRect() method. The code is simple:
var ui = document.getElementById("ui");
var screen = document.getElementById("screen");
var dimensions = screen.getBoundingClientRect();
ui.style.left = dimensions.left + "px";
ui.style.top = dimensions.top + "px";
ui.style.width = dimensions.width + "px";
ui.style.height = dimensions.height + "px";
You can see a working example here: https://jsfiddle.net/hxe9nb3n/
For a start it doesn't have to adapt to the size of the window. That behaviour is under your control.
Alternatively, you can embed HTML inside an SVG using the <foreignObject> element. That way the embedded HTML will adapt to whatever size the SVG becomes. There are many examples of how to do that in SO.
Hi i am facing a problem i have a svg.When i try to change the height and width and viewbox's height and width the drawing inside the svg will not get fit in to the box
This is my mysvg i am giving the short form
<?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 width="500pt" height="500pt" viewBox="0 0 500 500" version="1.1" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(528,270)" >
<g id="states" fill="green" width="500pt" height="500pt" >
<a id="s01">
<path d="M158.95067408594068,46.88327098850149L185.03303599629845,44.0148159910488L189.74121811302572,59.50889743727097L196.59587401503094,82.27898337817625L199.0518321008348,87.17077847298319L201.13017099189912,89.85649424407167L200.707578706067,91.7588142001174L202.6261541288344,92.6205139503571L200.33524838576966,95.29216920133321L200.7363444144292,97.59217497211156L199.80999341478454,100.8918397716738L202.09021078470892,106.20782432993735L201.64399529140977,111.17790897235179L204.03767592952832,115.96122130827978L196.3574723373462,117.09985438789514L163.47293491613115,121.08122011183377L163.22294648718562,123.55296427740802L167.13791879442175,126.6835133291724L166.871741037497,129.76735843938286L168.2485001228969,131.1400084527912L166.21795234496457,134.1137855808483L164.12121282499038,134.9547500732084L159.81791064191435,132.36796011584426L158.90469329765804,127.88713803963412L157.64560372254968,127.51168600895127L156.5390262005875,131.08669596034315L156.36678872306632,134.46030822963786L152.20800610122825,133.97284127048096L148.16895577705603,105.98121856614907L148.12136132417422,70.56398790998259L148.15893441899317,50.102043132249676L146.40831263672231,48.33943105796875Z" stroke="#FFFFFF" stroke-dasharray="1, 0" stroke-width="1.5"></path>
<text x="162.66165594858754" y="86.92631614090374" style="">AL</text>
<title></title>
</a>
</g>
</g>
</svg>
this is what happen when i change the width and height or viewbox or both
\
now width height get reduced but drawing remains the same
Assume the initial height and width 1000px.
<svg height="1000" width="1000" viewBox="0 0 1000 1000">
If you want to resize svg and all elements in it, then don't change viewBox value. For 500px SVG:
<svg height="500" width="500" viewBox="0 0 1000 1000">
Example
How to Zoom and Pan with SVG
The solution is the same as the answer I gave you yesterday.
Width height of the svg is not changing
Try following these steps:
(1) Set svg width and height to 500, and add preserveAspectRatio="none" to your svg.
<svg width="500" height="500" preserveAspectRatio="none" ...>
This will probably stretch your map strangely, but don't worry, it is just a temporary change that makes the next step easier.
(2) Now adjust the viewBox until all the map is visible. Once you find the right values, leave the viewBox alone. You shouldn't need to change it further.
(3) Remove the preserveAspectRatio="none". The stretch effect will disappear.
(4) Now you can adjust the svg width and height from 500x500 to whatever size you like. The entire map should stay visible no matter how you change the width and height.