Scaling SVG (Raphael.js) like an SWF

后端 未结 5 761
[愿得一人]
[愿得一人] 2020-12-12 16:43

I started using Raphael.js a few days ago and I\'m really enjoying it. The only thing I haven\'t been able to figure out is how to get the \"paper\" or svg/vml tag to fill t

相关标签:
5条回答
  • 2020-12-12 17:10

    You could loop over all paths and scale() them acording to the new scale of the paper after resizing it.

    0 讨论(0)
  • 2020-12-12 17:15

    This might just be too old of a thread, but Raphael 2.0 at least has a setViewBox method -- http://raphaeljs.com/reference.html#Paper.setViewBox

    You'll still need to set the actual canvas size to 100%, so the container scales to the window, but calling setViewBox with appropriate w/h in your window.resize callback should do the trick.

    0 讨论(0)
  • 2020-12-12 17:25

    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:

    1. use viewBox for svg
    2. wrap all vml nodes in a group node
    3. wrap the Raphael constructor up so that the vml group node is passed to the Raphael constructor
    4. 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.

    0 讨论(0)
  • 2020-12-12 17:31

    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>
    

    0 讨论(0)
  • 2020-12-12 17:32

    You could add a 'viewBox' attribute on the svg root element to define the coordinate system, the shapes will then scale to whatever the size of the container is. Not sure how to deal with the VML side of things though. I'd suggest reporting an issue for it, https://github.com/DmitryBaranovskiy/raphael/issues.

    0 讨论(0)
提交回复
热议问题