Scaling SVG (Raphael.js) like an SWF
Well hello Zévan,
I found a nice answer, made by a guy called Zevan. However, I found the code overcomplicated for my liking (Required jquery, did wierd stuff like "$(this)" etc).
So I simplified it. It's now short enough to fit into stackoverflow ;):
var paper;
window.ScaleRaphael = function(container, width, height) {
var wrapper = document.getElementById(container);
wrapper.style.width = width + "px";
wrapper.style.height = height + "px";
wrapper.style.overflow = "hidden";
wrapper.innerHTML = "<div id='svggroup'><\/div>";
var nestedWrapper = document.getElementById("svggroup");
paper = new Raphael(nestedWrapper, width, height);
paper.w = width;
paper.h = height;
paper.canvas.setAttribute("viewBox", "0 0 "+width+" "+height);
paper.changeSize = function() {
var w = window.innerWidth
var h = window.innerHeight
var ratioW = w / width;
var ratioH = h / height;
var scale = ratioW < ratioH ? ratioW : ratioH;
var newHeight = Math.floor(height * scale);
var newWidth = Math.floor(width * scale);
wrapper.style.width = newWidth + "px";
wrapper.style.height = newHeight + "px";
paper.setSize(newWidth, newHeight);
}
window.onresize = function() {
paper.changeSize();
}
paper.changeSize();
return paper;
}
The only drawback from your version is that it requires SVG, it doesn't do VML. Is this a problem?
I'm using it with a simplified version of your demo page:
<!DOCTYPE html>
<html lang="en">
<head>
<title>ScaleRaphaël Demo 1</title>
<meta charset="utf-8">
<script type="text/javascript" src="raphael.js"></script>
<script type="text/javascript" src="scale.raphael.js"></script>
<script type="text/javascript">
window.onload = function() {
var paper = new ScaleRaphael("wrap", 600, 400);
// draw some random vectors:
var path = "M " + paper.w / 2 + " " + paper.h / 2;
for (var i = 0; i < 100; i++){
var x = Math.random() * paper.w;
var y = Math.random() * paper.h;
paper.circle(x, y,
Math.random() * 60 + 2).
attr("fill", "rgb("+Math.random() * 255+",0,0)").
attr("opacity", 0.5);
path += "L " + x + " " + y + " ";
}
paper.path(path).attr("stroke","#ffffff").attr("stroke-opacity", 0.2);
paper.text(200,100,"Resize the window").attr("font","30px Arial").attr("fill","#ffffff");
}
</script>
<style type="text/css">
body, html {
margin: 0;
padding: 0;
overflow: hidden;
}
#wrap{
background-color: orange;
}
</style>
</head>
<body>
It took me awhile but I finally came up with a solution to this problem. I've wrapped the solution in a small js file that can be used with Raphael. You can get the js file along with some simple documentation here. See it in action.
How it works:
- use viewBox for svg
- wrap all vml nodes in a group node
- wrap the Raphael constructor up so that the vml group node is passed to the Raphael constructor
- alter a few css properties when the paper is resized to deal with centering, clipping and maintaining the correct aspect ratio.
Any feedback would be greatly appreciated.