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

Python & Ctypes: Passing a struct to a function as a pointer to get back data

python pointers struct ctypes

I've looked through other answers but can't seem to get this to work. I'm trying to call a function within a DLL for communicating with SMBus devices. This function takes a pointer to a struct, whi...