/    Sign up×
Community /Pin to ProfileBookmark

SVG graphic scaling

The following creates an SVG display of 5 lines at a specific place on the screen.

[code]
<svg xmlns=”http://www.w3.org/2000/svg”
xmlns:xlink=”http://www.w3.org/1999/xlink”
height=”200″ width=”300″ style=”border:1px solid black”>
<line x1=”0″ y1=”10″ x2=”0″ y2=”110″ style=”stroke-width:6; stroke:#ff0000;”/>
<line x1=”20″ y1=”20″ x2=”120″ y2=”50″ style=”stroke-width:6; stroke:#00ff00;”/>
<line x1=”30″ y1=”30″ x2=”140″ y2=”100″ style=”stroke-width:6; stroke:#0000ff;”/>
<line x1=”40″ y1=”40″ x2=”150″ y2=”150″ style=”stroke-width:6; stroke:#006600;”/>
<line x1=”75″ y1=”25″ x2=”200″ y2=”25″ style=”stroke-width:6; stroke:#006600;”/>
</svg>
[/code]

What I would like to know is: Is it possible to make the hard coded values of x1,y1, x2,y2
to be scaled to a world range?

For example, if I define the “world” view to be 1000 wide an 800 high,
and given the actual screen if 300 pixels wide by 200 pixels high,
I could calculate the world positions on the screen as:

[code]
<script>
var World = [1000,800];
var Actual = [300,200];
var x1 = 175;
var y2 = 125;
var x2 = 200;
var y2 = 225;
sx1 = x1 / World[0] * Actual[0];
sy1 = y1 / World[1] * Actual[1];
sx2 = x2 / World[0] * Actual[0];
sy2 = y2 / World[1] * Actual[1];
</script>
<!– following line does not work –>
<line x1=sx1 y1=sy1 x2=sx2 y2=sy2 style=”stroke-width:6; stroke:#006600;”/>

[/code]

I want to use real world numbers like feet, yards, meters, etc
and scale them to the actual size of the graphics display
but I don’t know how to NOT hard code into the SVG tags.

Is there a way to do this?

to post a comment

6 Comments(s)

Copy linkTweet thisAlerts:
@rtretheweyMay 11.2013 — Since I know almost nothing about SVG graphics, I thought I'd share my lack of wisdom with you in the great tradition of online forums.... Actually, I have been curious about SVG, and just thought I might pick up something in your discussion - especially about the scaling parts. Anyway, it just struck me that as long as you could write the JavaScript that corresponds to your needs, you could always output the SVG tags in your HTML mark-up using that code. That would get you by until you can find the 'real' solution.

I am truly rotten when it comes to graphics, so when I need something like this, I generally rely on ImageMagick via PHP (or Perl, in days gone by). I've played with the HTML 5 <canvas> and managed to create a single SVG image, and I think there's a lot of ways I could use it once IE8 use is no longer significant. Good luck!
Copy linkTweet thisAlerts:
@JMRKERauthorMay 11.2013 — Yes, I can create a JS script to create the SVG tags

but, even without any errors being reported, nothing is displayed.

See this example...
<i>
</i>&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
&lt;meta charset="UTF-8" /&gt;

&lt;title&gt; SVG creation with JS &lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;h2&gt; Normal version &lt;/h2&gt; 300 x 250
&lt;svg id="actual" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="300" height="250" style="border:1px solid black"&gt;
&lt;line x1="0" y1="10" x2="0" y2="110" style="stroke-width:6; stroke:#ff0000;"/&gt;
&lt;line x1="20" y1="20" x2="120" y2="50" style="stroke-width:6; stroke:#00ff00;"/&gt;
&lt;line x1="30" y1="30" x2="140" y2="100" style="stroke-width:6; stroke:#0000ff;"/&gt;
&lt;line x1="40" y1="40" x2="150" y2="150" style="stroke-width:6; stroke:#006600;"/&gt;
&lt;line x1="75" y1="25" x2="200" y2="25" style="stroke-width:6; stroke:#006600;"/&gt;
&lt;line x1="175" y1="125" x2="200" y2="225" style="stroke-width:6; stroke:#000000;"/&gt;
&lt;/svg&gt;

&lt;h2&gt; Scaled version &lt;/h2&gt; 1000 x 800
&lt;svg id="world" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="300" height="200" style="border:1px solid black"&gt;
&lt;/svg&gt;

&lt;script type="text/javascript"&gt;
var World = [1000,800]; // w,h
var Actual = [300,250]; // w,h

function scaleX(x) { return Math.floor(x / World[0] * Actual[0]); }
function scaleY(y) { return Math.floor(y / World[1] * Actual[1]); }
function scaleLine(x1,y1,x2,y2) {
var str = '&lt;line x1="'+x1+'" y1="'+y1+'" x2="'+x2+'" y2="'+y2+'"';
str +=' style="stroke-width:6; stroke:#000000;"/&gt;';
// alert('Worldn'+x1+' '+y1+' '+x2+' '+y2); // shows scaling works
return str;
}

function init() {
var x1 = 175; var sx1 = scaleX(x1); var y1 = 125; var sy1 = scaleY(y1);
var x2 = 200; var sx2 = scaleX(x2); var y2 = 225; var sy2 = scaleY(y2);
// alert('Actualn'+x1+' '+y1+' '+x2+' '+y2); // shows scaling works
document.getElementById('world').innerHTML = scaleLine(sx1,sy1,sx2,sy2);
}
window.onload = function() { init(); }

&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;

I thought I could create the SVG line command, but it does not seem to activate this way? ?
Copy linkTweet thisAlerts:
@JMRKERauthorMay 12.2013 — I've played around with it some more and can now do what I originally wanted in post #1.

It is not a clean as I would like as it requires defining a scaled SVG command for every normal SVG command.

Would still be interested in making the change using variables within the normal commands,

but this will suffice for my needs at this time.

<i>
</i>&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
&lt;meta charset="UTF-8" /&gt;

&lt;title&gt; SVG creation with JS &lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;h2&gt; Normal version &lt;/h2&gt; 300 x 250
&lt;svg id="actual" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="300" height="250" style="border:1px solid black"&gt;
&lt;line x1="0" y1="10" x2="0" y2="110" style="stroke-width:6; stroke:#ff0000;"/&gt;
&lt;line x1="20" y1="20" x2="120" y2="50" style="stroke-width:6; stroke:#00ff00;"/&gt;
&lt;line x1="30" y1="30" x2="140" y2="100" style="stroke-width:6; stroke:#0000ff;"/&gt;
&lt;line x1="40" y1="40" x2="150" y2="150" style="stroke-width:6; stroke:#006600;"/&gt;
&lt;line x1="75" y1="25" x2="200" y2="25" style="stroke-width:6; stroke:#006600;"/&gt;
&lt;line x1="175" y1="125" x2="200" y2="225" style="stroke-width:6; stroke:#000000;"/&gt;
&lt;circle cx="100" cy="150" r="40" stroke="black" stroke-width="2" fill="red"/&gt;
&lt;/svg&gt;

&lt;h2&gt; Scaled version &lt;/h2&gt; 1000 x 800
&lt;svg id="world" width="300" height="250" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="300" height="200" style="border:1px solid black"&gt;
&lt;/svg&gt;

&lt;script type="text/javascript"&gt;
var World = [1000,800]; // w,h
var Actual = [300,250]; // w,h

function scaleX(x) { return Math.floor(x / World[0] * Actual[0]); }
function scaleY(y) { return Math.floor(y / World[1] * Actual[1]); }
function scaleLine(x1,y1,x2,y2,stkW,stkC) {
x1 = scaleX(x1); y1 = scaleY(y1);
x2 = scaleX(x2); y2 = scaleY(y2);

var str = '';
str += '&lt;svg&gt;';
str +=' &lt;line x1="'+x1+'" y1="'+y1+'" x2="'+x2+'" y2="'+y2+'"';
str +=' style="stroke-width:'+stkW+'; stroke:'+stkC+'"/&gt;';
str +='&lt;/svg&gt;';
return str;
}
function scaleCircle(x,y,r,stkW,stkC,stkF) {
x = scaleX(x); y = scaleY(y); r = scaleX(r);

var str = '';
str += '&lt;svg&gt;';
str += '&lt;circle cx="'+x+'" cy="'+y+'" r="'+r+'"';
str += ' stroke="'+stkC+'" stroke-width="'+stkW+'" fill="'+stkF+'"/&gt;';
str += '&lt;/svg&gt;';
return str;
}

function init() {
var sx1 = sy1 = sx2 = sy2 = 0;

sx1 = 0; sy1 = 10; sx2 = 0; sy2 = 110;
document.getElementById('world').innerHTML += scaleLine(sx1,sy1,sx2,sy2,'3','#ff0000');

sx1 = 20; sy1 = 20; sx2 = 120; sy2 = 50;
document.getElementById('world').innerHTML += scaleLine(sx1,sy1,sx2,sy2,'3','#00ff00');

sx1 = 30; sy1 = 30; sx2 = 140; sy2 = 100;
document.getElementById('world').innerHTML += scaleLine(sx1,sy1,sx2,sy2,'3','#0000ff');

sx1 = 40; sy1 = 40; sx2 = 150; sy2 = 150;
document.getElementById('world').innerHTML += scaleLine(sx1,sy1,sx2,sy2,'3','#006600');

sx1 = 75; sy1 = 25; sx2 = 200; sy2 = 25;
document.getElementById('world').innerHTML += scaleLine(sx1,sy1,sx2,sy2,'3','#006600');

sx1 = 175; sy1 = 125; sx2 = 200; sy2 = 225;
document.getElementById('world').innerHTML += scaleLine(sx1,sy1,sx2,sy2,'3','#000000');

sx1 = 100; sy1 = 150; sx2 = 40;
document.getElementById('world').innerHTML += scaleCircle(sx1,sy1,sx2,'#000000','3','#ff0000');

}
window.onload = function() { init(); }

&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;

Copy linkTweet thisAlerts:
@rtretheweyMay 12.2013 — I had a hunch that searching with the keyword "dynamic" might be helpful, but all of the references I found relied on JavaScript, so I think that's the only viable approach at the moment.
Copy linkTweet thisAlerts:
@iBeZiMay 12.2013 — It might be a bit neater if you create SVG elements and append them to the world element instead of creating a string and updating the innerHTML, you could create a function that automates the creation of an SVG element like so

[code=html]
function svgElement(element,attributes) {
var element = document.createElementNS("http://www.w3.org/2000/svg",element);
for(key in attributes) {
element.setAttribute(key,attributes[key]);
}
return element;
}
function scaleLine(x1,y1,x2,y2,stkW,stkC) {
x1 = scaleX(x1); y1 = scaleY(y1);
x2 = scaleX(x2); y2 = scaleY(y2);
var attributes = {
"x1":x1,
"x2":x2,
"y1":y1,
"y2":y2,
"style":"stroke-width:"+stkW+"; stroke:"+stkC
};
var line = svgElement("line",attributes);
return line;
}
function scaleCircle(x,y,r,stkW,stkC,stkF) {
x = scaleX(x); y = scaleY(y); r = scaleX(r);
var attributes = {
"cx":x,
"cy":y,
"r":r,
"stroke":stkC,
"stroke-width":stkW,
"fill":stkF
};
var circle = svgElement("circle",attributes);
return circle;
}
function init() {
var sx1 = sy1 = sx2 = sy2 = 0;
var world = document.getElementById('world');
sx1 = 0; sy1 = 10; sx2 = 0; sy2 = 110;
world.appendChild(scaleLine(sx1,sy1,sx2,sy2,'3','#ff0000'));

sx1 = 20; sy1 = 20; sx2 = 120; sy2 = 50;
world.appendChild(scaleLine(sx1,sy1,sx2,sy2,'3','#00ff00'));

sx1 = 30; sy1 = 30; sx2 = 140; sy2 = 100;
world.appendChild(scaleLine(sx1,sy1,sx2,sy2,'3','#0000ff'));

sx1 = 40; sy1 = 40; sx2 = 150; sy2 = 150;
world.appendChild(scaleLine(sx1,sy1,sx2,sy2,'3','#006600'));

sx1 = 75; sy1 = 25; sx2 = 200; sy2 = 25;
world.appendChild(scaleLine(sx1,sy1,sx2,sy2,'3','#006600'));

sx1 = 175; sy1 = 125; sx2 = 200; sy2 = 225;
world.appendChild(scaleLine(sx1,sy1,sx2,sy2,'3','#000000'));

sx1 = 100; sy1 = 150; sx2 = 40;
world.appendChild(scaleCircle(sx1,sy1,sx2,'#000000','3','#ff0000'));

}
[/code]


You can also scale SVG images by using the viewbox attribute, so for example if you want to scale an SVG image that is 300 x 250 up to 1000 x 800 you can add a viewbox attribute to do so by setting the viewbox to the original size and then setting the height and width attributes to the size you want it to appear

[code=html]
<svg id="actual" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="1000" height="800" style="border:1px solid black"
viewBox="0 0 300 250">
<line x1="0" y1="10" x2="0" y2="110" style="stroke-width:6; stroke:#ff0000;"/>
<line x1="20" y1="20" x2="120" y2="50" style="stroke-width:6; stroke:#00ff00;"/>
<line x1="30" y1="30" x2="140" y2="100" style="stroke-width:6; stroke:#0000ff;"/>
<line x1="40" y1="40" x2="150" y2="150" style="stroke-width:6; stroke:#006600;"/>
<line x1="75" y1="25" x2="200" y2="25" style="stroke-width:6; stroke:#006600;"/>
<line x1="175" y1="125" x2="200" y2="225" style="stroke-width:6; stroke:#000000;"/>
<circle cx="100" cy="150" r="40" stroke="black" stroke-width="2" fill="red"/>
</svg>
[/code]
Copy linkTweet thisAlerts:
@JMRKERauthorMay 13.2013 — It might be a bit neater if you create SVG elements and append them to the world element instead of creating a string and updating the innerHTML, you could create a function that automates the creation of an SVG element like so

[code=html]
...
[/code]


You can also scale SVG images by using the viewbox attribute, so for example if you want to scale an SVG image that is 300 x 250 up to 1000 x 800 you can add a viewbox attribute to do so by setting the viewbox to the original size and then setting the height and width attributes to the size you want it to appear

[code=html]
...
[/code]
[/QUOTE]


Thank you, both versions work well.

Version 1 is a little closer to what I was trying to accomplish,

but I can see some other applications for the second as well.

I was not aware of the 'viewbox' command.

My ultimate goal is to be able to create dynamic optical ray diagrams

from user input for the display of simple and complex optical systems such as,

thin lens, telescopes, compound microscopes and simple optical principles like,

Snell's law, prismatic refraction and critical angles.

I want the user to be able to input values for the formulas to see the actions that occur.

Actual input values can be large and the resulting graphics would need to be scaled down

to be able to be displayed on the screen.

You have given me some possibilities that I shall investigate further. Thanks! ?

I'll post back if I come up with some acceptable designs for the displays.
×

Success!

Help @JMRKER spread the word by sharing this article on Twitter...

Tweet This
Sign in
Forgot password?
Sign in with TwitchSign in with GithubCreate Account
about: ({
version: 0.1.9 BETA 4.29,
whats_new: community page,
up_next: more Davinci•003 tasks,
coming_soon: events calendar,
social: @webDeveloperHQ
});

legal: ({
terms: of use,
privacy: policy
});
changelog: (
version: 0.1.9,
notes: added community page

version: 0.1.8,
notes: added Davinci•003

version: 0.1.7,
notes: upvote answers to bounties

version: 0.1.6,
notes: article editor refresh
)...
recent_tips: (
tipper: @Yussuf4331,
tipped: article
amount: 1000 SATS,

tipper: @darkwebsites540,
tipped: article
amount: 10 SATS,

tipper: @Samric24,
tipped: article
amount: 1000 SATS,
)...