I would like to make an image appear as hexagon.
Therefore I am using svg.
<svg id="hexagon">
<defs>
<pattern id="pattern1" height="100%" width="100%" patternContentUnits="objectBoundingBox">
<image height="1" width="1" preserveAspectRatio="none" xlink:href="https://pixabay.com/static/uploads/photo/2016/01/14/01/41/image-view-1139204_960_720.jpg"/>
</pattern>
</defs>
<polygon fill="url(#pattern1)" points=" 121.25 0 242.5 100 242.5 300 121.25 400 121.25 400 0 300 0 100"/>
</svg>
Now I want to manipulate the coordinates of this svg depending on position of mouse on screen. So if the mouse-cursor is on right side of screen the first point of hexagon (the upper one) should be at right edge of screen too. Otherwise if the mouse-cursor is on left side of screen the first point of hexagon should be at left edge of screen. The position of this upper point should change dynamically depending on mouse-cursor position.
For testing I tried this one to access the points but it did not work:
<script>
var polygon = document.getElementById("hexagon");
polygon.setAttribute("points", "0,0 100,100 200,200");
</script>
What did I do wrong?
You need to find the center of the svg (I think I have that correct but you might want to verify). Once you have that, you can rotate it to "look at the mouse"
document.addEventListener("mousemove", function(event) {
var follower = document.getElementById("hexagon");
// -----------------------
// calculate the center of the hexagon
// -----------------------
var followerCentroid = (function() {
var followerClientBox = follower.getBoundingClientRect();
return [
(followerClientBox.top + followerClientBox.bottom) / 2,
(followerClientBox.left + followerClientBox.right) / 2
];
})();
// -----------------------
// -----------------------
// rotate to look at mouse
// -----------------------
var lookAngle = Math.atan2(
event.pageX - followerCentroid[1],
-(event.pageY - followerCentroid[0])) * (180 / Math.PI);
follower.style.transform = 'rotate(' + lookAngle + 'deg)';
// -----------------------
});
<div style="padding: 50px;">
<svg id="hexagon">
<defs>
<pattern id="pattern1" height="100%" width="100%" patternContentUnits="objectBoundingBox">
<image height="1" width="1" preserveAspectRatio="none" xlink:href="https://pixabay.com/static/uploads/photo/2016/01/14/01/41/image-view-1139204_960_720.jpg" />
</pattern>
</defs>
<polygon fill="url(#pattern1)" points=" 121.25 0 242.5 100 242.5 300 121.25 400 121.25 400 0 300 0 100" />
</svg>
</div>
Related
Previously, I asked how to obtain the real coordinates (d) of a path when a transformation is applied, finally I decided to investigate the transformation formulas, I have already seen the translation, and now I am seeing the scaling (scale), I managed to do a scaling Basically the formula is:
x’ = x * sx
y’ = y * sy
If I have a path where d attribute (command) of M5, 5 L50, 5 L50, 45 L5, 45 Z, and, If we inspect the path in the DOM, we'll find that it has a width of 135px and a height of 120px:
<svg width="300" height="300" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="100" height="100" fill="red" />
<path id="element" d="M5, 5 L50, 5 L50, 45 L5, 45 Z" fill="none" stroke="white" />
</svg>
So if I wanted to scale this path using a scale factor of 2, it would be M10, 10 L100, 10 L100, 90 L10, 90, but if we now inspect the path in the DOM, the width is 270px and its height is 240px:
<svg width="300" height="300" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="100" height="100" fill="red" />
<path id="element" d="M10, 10 L100, 10 L100, 90 L10, 90 Z" fill="none" stroke="white" />
</svg>
Therefore, the value or scale factor of 2 is equivalent to a width of 135px and a height of 120px, so:
How can I make this scale factor or value equal to 1px?
Is there a conversion formula?
Playing around, I managed to guess that if the scale factor is:
1.1 = 15px -> therefore, the width would be 135px increasing to 150px and the height would be 120px increasing to 135px.
1.01 = 1.5px -> therefore, the width would be 135px increasing to 136.5px and the height would be 120px increasing to 121.5px.
I hope you have understood what I want to do, I hope you can help me.
I think I get what you are saying, but your formulas don't seem to make sense.
1.1 = 15px -> therefore, the width would be 135px increasing to 150px
and the height would be 120px increasing to 135px
That "15px" seems wrong. 1.1 * 135 = 148.5, not 150.
What I think you are asking is how to calculate the scale that would make the width become 150. Is that right?
The scale that will get the width to exactly 150 can be calculated like this:
new_width 150
scale = ----------- = ----- = 1.1111...
old_width 135
So checking that: 135 * 1.1111... = 150.0.
And the new height using this scale would be: 120 * 1.1111... = 133.333...
I am trying to create a progress bar (arc) with SVG. I currently have the progress bar working, it is moving the desired amount using a value stored in a data attribute, and looks pretty good. although i am trying to get an image to move around the arc with the bar. The image should start at 0 with the bar and move around to the completion point, say 50% which will be at the top.
<div class="w-100 case-progress-bar input p-2" style="position: relative;" data-percentage="80">
<svg class='progress_bar' viewBox="0 0 100 50" >
<g fill-opacity="0" stroke-width="4">
<path d="M5 50a45 45 0 1 1 90 0" stroke="#EBEDF8"></path>
<path class="progress" d="M5 50a45 45 0 1 1 90 0" stroke="#f00" stroke-dasharray="142" stroke-dashoffset="142"></path>
</g>
<circle fill="url(#image)" id='case_progress__prog_fill' class="case_progress__prog" cx="0" cy="0" r="8" fill="#999" stroke="#fff" stroke-width="1" />
<defs>
<pattern id="image" x="0%" y="0%" height="100%" width="100%" viewBox="0 0 60 60">
<image x="0%" y="0%" width="60" height="60" xlink:href="https://via.placeholder.com/150x150"></image>
</pattern>
</defs>
</svg>
</div>
(function(){
var $wrapper = $('.case-progress-bar'),
$bar = $wrapper.find('.progress_bar'),
$progress = $bar.find('.progress'),
$percentage = $wrapper.data('percentage');
$progress.css({
'stroke-dashoffset': 'calc(142 - (0 * 142 / 100))',
'transition': 'all 1s'
});
var to = setTimeout(function(){
$progress.css('stroke-dashoffset', 'calc(142 - (' + $percentage + ' * 142 / 100))');
clearTimeout(to);
}, 500);
})();
this is what I currently have
this is what i'm trying to achieve
To solve, you need to combine two animations:
Painting half of the arc from the beginning to the middle (top)
Animation of movement of a circle with an image inside
Set the same time for both animations
<div class="w-100 case-progress-bar input p-2" style="position: relative;" data-percentage="80">
<svg class='progress_bar' viewBox="0 0 100 50" >
<g fill-opacity="0" stroke-width="4">
<path id="pfad" d="M5 50C5 44.1 6.1 38.5 8.2 33.4 10.8 26.8 14.9 20.9 20.2 16.3 28.1 9.3 38.6 5 50 5" stroke="#EBEDF8"></path>
<path d="M5 50a45 45 0 1 1 90 0" stroke="#EBEDF8"></path>
<!-- Animation to fill half an arc -->
<path class="progress" d="M5 50a45 45 0 1 1 90 0" stroke="#f00" stroke-dasharray="142" stroke-dashoffset="142">
<animate attributeName="stroke-dashoffset" from="142" to="71" dur="4s" fill="freeze" />
</path>
</g>
<defs>
<pattern id="image" x="0%" y="0%" height="100%" width="100%" viewBox="0 0 60 60">
<image x="0%" y="0%" width="60" height="60" xlink:href="https://via.placeholder.com/150x150"></image>
</pattern>
</defs>
<circle fill="url(#image)" id='case_progress__prog_fill' class="case_progress__prog" cx="0" cy="0" r="8" fill="#999" stroke="#fff" stroke-width="1" >
<!-- Animation of movement of a circle with an image -->
<animateMotion begin="0s" dur="4s" fill="freeze">
<mpath xlink:href="#pfad" />
</animateMotion>
</circle>
</svg>
</div>
This is a case where it has advantages not to use thestroke-dasharray trick.
SVG can draw a marker at the end of a path. That marker can be any sort of grafic, and its syntax is just like that of a <symbol>. The position of the marker is defined by the path d attribute, and not influenced by a dashed stroke.
The general strategy is to compute the endpoint of the path
endpoint_x = center_x - cos(percentage / 100 * 180°) * radius
endpoint_y = center_y - sin(percentage / 100 * 180°) * radius
It is possible to do so relatively seamlessly because you decided to use only a half-circle to represent 100%. I have changed the way the path data are written to make that possible:
`M5 50 A 45 45 0 ${large} 1 ${x} ${y}`
A means: draw an arc and use absolute coordinates.
45 45 0 use a rx of 45, a ry of 45, do not rotate the axis of the arc.
${large} is the important bit. It discerns arcs of less than 180° from those that have more than 180°. As soon as that value would be crossed, the flag must change from 0 to 1. But since you are never expecting values above 180°, you would not need it.
1 means looking in the direction of the path, the arc should be drawn to the left side.
${x} ${y} are the final coordinates expressed in absolute, not relative coordinates.
The <marker> element has a number of attributes that must be considered:
orient="0" means the marker will not change its direction with the direction of the path at its end. orient="auto" would make it turn around , as you would like to see with an arrow for example.
markerUnits="userSpaceOnUse" means the numbers in the other attributes are in px units of the coordinate system of the path. Default would be markerUnits="strokeWidth", which would mean a size relative to the width of the stroke.
viewBox="-8 -8 16 16" is choosen because the circle used is centered around the coordinate system origin.
markerWidth="16" markerHeight="16" is saying how large the marker should be drawn.
refX="0" refY="-10" describes how the marker should be positioned: Take a point in the coordinate system of the marker itself (slightly above its topmost point and in the middle), and align it exactly with the end of the path.
Finally, note the marker-end="url(#image)" presentation attribute for the path. This is what sets the marker, and defines that it will be at the end of the path.
(function(){
var $wrapper = $('.case-progress-bar'),
$bar = $wrapper.find('.progress_bar'),
$progress = $bar.find('.progress'),
$percentage = $wrapper.data('percentage');
function computePath (percentage) {
var x = 50 - Math.cos(percentage / 100 * Math.PI) * 45,
y = 50 - Math.sin(percentage / 100 * Math.PI) * 45,
large = percentage > 100 ? 1 : 0;
return `M5 50 A 45 45 0 ${large} 1 ${x} ${y}`;
}
var to = setTimeout(function(){
$progress.attr('d', computePath($percentage));
clearTimeout(to);
}, 500);
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="w-100 case-progress-bar input p-2" style="position: relative;" data-percentage="80">
<svg class='progress_bar' viewBox="0 0 100 70" >
<g fill-opacity="0" stroke-width="4">
<path d="M5 50a45 45 0 1 1 90 0" stroke="#EBEDF8"></path>
<path class="progress" d="M5 50 A 45 45 0 0 1 95 50`" stroke="#f00"
marker-end="url(#image)"></path>
</g>
<marker id="image" orient="0" markerUnits="userSpaceOnUse"
viewBox="-8 -8 16 16"
markerWidth="16" markerHeight="16"
refX="0" refY="-10">
<circle r="8" fill="#aaf" />
<path d="M-6 0h12" stroke="#000" stroke-width="2" />
</marker>
</svg>
</div>
Just use a little JavaScript since you can't do trigonometry in CSS easily yet.
Codepen: https://codepen.io/mullany/pen/02cd0773588b3d975c8443ab6a87f670
(function(){
var $wrapper = $('.case-progress-bar'),
$bar = $wrapper.find('.progress_bar'),
$progress = $bar.find('.progress'),
$percentage = $wrapper.data('percentage');
var $circpos = $('.case_progress__prog');
$progress.css({
'stroke-dashoffset': 'calc(142 - (0 * 142 / 100))',
'transition': 'all 1s'
});
var to = setTimeout(function(){
$progress.css('stroke-dashoffset', 'calc(142 - (' + $percentage + ' * 142 / 100))');
var angleInRadians = 180*(1-$percentage/100) * 0.01745329251;
var xPos = 5 + 45 * (1 + Math.cos(angleInRadians) );
var yPos = 5 + 45 * (1 - Math.sin(angleInRadians) );
$circpos.css('cx', xPos);
$circpos.css('cy', yPos);
clearTimeout(to);
}, 500);
})();
I had a very similarly shaped loading SVG. You cen see it in action here. The green one at the bottom of the main banner.
What I used was the ProgressBar.js library. It made it very easy. I just focused on adjusting my SVG in terms of shape, because of the design of my site and then just used:
<svg id="progress-bar" xmlns="http://www.w3.org/2000/svg" width="650" height="526" viewBox="0 0 650 526">
<path opacity=".55" id="progress-bar-base" fill="none" stroke="#fefefe" stroke-width="20" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M84.591 512.622S20 441.232 20 324.941 79.903 131.327 137.4 84.476 269.116 20 324.94 20s124.217 15.743 184.57 62.183 89.159 101.578 103.475 142.419c14.316 40.84 25.203 105.21 8.788 170.477-16.415 65.268-43.628 101.409-56.482 117.543"></path>
<linearGradient id="grade" gradientUnits="userSpaceOnUse" x1="592.08" y1="157.665" x2="46.149" y2="472.859">
<stop offset="0" stop-color="#2cab9a"></stop>
<stop offset="1" stop-color="#8ed1c3"></stop>
</linearGradient>
<path fill-opacity="0" id="progress-bar-indicator" stroke="url(#grade)" stroke-width="24" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M84.591 512.622S20 441.232 20 324.941 79.903 131.327 137.4 84.476 269.116 20 324.94 20s124.217 15.743 184.57 62.183 89.159 101.578 103.475 142.419c14.316 40.84 25.203 105.21 8.788 170.477-16.415 65.268-43.628 101.409-56.482 117.543" style="stroke-dasharray: 1362.73, 1362.73; stroke-dashoffset: 1140.45;"></path>
</svg>
var progressBar = new ProgressBar.Path('#progress-bar-indicator', {
easing: 'easeInOut',
duration: 2500
});
progressBar.set(0); // Initiate it at zero.
progressBar.animate(0.33); // this is your percentage of load
It's a very basic example, but I think you could adjust it to your needs.
As for the image, perhaps you could add it to your own SVG at the tip of the loading curve and it should move with it I think.
I want to animate a svg path on a line. Exactly like this codepen but instead of use a polygon, I want to use a more complex svg. (path)
Codepen example
Html :
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="100%" height="100%" viewBox="0 0 800 300" enable-background="new 0 0 800 300" xml:space="preserve">
<path d="M30,30 L770,30" />
<path d="M29.833,113.5C29.833,178.667,99,271.334,257,271.334 S475.5,81,375.5,81S305,271.334,770,271.334"/>
<polygon points="15,0 18.541,11.459 30,11.459 20.729,18.541 24.271,30 15,22.918 5.729,30 9.271,18.541 0,11.459 11.459,11.459 "/>
<polygon points="15,0 18.541,11.459 30,11.459 20.729,18.541 24.271,30 15,22.918 5.729,30 9.271,18.541 0,11.459 11.459,11.459 "/>
</svg>
Is anyone know how to replace the polygon by a svg path file ?
Thank you,
In this example I'm using a complex <symbol> element instead of the star. The <symbol> contains a path and 4 circles. I've putted this symbol in a hidden SVG element.
In the main SVG element I've changed the polygons (stars) with 2 <use> elements that are using the #cow symbol.
In the Javascript I've changed var stars = svgContainer.getElementsByTagName("polygon"); with var stars = svgContainer.getElementsByTagName("use");
You can if you want to change the name of the variable from stars to cows in all your javascript.
/* A variable to keep track of where we are on the line
0 = start, 1 = end */
var counter = 0;
/* A boolean variable to keep track of the direction we want to travel in
true = move to the left, false move to the right */
var direction = true;
/* First get a reference to the enclosing div and then to
the 2 svg paths */
var svgContainer = document.getElementById("outerWrapper");
var ns = "http://www.w3.org/2000/svg";
var svg = svgContainer.getElementsByTagNameNS(ns, "path");
/* the var 'svg' contains a reference to two paths so svg.length = 2
svg[0] is the straight line and svg[1] is the curved lines */
/* Now get the length of those two paths */
var straightLength = svg[0].getTotalLength();
var curveLength = svg[1].getTotalLength();
/* Also get a reference to the two star polygons */
var stars = svgContainer.getElementsByTagName("use");
function moveStar() {
/* Check to see where the stars are journeys to determine
what direction they should be travelling in */
if (parseInt(counter,10) === 1) {
/* we've hit the end! */
direction = false;
} else if (parseInt(counter,10) < 0) {
/* we're back at the start! */
direction = true;
}
/* Based on the direction variable either increase or decrease the counter */
if (direction) {
counter += 0.003;
} else {
counter -= 0.003;
}
/* Now the magic part. We are able to call .getPointAtLength on the tow paths to return
the coordinates at any point along their lengths. We then simply set the stars to be positioned
at these coordinates, incrementing along the lengths of the paths */
stars[0].setAttribute("transform","translate("+ (svg[0].getPointAtLength(counter * straightLength).x -15) + "," + (svg[0].getPointAtLength(counter * straightLength).y -15) + ")");
stars[1].setAttribute("transform","translate("+ (svg[1].getPointAtLength(counter * curveLength).x -15) + "," + (svg[1].getPointAtLength(counter * curveLength).y -15) + ")");
/* Use requestAnimationFrame to recursively call moveStar() 60 times a second
to create the illusion of movement */
requestAnimationFrame(moveStar);
}
requestAnimationFrame(moveStar);
body {
margin: 0;
background: #565279;
}
.outerWrapper {
width: 800px;
height: 300px;
position: relative;
}
.outerWrapper svg {
position: absolute;
}
.outerWrapper svg path {
fill:none;
stroke:#DABDD8;
stroke-width:5;
stroke-dasharray:10,10;
}
.outerWrapper svg polygon {
fill:orange;
}
<svg style="display:none">
<defs>
<symbol id="cow" viewBox= "0 0 200 200">
<path class="head" fill="gold" stroke-width="1" d="M87 110 c5 0 12-0 21-0 c9-0 26 2 33-4 c5-4 2-14 0-19 c-6-11-14-11-25-11c-10-0-15-7-8-16 c11-13 22-2 35-3 c7-0.622 15.812-11.692 5.757-14.441c-3.556-0.973-12.802 0.949-15.412-0.906c6.371 4.5 20.854-11.553 23.774-15.168 c4.103-5.079 7.713-10.561 10.987-16.205c0.678-1.169 2.928-7.366 4.133-7.882c-7.42 3.175-14.234 8.021-22.368 10.7 c-20.585 6.695-42.426 9.711-64.039 9.711c-18.865 0.045-41.083-2.831-60.479-8.723C16.774 10.2 9.1 5 0.6 1.4 C4.425 3 11 19.4 13.8 23.083c3.03 4 18.5 22.6 25.6 17.551c-2.173 1.544-10.67-0.021-13.562 0.5 c-9.382 1.672-7.292 11.8 1 14.308c12.151 3.7 23.371-8.617 35 0.611c7.217 5.7 11.1 18.941-1.428 19.4 c-10.27 0.355-20.138-1.575-26.384 8.23c-4.091 6.423-6.256 13.976-2.265 20.886c3.503 6.1 24.2 4.7 30.3 4.9 C70.382 109.8 78.7 109.9 87 109.8"/>
<circle class="eyeR" fill="#040B13" stroke-width="1" cx="117.3" cy="64.9" r="6"/>
<circle class="eyeL" fill="#040B13" stroke-width="1" cx="55.4" cy="64.9" r="6"/>
<circle class="nostrilL" fill="#446B70" stroke-width="1" cx="50.6" cy="92.9" r="9"/>
<circle class="nostrilR" fill="#446B70" stroke-width="1" cx="123.4" cy="92.9" r="9"/>
</symbol>
</defs>
</svg>
<div class="outerWrapper" id="outerWrapper">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="100%" height="100%" viewBox="0 0 800 300" enable-background="new 0 0 800 300" xml:space="preserve">
<path class="pth" d="M30,30 L770,30" />
<path class="pth" d="M29.833,113.5C29.833,178.667,99,271.334,257,271.334 S475.5,81,375.5,81S305,271.334,770,271.334"/>
<use xlink:href="#cow" width="30" height="30" />
<use xlink:href="#cow" width="30" height="30" />
</svg>
</div>
I have a rectangle in my SVG, I have one graphic like aircraft and i would like to use mask and move it on random orbit. I'm looking for the sollution for this.
EDIT:
I would like to get a javascript which makes like the black paths as mask in SVG. Wanna be move and make a copy of the element.
Here it is my svg i would like to move the plane and copy after moving:
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="500px" viewBox="0 0 500 500" width="500px" version="1.1" y="0px" x="0px" xmlns:xlink="http://www.w3.org/1999/xlink" enable-background="new 0 0 500 500">
<g id="_x32_">
<path d="M250.2,59.002c11.001,0,20.176,9.165,20.176,20.777v122.24l171.12,95.954v42.779l-171.12-49.501v89.227l40.337,29.946v35.446l-60.52-20.18-60.502,20.166v-35.45l40.341-29.946v-89.227l-171.14,49.51v-42.779l171.14-95.954v-122.24c0-11.612,9.15-20.777,20.16-20.777z"/>
<path stroke="#000" stroke-width="0.2" d="M31.356,500.29c-17.26,0-31.256-13.995-31.256-31.261v-437.67c0-17.265,13.996-31.261,31.256-31.261h437.68c17.266,0,31.261,13.996,31.261,31.263v437.67c0,17.266-13.995,31.261-31.261,31.261h-437.67z" fill="none"/>
</g>
</svg>
I'm not sure I understand exactly what you want. But here is a little demo that hopefully should help you get started at least.
// Get references to the various elements in the SVG
var svg = document.getElementById("Layer_1");
var blackpath = svg.getElementById("blackpath");
var redplane = svg.getElementById("redplane");
// Add an event listener to the SVG that captures mouse move events
svg.addEventListener("mousemove", function(evt) {
// Convert the mouse position from screen coords to SVG coords.
var pt = svg.createSVGPoint();
pt.x = evt.clientX;
pt.y = evt.clientY;
pt = pt.matrixTransform(svg.getScreenCTM().inverse());
// Move the red plane to the mouse mosition
redplane.setAttribute("x", pt.x);
redplane.setAttribute("y", pt.y);
// Create a <use> element to add a cloned "copy" of the plane to the "blackpath" group.
var useElement = document.createElementNS("http://www.w3.org/2000/svg", "use");
useElement.setAttributeNS("http://www.w3.org/1999/xlink", "href", "#plane");
// Position the clone at the mouse coords
useElement.setAttribute("x", pt.x);
useElement.setAttribute("y", pt.y);
// Add it to the blackpath group
blackpath.appendChild(useElement);
});
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" height="500px" viewBox="0 0 500 500" width="500px" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path id="plane"
d="M250.2,59.002c11.001,0,20.176,9.165,20.176,20.777v122.24l171.12,95.954v42.779l-171.12-49.501v89.227l40.337,29.946v35.446l-60.52-20.18-60.502,20.166v-35.45l40.341-29.946v-89.227l-171.14,49.51v-42.779l171.14-95.954v-122.24c0-11.612,9.15-20.777,20.16-20.777z" transform="scale(0.2, 0.2) translate(-250, -250)"/>
</defs>
<rect width="500" height="500" fill="#407085"/>
<g id="blackpath" fill="black"></g>
<use id="redplane" xlink:href="#plane" fill="#f30000" x="-100" y="-100"/>
</svg>
I am dynamically generating some SVG. What I want to do is divide the page in half (no matter what size it is) and be able to insert some objects on the left side of the screen and some objects on the right of the screen. I just can't seem to get it right. I have actually tried to do it many different ways, the code listed here was my most recent attempt:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%">
<script type="text/ecmascript">
var svgNS = "http://www.w3.org/2000/svg";
var xlinkNS = "http://www.w3.org/1999/xlink";
var i = 0;
function makeBox() {
i++;
var newRect = document.createElementNS(svgNS,"rect");
newRect.setAttributeNS(null,"width", 100);
newRect.setAttributeNS(null,"height", 100);
newRect.setAttributeNS(null, "x", 10);
newRect.setAttributeNS(null, "y", i * 100);
newRect.setAttributeNS(null,"fill","blue");
if(i % 2 === 1) {
document.getElementById("screenLeft").appendChild(newRect);
} else {
document.getElementById("screenRight").appendChild(newRect);
}
}
</script>
<g id="firstGroup">
<text x="20" y="30" onclick="makeBox()" font-size="+13px">Click this text to Draw a Box.</text>
</g>
<svg id="screenLeft" viewBox="50% 100%">
</svg>
<svg id="screenRight" viewBox="50% 100%" x="50%">
</svg>
</svg>
Of course I changed a bunch of code to make this post more concise. What it does is, when user clicks the text, it draws a rectangle in element "screenLeft" or "screenRight" depending on if the increment (i) is even or odd.
The way I have the viewBox setup right now sort of works. If I reduce the chrome window to a smaller size, the gap between the "leftSide" and the "rightSide" does get smaller. However, if I have the window Maximized, the screen area is WAY too big. I have to scroll far to the right to see the "rightSide". It is about twice my screen size.
I have also tried several other methods, involving grouping.
So, I guess my question is, what is the best way to divide the screen in half so I can generate some objects on the left side of the screen and some on the right side of the screen, while allowing the total screen size to differ?
Give your <svg> element a viewBox with fixed width and an exceptional height. Then specify a preserveAspectRatio attribute with the value of xMidYMid slice.
This will ensure that the full width of your SVG viewport will always cover the viewBox, and half of your viewBox will thus cover half the screen.
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="-100 -1000 200 2000" preserveAspectRatio="xMidYMid slice">
<style type="text/css"><![CDATA[
rect { stroke:red }
text { text-anchor:middle; font-size:8px }
]]></style>
<rect x="-100" y="-1000" width="100" height="2000" fill="lightblue" />
<rect x="0" y="-1000" width="100" height="2000" fill="yellow" />
<text x="-50" y="0">Left Side</text>
<text x="+50" y="0">Right Side</text>
</svg>
See this live: http://phrogz.net/svg/half-width.svg
The only downside with this (which I can't tell if it matters to you) is that resizing the browser window will resize the elements. Maybe you want elements to always remain the same size on screen no mater how large the browser?
This seemed to do what I think you wanted, the only thing you need to decide is how you want aspect ratio to effect your display... I deliberately left the right side's aspect ratio unadjusted so you could see the difference.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" >
<svg width="50%" viewBox="0 0 100 100" preserveAspectRatio="none">
<rect x="0" y="0" width="100%" height="100%" fill="red" opacity="0.5"/>
</svg>
<svg x="50%" width="50%" viewBox="0 0 100 100" >
<rect x="0" y="0" width="100%" height="100%" fill="blue" opacity="0.5"/>
<rect x="80%" y="10%" width="10%" height="50%" fill="green"/>
<rect x="10" y="10" width="70" height="40" fill="gray"/>
</svg>