使用jquery(和|或)与Canvas比较两个HTML元素视图

时间:2013-05-02 06:42:14

标签: javascript jquery webkit html5-canvas

我的文字DIV如下。我只针对非IE和webkit浏览器。

一:

<div id="target1"> Some<sup>en</sup> <i><b>text</b></i> </div>

上面这一行看起来像:带有样式的 en 文字

第二:

<div id="target2"> Some<sup>en</sup> <span class='boldIt'>text</span></div>
.boldIt{
   font-weight : bold;
   font-style : italic;
}

它与上面相同。根据观点两者都是一样的。 但下面与上面不同

<div id="target3"> Someen text</div>

我的要求是比较三个目标元素。

我尝试了什么: 我已经尝试迭代DIV的每个子节点并使用getComputedStyle()匹配样式。但我可以在页面上看到一个巨大的性能混蛋。因为涉及的案件很多。

有一个想法,但无奈,这是一个IDEA 在画布上绘制两个元素并比较两个画布,比如比较两个图像。这真的有可能吗?如果可能,当我将一个内联元素与块级元素进行比较时,它是否会改变比较的行为?

请建议我这个。如果没有想法,我会像以前提到的那样坚持HTML方式。

我已尝试使用画布this,而我的目标只是Chrome。安东尼的答案完全符合我的要求。但在下面的情况下,我找不到办法做到这一点

for(var i = 0; i < arr.length; i++){
  var htStr = arr[i].one, htStr2 = arr[i].two;
  // How can I match these two now...
} 

2 个答案:

答案 0 :(得分:3)

您可以使用<canvas>

请参阅 DEMO (在Chrome,Safari和Opera上测试过)。

您可以使用html2canvas将以下内容转换为3个不同的画布,并比较它们的base64字符串以确定它们在视觉上是否相同。您应该将它们包装在单独的容器中,以便所有文本都在画布中呈现。

<div id="target1-container">
    <div id="target1"> Some<sup>en</sup> <i><b>text</b></i> </div>
</div>
<div id="target2-container">
    <div id="target2"> Some<sup>en</sup> <span class='boldIt'>text</span></div>
</div>
<div id="target3-container">
    <div id="target3"> Someen text</div>
</div>

转换为canvas和base64字符串,使用async.js处理多个异步调用:

async.parallel({
    target1: function (callback) {
        html2canvas(document.getElementById("target1-container"), {
            onrendered: function (canvas) {
                callback(null, canvas.toDataURL());
            }
        });
    },
    target2: function (callback) {
        html2canvas(document.getElementById("target2-container"), {
            onrendered: function (canvas) {
                callback(null, canvas.toDataURL());
            }
        });
    },
    target3: function (callback) {
        html2canvas(document.getElementById("target3-container"), {
            onrendered: function (canvas) {
                callback(null, canvas.toDataURL());
            }
        });
    }
},
function (err, results) {
    console.log(results);
});

关于您更新的问题,这里是一个比较字符串定义的元素的视觉外观的函数:

function compare(arr, fn) {
    // create test div
    var testdiv = document.createElement("div");
    testdiv.style.marginTop = '1000px';
    document.body.appendChild(testdiv);
    async.map(
        arr,
        function (data, callback) {
            var htStr = data.one,
                htStr2 = data.two;
            // create elements from strings
            var el = document.createElement("div"),
                el2 = document.createElement("div");
            el.innerHTML = htStr;
            testdiv.appendChild(el);
            el2.innerHTML = htStr2;
            testdiv.appendChild(el2);
            // convert to canvas and base64 strings
            async.parallel([
                function (callback) {
                    html2canvas(el, {
                        onrendered: function (canvas) {
                            callback(null, canvas.toDataURL());
                        }
                    });
                },
                function (callback) {
                    html2canvas(el2, {
                        onrendered: function (canvas) {
                            callback(null, canvas.toDataURL());
                        }
                    });
                }
            ],
            // start comparison
            function (err, results) {
                if (results[0] === results[1]) {
                    callback(null, true);
                } else {
                    callback(null, false);
                }
            });
        },
        // callback function
        function (err, results) {
            document.body.removeChild(testdiv);
            if (typeof fn === 'function') {
                fn(results);
            }
        }
    );
}
// elements to be tested
var arr = [];
arr.push({
    one: '<div id="target1"> Some<sup>en</sup> <i><b>text</b></i> </div>',
    two: '<div id="target2"> Some<sup>en</sup> <span class="boldIt">text</span></div>'
});
arr.push({
    one: '<div id="target1"> Some<sup>en</sup> <i><b>text</b></i> </div>',
    two: '<div id="target3"> Someen text</div>'
});
// let the test begin
compare(arr, function (result) {
    console.log(result);
});

它在回调函数中返回一个数组,带

  • true表示元素在视觉上相同,
  • false意味着他们与众不同。

请参阅this DEMO中的控制台。

答案 1 :(得分:1)

我假设通过“比较”你指的是检测元素是否在像素级别上相同地呈现。请注意,这个条件可以通过词汇基础上完全不相等的元素来满足;相反,由于许多因素,特别是从父母继承的属性,两个元素可以在词法上相同但呈现不同。您还需要考虑这样一个事实,即包含其包含矩形的像素意义上的元素的像素表示可能被页面上其他位置的某些东西污染;明显的例子是具有固定位置的元素。

鉴于上述所有情况,由于我们将等值定义为像素级等价,因此答案确实是要对要比较的元素进行“快照”并进行比较。最简单的方法是使用无头网络浏览器,如PhantomJS。我不会提供完整的程序,但这里有基础知识:

  1. page.evaluate函数中,使用getBoundingClientRect获取相关元素的维度。

  2. 然后使用window.callPhantom回调PhantomJS。这将调用使用page.onCallBack定义的函数。

  3. 在回调中,将page.clipRect设置为您要捕获的项目的尺寸。然后使用类似page.renderBase64的内容来捕获图像,并将结果存储为文件。

  4. 重复您要比较的其他元素。

  5. 将存储的base64图像与字节级等效进行比较。