使用Javascript将绝对值转换为相对CSS值

时间:2013-07-16 18:36:15

标签: javascript html css svg

我想知道使用Javascript将绝对CSS值转换为相对的同时保持比例是否可行和可行。解决方案必须使用HTML和SVG标记。

说你得到了这个:

<div style="width:100%;height:800px">
  <svg width="1000" height="500">
    <rect width="30" height="50" x="34" y="24"/>
  </svg>
</div>

你将如何实现这一目标?

<div style="width:100%;height:100%">
  <svg width="83%" height="62.5%">
    <rect width="3%" height="10%" x="3.4% y="4.8%"/>
  </svg>
</div>

  1. 从根元素(div
  2. 开始
  3. 获取.width()的{​​{1}}和.height()以及父元素
  4. 计算比例(this
  5. 相应地设置宽度和高度
  6. 遍历子项,将子项设置为root,从1开始。
  7. 可能发生的常见陷阱是什么?可能有标签没有设置宽度或高度,例如this_height/parent_height*100。然后是svg:g中的非标准尺寸定义或者您最初没有考虑的属性,例如svg:circle s svg:text。有没有办法对由于大规模回流造成的性能损失进行有根据的猜测?还有什么?

    非常感谢!

1 个答案:

答案 0 :(得分:2)

确定。所以这就是我所理解的,你想用自己的话来做。

  

循环遍历所有转换绝对尺寸的DOM元素(即   相对尺寸的高度/宽度(以像素计))   以百分比表示的高度/宽度)。这应该用   是否使用CSS或HTML设置维度的敏感性   属性,以便可用于SVG元素。

话虽如此,但有一个主要约束:如果要使用<x>作为根元素将绝对尺寸转换为相对尺寸,则<x>必须具有绝对尺寸。否则,容器内的相对尺寸将根据其内容而不是父<x>的整体大小来更改大小。

根据这个规定,你要问的是相当容易的。这是需要使用的算法。

  1. <body>
  2. 开始
  3. 提供<body>固定尺寸
  4. <body>执行DOM树,为每个元素执行以下操作
    1. 获取元素的尺寸
    2. 获取父级维度
    3. 转换为相对尺寸(即宽度/父宽度)。
    4. 应用相对尺寸
  5. 为了测试我的代码,我使用了以下HTML。它包含您包含的代码和子元素大于其父元素的实例。这是一个我认为是要测试的边界条件的案例。

    <div style="width:100%;height:800px">
      <svg width="150" height="200" style="background: red;">
        <rect width="30" height="50" x="34" y="24"/>
      </svg>
    
      <div style="background: green; width: 50px; height: 50px;">
          <p style="background: teal; width: 100px; height: 20px;">Content</p>
      </div>
    </div>
    

    这是JavaScript。它评论得相当好,并提供了不错的控制台输出。对于生产代码,我建议建议删除控制台日志记录。

    请记住,代码不会立即执行,但延迟时间为2秒。通过这种方式,您可以看到DOM在修改之前的外观。

    对于那些不知道以下代码的人,如果它存在则返回a而不是false,否则返回b

    foo = a || b;
    

    我们可以像下面两个中的一个那样重写,但这更简洁。

    foo = a ? a : b;
    
    if(a)
        foo = a
    else
        foo = b
    

    这是jsFiddle

    代码!

    /** convertToRelative
     * Convert absolute width/height to relative. Should work for
     * Both HTML and SVG objects. Tries to use CSS attributes, falls
     * back on HTML attributes.
     */
    function convertToRelative(element) {
        // Get Element and Parent
        element = $(element);
        parent  = element.parent();
    
        // If there is no valid with, we need to use attributes
        var useAttr   = !element.width();
    
        // Get dimensions from css or attributes
        var width     = element.width()  || element.attr('width');
        var height    = element.height() || element.attr('height');
        var pWidth    = parent.width()   || parent.attr('width');
        var pHeight   = parent.height()  || parent.attr('height');
    
        // Find relative dimensions
        var relWidth  = (width  / pWidth)  * 100.0;
        var relHeight = (height / pHeight) * 100.0;
    
        // Log info
        console.log(element);
        console.log("1: "+ parent.height() +", 2: "+ parent.attr('height'));
        console.log("Width: "+ width +", Height: "+ height);
        console.log("PWidth: "+ pWidth +", pHeight: "+ pHeight);
        console.log("relWidth: "+ relWidth +", relHeight: "+ relHeight);
    
        // Clear current stylings
        element.removeAttr('width');
        element.removeAttr('height');
    
        // Apply relative dimensions
        if (useAttr) {
            element.attr('width', relWidth +'%');
            element.attr('height', relHeight +'%');
        } else {
            element.width(relWidth +"%");
            element.height(relHeight +"%");
        }
    }
    
    /** walk
     * Walk through a DOM element and all its sub elements running
     * the convertToRelative function to convert absolute positions
     * to relative positions.
     * DOES NOT CONVERT THE FIRST ELEMENT, ONLY CHILDREN.
     */
    function walk(element) {
        $(element).children().each(function() {
            convertToRelative(this);
            walk(this);
        });
    }
    
    /** fixBody
     * In order to play with relative dimensions for children of the
     * body, we need to fix the dimensions of the body. Otherwise it
     * will resize as we begin to use relative dimensions.
     */
    function fixBody() {
        $('body').css('width', $('body').width() +"px");
        $('body').css('height', $('body').height() +"px");
    }
    
    // Walk the body and all children on a 2 second delay.
    setTimeout(function() {
        console.log('Running Conversion');
        fixBody()
        walk('body');
        console.log('Conversion Finished');
    }, 2000);
    

    如果这不是您想要的,或者您遇到问题,请告诉我!

    提出您的问题

      

    可能发生的常见陷阱是什么?

    最常见的陷阱是转换不正确。转换中出现问题,生成的DOM看起来就像输入一样。

      

    可能有标签没有设置宽度或高度,例如svg:g。然后有非标准的大小定义,比如svg:circle或你最初没想过的属性,比如svg:texts dy。

    有些标签没有width / height元素。但是,使用jQuery应该会让我们在这个部门更加健壮。我没有使用jQuery和SVG,但是如果我们遇到更多模糊元素的任何问题,我们就会有一个支持插件。

      

    有没有办法对由于大规模回流造成的性能损失进行有根据的猜测?

    我相信此代码将在O(m * n) m = delay for a single reflown = number of nodes中运行。 Reflows应该有一个相当一致的变化,因为我们正在转换最小元素之前的最大元素。 但是在最后一句话中我可能被证明是错误的。

      

    还有什么?

    Success!