Compare two HTML elements view using jquery (and | or) with Canvas

I have text DIV's like below. I am targeting only non IE and webkit browsers.

One :

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

The above line looks like : Someen text with style

Second :

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

It looks same as above. According to view both are same. But below is different from above

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

My requirement is to compare three target elements.

What I have tried: I have tried iterating through each child node of DIV and and matching styles using getComputedStyle(). But I could see a big performance jerk happening on page. Because there are so many cases involved in this.

Have an idea, but helpless, Here is an IDEA Draw two elements on canvas and compare two canvas like comparing two images. Is this really possible? If possible when I am comparing one inline element with block level element, does it change the behavior of comparison?

Please suggest me on this. If no ideas I would stick to HTML way as I have mentioned before.

I have tried this using canvas and my target is only Chrome. Antony's answer is exactly matching with my requirement. But in below case I could not find a way to do that

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

Answers


Your idea of using a <canvas> is possible.

See DEMO (tested on Chrome, Safari and Opera).

You can convert the following into 3 different canvases using html2canvas, and compare their base64 string to determine if they are visually the same. You should wrap them in separate containers so that all the texts are rendered in the canvases.

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

Converting to canvas and base64 strings, using async.js to handle multiple asynchronous calls:

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);
});

Regarding your updated question, here's a function to compare the visual appearance of elements defined by the strings:

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);
});

It returns an array in a callback function, with

  • true meaning the elements being visually the same, and
  • false meaning they being different.

See the console in this DEMO.


Need Your Help

how to change cron table from svn?

git unix svn cron crontab

is there a way to update cron table with a file from svn or git?

Changing nested attribute with model.set in Backbone

javascript json backbone.js marionette backbone-model

I'm trying to do what I hope is a simple thing -- doing a model.set only on a sub attribute of the object.

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.