lock element to the SVG element - javascript

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.

Related

SVG - make viewBox(0, 0, 100%, 100%) with percentages

How can I make SVG viewBox user coordinate system the same as the viewport coordinates system provided by SVG itself (height="100%" and width="100%")?
I need this special case for a project I'm doing, SVG element should be responsive, but still we need to keep height and width 100% on the SVG itself.
So, I need something like this:
<svg height="100%" width="100%" viewBox="0, 0, 100%, 100%">
<circle cx="25" cy="25" r="20" stroke="black" strokeWidth="1" fill="black" />
</svg>
.. but the viewBox attribute doesn't accept percentages.
%/px is not allowed in the viewBox, those are the maximum coordinates.
By default the SVG content is contained to the SVG size.
If you want the content to stretch to 100%, disable the aspect ratio using preserveAspectRatio="none".
You can also use preserveAspectRatio="slice" to make the content cover the SVG (like background-size: cover).
<svg height="100%" width="100%" viewBox="0 0 100 100" preserveAspectRatio="none">
There are some good articles about this: https://css-tricks.com/scale-svg/ and https://alligator.io/svg/preserve-aspect-ratio/

Scaling an SVG with complex animation paths

I have this code for an SVG on my page. It's a track and I have a car that scrolls along the path as you go down the page.
<div class="my-svg-container">
<svg viewBox="-220 -219 1250 2212.5" style="
position: absolute;
" class="my-svg" preserveAspectRatio="xMinYMin meet"><defs>
<style>.cls-1,.cls-10,.cls-11,.cls-12,.cls-13,.cls-14,.cls-15,.cls-16,.cls-17,.cls-3,.cls-4,.cls-5,.cls-6,.cls-7,.cls-8,.cls-9{fill:none;}.cls-2{clip-path:url(#clip-path);}.cls-3{stroke:#2d2d2d;stroke-width:100px;}.cls-10,.cls-11,.cls-12,.cls-13,.cls-14,.cls-15,.cls-16,.cls-17,.cls-4,.cls-5,.cls-6,.cls-7,.cls-8,.cls-9{stroke:#fad000;stroke-width:9px;}.cls-4{stroke-dasharray:12 11.54;}.cls-5{stroke-dasharray:12 10.64;}.cls-6{stroke-dasharray:12 12.26;}.cls-7{stroke-dasharray:12 13.27;}.cls-8{stroke-dasharray:12 12.67;}.cls-9{stroke-dasharray:12 10.99;}.cls-10{stroke-dasharray:12 12.24;}.cls-11{stroke-dasharray:12 13.42;}.cls-12{stroke-dasharray:12 12.63;}.cls-13{stroke-dasharray:12 10.47;}.cls-14{stroke-dasharray:12 11.73;}.cls-15{stroke-dasharray:12 11.95;}.cls-16{stroke-dasharray:12 12.17;}</style>
<clipPath id="clip-path" transform="translate(4349 2519.5)"><rect class="cls-1" x="-4349" y="-2519.5" width="868.18" height="1964.5"></rect></clipPath></defs><title>Road(whole)</title>
<g class="cls-2">
<path id="theMotionPath" class="cls-3" d="M709.08 0.54v306s7,91-106,91h-461s-92-8-92,96v444s-6,78,64,78h606s98-10,98,90v394s5,84-84,84h-522s-90-3-90,90v290" ></path>
<line class="cls-4" x1="709.08" y1="17.54" x2="709.08" y2="294.23"></line>
<path class="cls-5" d="M-3640.93-2196.91c-3.89,25-21,69.87-93.68,74.09" transform="translate(4349 2519.5)"></path>
<line class="cls-6" x1="584.81" y1="397" x2="154.21" y2="397"></line>
<path class="cls-7" d="M-4226.14-2121.52c-25.35,3.77-67.35,19.56-72.3,82.4" transform="translate(4349 2519.5)"></path>
<line class="cls-8" x1="50.08" y1="511.67" x2="50.08" y2="924.67"></line>
<path class="cls-9" d="M-4298.32-1565.54c2.45,21,12.58,54.8,51.94,60.28" transform="translate(4349 2519.5)"></path>
<line class="cls-10" x1="132.32" y1="1015" x2="707.96" y2="1015"></line>
<path class="cls-11" d="M-3609.53-1504.15c26.79,2.72,72.47,16.34,78,77" transform="translate(4349 2519.5)"></path>
<line class="cls-12" x1="818.08" y1="1123.63" x2="818.08" y2="1486.69"></line>
<path class="cls-13" d="M-3532-1004.08c-3.44,22.94-17.31,62.35-71.73,67.11" transform="translate(4349 2519.5)"></path>
<line class="cls-14" x1="716.35" y1="1583" x2="223.99" y2="1583"></line>
<path class="cls-15" d="M-4154.73-934.92c-24.59,4.26-66.45,19.86-71.61,76.46" transform="translate(4349 2519.5)"></path>
<line class="cls-16" x1="122.13" y1="1691.17" x2="122.13" y2="1950.92"></line>
<path class="cls-17" d="M-4226.87-562.5
v6m.13-296
q-.14,2.93-.13,6
v6
m96-96
h-6
s-2.23-.07-6,.16
m533.95-.29q-2.92.14-6,.13
h-6
m90-90
v6
s.13,2.24,0,6
m-.09-406
c.08,2,.12,4,.12,6
v6
m-104-96
h6
s2.22-.23,6-.27
m-618,.07
c1.94.13,3.93.2,6,.2h6m-70-84v6s-.18,2.26-.12,6m.22-456
q-.11,2.94-.1,6v6m98-102h-6s-2.23-.19-6-.13m473,0q-2.94.09-6,.09
h-6m112-97v6a57.48,57.48,0,0,1,0,6m0-312v6" transform="translate(4349 2519.5)"></path></g>
<g class="shakyimage">
<image speed="2" width="5%" height="5%" x="-65" y="-30" xlink:href="https://cdn3.iconfinder.com/data/icons/cars-28/512/Car_5-512.png" id="dot" ></image>
</g>
<g >
<image width="45%" height="11%" x="423" y="-100" xlink:href="https://cdn0.iconfinder.com/data/icons/gpsmapicons/red/gpsmapicons07.png">
</g>
<g >
<image width="30%" height="10%" x="-66" y="1782.17" xlink:href="https://cdn0.iconfinder.com/data/icons/gpsmapicons/red/gpsmapicons07.png">
</g>
</svg>
</div>
This functions very well as-is. My main issue is I have built the page to align with the track. This means that the end of the track perfectly aligns with the last section of the page. The problem is, when you make the page smaller the track shrinks in size.
Currently I have tried doing this:
.my-svg-container{
display: inline-block;
position: relative;
width: 100%;
padding-bottom: 38.5%; /* depends on svg ratio, for my zebra height/width = 1.2 so padding-bottom = 50% * 1.2 = 60% */
vertical-align: middle; /* top | middle | bottom ... do what you want */
}
.my-svg{ /* svg into : object, img or inline */
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%; /* only required for <img /> */
}
However this seems to have no effect on the responsiveness.
So is it possible to basically make this scale, but retain its position on the page? The height seems to be the main issue; positioning seems to be intact, but the height shrinks so everything isn't aligned any more.
Thanks! Let me know if you need more info
You are scaling the SVG image proportionally, which means that when the width changes (to adapt to the page width), the height must also change to keep the image proportions.
In part this is what you want, because scaling the image disregarding proportions would cause your traffic sign or the car to become stretched. On the other hand you want to keep the road height fixed, so here are your alternatives:
Alternative 1 — don't scale the image
This may seem counter to what you're looking for but it's definitely worth considering. You're not scaling the text around which the image revolves, so why scaling the image at all? Just keep both centered with constant size.
Alternative 2 — scale parts of your SVG separately
You can split your SVG into the parts you want with fixed proportion (like the traffic sign and vertical parts of roads) and variable proportion (like horizontal roads). You can use the preserveAspectRatio and viewBox attributes to. There's an example here (works on Chrome but not on current Firefox).
Alternative 3 — scale in discrete steps
If you really want the image to become bigger on a larger display, but don't feel like going through the complexity of alternative 2, you can prepare several SVGs for several width / height ratios and use media queries to display the appropriate one for the appropriate width interval.
Try changing your SVG to
preserveAspectRatio="xMinYMin slice"
It should mean that the SVG stays the same height as your content, but that the right hand side of the SVG gets clipped off as the page gets narrower.
If you want both sides (left and right) to get clipped off at the same rate, so the SVG remains centred, then use:
preserveAspectRatio="xMidYMin slice"

display all elements in svg in a fixed area

I have some javascript code that dynamically creates SVG polygons at various locations. Currently if a polygon is created outside of the range of the SVG element's width and height, then it isn't displayed. I would like the polygons to scale down so that each polygon is visible, within the specified area.
As an example this only displays one triangle:
<svg width="100" height="100">
<polygon points="0,0 0,100 100,50 " fill="blue"></polygon>
<polygon points="100,0 100,100 200,50 " fill="blue"></polygon>
</svg>
but I would like it to display something closer to what this displays (two triangles scaled to fit inside a 100 by 100 box,) without having to change the points myself:
<svg width="100" height="100">
<polygon points="0,0 0,100 50,50 " fill="blue"></polygon>
<polygon points="50,0 50,100 100,50 " fill="blue"></polygon>
</svg>
This seems like it should be easy to do but I searched for "svg scale to fit" and "display all elements in svg in a fixed area" but I couldn't find anything related to my problem

How to create responsive svg using d3.js

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.

how to scale the drawing according to viewbox or height width of svg tag

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.

Categories

Resources