像SWF一样缩放SVG(Raphael.js)

20

我几天前开始使用Raphael.js,非常喜欢它。唯一让我困惑的是如何使“paper”或svg / vml标签填充浏览器窗口,就像swf一样。 参见此示例。

注意上面示例随浏览器窗口大小调整的方式

我能够使“paper”随浏览器窗口调整大小,但无法让所有的矢量图形调整大小。如果有任何反馈,将不胜感激。

编辑

我尝试了多种不同的方法。 viewBox非常好用,但它只适用于SVG。我刚刚通过Raphael集和window.onresize事件上的一些代码来解决了这个问题。今晚或明天我会发布我的发现。如果还有其他解决方案,我仍然很想看到它们。

5个回答

37

我花了一段时间才想出了解决这个问题的方法。 我将解决方案包装在一个小的js文件中,可与Raphael一起使用。您可以在此处获取js文件以及一些简单的文档(链接)在此处查看其操作

它是如何工作的:

  1. 为svg使用viewBox
  2. 将所有vml节点包装在组节点中
  3. 将Raphael构造函数包装起来,以便将vml组节点传递给Raphael构造函数
  4. 当画布大小调整时,更改一些CSS属性以处理居中、裁剪和维护正确的纵横比。

非常感谢您的任何反馈。


你只能拥有一个ScaleRaphael的实例吗?我正在将.svg文件制作成缩略图。原始的.svg文件大约是400x400像素,但缩略图大小为75x75像素。我一直在为每个缩略图使用唯一的Raphael( container_id )实例。但是当我切换到new ScaleRaphael( container_id , 75, 75)时,所有的缩略图都被合并成一个视觉元素。 - dsdsdsdsd

7

你好,Zévan,

我找到了一个不错的答案,由一个叫做Zevan的人制作。然而,我发现这段代码过于复杂(需要jquery,使用诸如“$(this)”之类的奇怪语法等)。

因此,我对它进行了简化。现在它足够短,可以适应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;
}

你的版本唯一的缺点是它需要SVG,而不支持VML。这会成为一个问题吗?

我正在使用你演示页面的简化版本:

<!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>


我知道你没有做VML支持,这就是为什么你的调整大小函数没有为IE设置吗?对我来说,Raphael的一个重要部分是VML支持...因此,窗口调整大小方法需要在IE中工作。 - Zevan
1
非常棒的答案和代码。这刚刚为我节省了大量的试错时间。谢谢! - Adam Crossland

2
这可能是一个过时的线程,但至少 Raphael 2.0 有一个 setViewBox 方法 -- http://raphaeljs.com/reference.html#Paper.setViewBox。你仍然需要将实际画布大小设置为 100%,以便 容器 缩放到窗口大小,但在 window.resize 回调中调用 setViewBox 并传入适当的 w/h 值即可解决问题。

这是一个同样古老的随机示例,演示如何使用setViewBox在鼠标滚轮上进行“缩放”- http://jsfiddle.net/9zu4U/2/ - drzaus

2
您可以循环遍历所有路径,并根据重新调整大小后纸张的新比例对它们进行缩放。

3
原来如果使用集合并执行myset.scale(2,2,0,0),就不需要循环了。 - Zevan
@Zeven 很有趣!当我使用raphaël时,我没有研究过集合。 - Gipsy King
我说得太早了。不幸的是,如果你缩放一组对象,坐标系就不会被保留,这可能会破坏任何正在进行的动画。这意味着 cx 和 cy 会根据比例尺变化而改变。我很确定如果 Raphael 使用 transform() SVG 功能,这个问题可以避免。不确定为什么要手动完成缩放,而不是使用内置的 SVG 功能。也许这与代码易于与 VML 兼容有关。我将继续研究它。最坏的情况下,我会编写某种插件。 - Zevan

2

好的,我会试一下,并且会研究VML方面的事情。 - Zevan
这真的非常有效。在VML中的等效方法似乎是将所有对象都包装在一个组节点中。我这样做了,它实际上运行得很好。唯一的问题是Raphael无法再填充或样式化对象了。我猜这是由于对VML结构的更改所致。 - Zevan
我猜在IE中,纸张的宽度和高度可以设置为一个表达式,该表达式计算父元素的尺寸。 - Spadar Shut

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接