Zrobiłem coś podobnego podczas tworzenia strony związanej z CSS . Musiałem porównać dane wyjściowe wygenerowane przez HTML / CSS z obrazem, który został wcześniej wygenerowany za pomocą HTML / CSS.
Użyłem dom-to-image , który konwertuje kod na obraz zakodowany w standardzie base64. Umieszczam ten obraz w obszarze roboczym, a następnie używam dopasowania pikseli, aby porównać oba obrazy.
Oto przykład ilustrujący:
var node1 = document.querySelector("pre");
var node2 = document.querySelector(".div");
var canvas1 = document.querySelector(".first");
var canvas2 = document.querySelector(".second");
var ctx1 = canvas1.getContext("2d");
var ctx2 = canvas2.getContext("2d");
/* Change both code to Image and put inside Canvas */
domtoimage.toPng(node1)
.then(function(dataUrl) {
var image = new Image();
image.onload = function() {
ctx1.drawImage(this, 0, 0);
};
image.src = dataUrl;
})
domtoimage.toPng(node2)
.then(function(dataUrl) {
var image = new Image();
image.onload = function() {
ctx2.drawImage(this, 0, 0);
};
image.src = dataUrl;
})
/* Run the pixel matching*/
setTimeout(function() {
var im_r = ctx1.getImageData(0, 0, 300, 300).data;
var im_o = ctx2.getImageData(0, 0, 300, 300).data;
var pixDiff = pixelmatch(im_r, im_o, false, 280, 280, {
threshold: 0.1
});
console.log(pixDiff);
}, 3000);
canvas {
border: 1px solid;
}
pre,
.div {
border: 2px solid red;
width: 300px;
height: 300px;
box-sizing: border-box;
margin: 0;
}
<script type="text/javascript" src="https://css-challenges.com/wp-content/themes/ronneby_child/js/dom-to-image.js"></script>
<script type="text/javascript" src="https://css-challenges.com/wp-content/themes/ronneby_child/js/pixel.js"></script>
<pre>
sun<br/>
mercury <br/>
venus <br/>
earth <br/>
mars <br/>
jupiter <br/>
saturn <br/>
</pre>
<div class="div" style="font-family:monospace">
<div style="text-indent: 0">sun</div> <br/>
<div style="text-indent: 4ch">mercury</div> <br/>
<div style="text-indent: 4ch">venus</div> <br/>
<div style="text-indent: 8ch">earth</div> <br/>
<div style="text-indent: 8ch">mars</div> <br/>
<div style="text-indent: 12ch">jupiter</div> <br/>
<div style="text-indent: 4ch">saturn</div> <br/>
</div>
<canvas width="300" height="300" class="first"></canvas>
<canvas width="300" height="300" class="second"></canvas>
W powyższym kodzie mamy 2 bloki HTML i 2 płótna, na których będziemy malować nasze bloki. Jak widać, JS jest dość prosty. Kod na końcu uruchamia dopasowanie pikseli i pokazuje, ile różnych pikseli mają oba płótna. Dodałem opóźnienie, aby upewnić się, że oba obrazy są załadowane (możesz zoptymalizować później w przypadku niektórych zdarzeń)
Możesz również rozważyć trzecie płótno, aby podkreślić różnicę między oboma obrazami i uzyskać różnicę wizualną:
var node1 = document.querySelector("pre");
var node2 = document.querySelector(".div");
var canvas1 = document.querySelector(".first");
var canvas2 = document.querySelector(".second");
var canvas3 = document.querySelector(".result");
var ctx1 = canvas1.getContext("2d");
var ctx2 = canvas2.getContext("2d");
var ctx3 = canvas3.getContext("2d");
/* Change both code to Image and put inside Canvas */
domtoimage.toPng(node1)
.then(function(dataUrl) {
var image = new Image();
image.onload = function() {
ctx1.drawImage(this, 0, 0);
};
image.src = dataUrl;
})
domtoimage.toPng(node2)
.then(function(dataUrl) {
var image = new Image();
image.onload = function() {
ctx2.drawImage(this, 0, 0);
};
image.src = dataUrl;
})
/* Run the pixel matching*/
setTimeout(function() {
var im_r = ctx1.getImageData(0, 0, 300, 300).data;
var im_o = ctx2.getImageData(0, 0, 300, 300).data;
var diff = ctx3.createImageData(300, 300);
var pixDiff = pixelmatch(im_r, im_o, diff.data, 300, 300, {
threshold: 0.1
});
ctx3.putImageData(diff, 0, 0);
console.log(pixDiff);
}, 3000);
canvas {
border: 1px solid;
}
pre,
.div {
border: 2px solid red;
width: 300px;
height: 300px;
box-sizing: border-box;
margin: 0;
}
<script type="text/javascript" src="https://css-challenges.com/wp-content/themes/ronneby_child/js/dom-to-image.js"></script>
<script type="text/javascript" src="https://css-challenges.com/wp-content/themes/ronneby_child/js/pixel.js"></script>
<pre>
sun<br/>
mercury <br/>
venus <br/>
earth <br/>
mars <br/>
jupiter <br/>
saturn <br/>
</pre>
<div class="div" style="font-family:monospace">
<div style="text-indent: 0">sun</div> <br/>
<div style="text-indent: 4ch">mercury</div> <br/>
<div style="text-indent: 4ch">venus</div> <br/>
<div style="text-indent: 8ch">earth</div> <br/>
<div style="text-indent: 8ch">mars</div> <br/>
<div style="text-indent: 12ch">jupiter</div> <br/>
<div style="text-indent: 4ch">saturn</div> <br/>
</div>
<canvas width="300" height="300" class="first"></canvas>
<canvas width="300" height="300" class="second"></canvas>
<canvas width="300" height="300" class="result"></canvas>
Zmieńmy zawartość, aby zobaczyć różnicę:
var node1 = document.querySelector("pre");
var node2 = document.querySelector(".div");
var canvas1 = document.querySelector(".first");
var canvas2 = document.querySelector(".second");
var canvas3 = document.querySelector(".result");
var ctx1 = canvas1.getContext("2d");
var ctx2 = canvas2.getContext("2d");
var ctx3 = canvas3.getContext("2d");
/* Change both code to Image and put inside Canvas */
domtoimage.toPng(node1)
.then(function(dataUrl) {
var image = new Image();
image.onload = function() {
ctx1.drawImage(this, 0, 0);
};
image.src = dataUrl;
})
domtoimage.toPng(node2)
.then(function(dataUrl) {
var image = new Image();
image.onload = function() {
ctx2.drawImage(this, 0, 0);
};
image.src = dataUrl;
})
/* Run the pixel matching*/
setTimeout(function() {
var im_r = ctx1.getImageData(0, 0, 300, 300).data;
var im_o = ctx2.getImageData(0, 0, 300, 300).data;
var diff = ctx3.createImageData(300, 300);
var pixDiff = pixelmatch(im_r, im_o, diff.data, 300, 300, {
threshold: 0.1
});
ctx3.putImageData(diff, 0, 0);
console.log(pixDiff);
}, 3000);
canvas {
border: 1px solid;
}
pre,
.div {
border: 2px solid red;
width: 300px;
height: 300px;
box-sizing: border-box;
margin: 0;
}
<script type="text/javascript" src="https://css-challenges.com/wp-content/themes/ronneby_child/js/dom-to-image.js"></script>
<script type="text/javascript" src="https://css-challenges.com/wp-content/themes/ronneby_child/js/pixel.js"></script>
<pre>
sun<br/>
mercury <br/>
venus <br/>
earth <br/>
mars <br/>
jupiter <br/>
saturn <br/>
</pre>
<div class="div" style="font-family:monospace">
<div style="text-indent: 0">sun</div> <br/>
<div style="text-indent: 4ch">mercury</div> <br/>
<div style="text-indent: 4ch">venus</div> <br/>
<div style="text-indent: 8ch">earth</div> <br/>
<div style="text-indent: 8ch">april</div> <br/>
<div style="text-indent: 12ch">jupiter</div> <br/>
<div style="text-indent: 4ch">saturn</div> <br/>
</div>
<canvas width="300" height="300" class="first"></canvas>
<canvas width="300" height="300" class="second"></canvas>
<canvas width="300" height="300" class="result"></canvas>
Możesz przeczytać więcej o tym, jak działają dwie używane przeze mnie wtyczki i znaleźć bardziej interesujące opcje.
Naprawiam rozmiary do 300 x 300, aby ułatwić demonstrację we fragmencie, ale możesz rozważyć większą wysokość i szerokość.
Aktualizacja
Oto bardziej realistyczny przykład porównania dwóch układów, które dają ten sam wynik. Szerokość / wysokość płótna będzie dynamiczna i oparta na treści. Z różnicą pokażę tylko ostatnie płótno.
var node1 = document.querySelector(".flex");
var node2 = document.querySelector(".grid");
var canvas1 = document.querySelector(".first");
var canvas2 = document.querySelector(".second");
var canvas3 = document.querySelector(".result");
canvas1.height= node1.offsetHeight;
canvas2.height= node2.offsetHeight;
canvas3.height= node1.offsetHeight;
canvas1.width= node1.offsetWidth;
canvas2.width= node2.offsetWidth;
canvas3.width= node1.offsetWidth;
var ctx1 = canvas1.getContext("2d");
var ctx2 = canvas2.getContext("2d");
var ctx3 = canvas3.getContext("2d");
domtoimage.toPng(node1)
.then(function(dataUrl) {
var image = new Image();
image.onload = function() {
ctx1.drawImage(this, 0, 0);
};
image.src = dataUrl;
})
domtoimage.toPng(node2)
.then(function(dataUrl) {
var image = new Image();
image.onload = function() {
ctx2.drawImage(this, 0, 0);
};
image.src = dataUrl;
})
setTimeout(function() {
var im_r = ctx1.getImageData(0, 0, canvas1.width, canvas1.height).data;
var im_o = ctx2.getImageData(0, 0, canvas1.width, canvas1.height).data;
var diff = ctx3.createImageData(canvas1.width, canvas1.height);
var pixDiff = pixelmatch(im_r, im_o, diff.data, canvas1.width, canvas1.height, {
threshold: 0.2
});
ctx3.putImageData(diff, 0, 0);
console.log(pixDiff);
}, 3000);
.grid {
display:grid;
grid-template-columns:repeat(3,minmax(0,1fr));
border:2px solid red;
}
h1 {
text-align:center;
grid-column:1/-1;
flex-basis:100%;
}
.flex {
display:flex;
flex-wrap:wrap;
border:2px solid red;
}
.flex > div {
flex-grow:1;
flex-basis:0;
}
<script type="text/javascript" src="https://css-challenges.com/wp-content/themes/ronneby_child/js/dom-to-image.js"></script>
<script type="text/javascript" src="https://css-challenges.com/wp-content/themes/ronneby_child/js/pixel.js"></script>
<div class="grid">
<h1>A title here</h1>
<div>
<img src="https://picsum.photos/id/10/200/200" >
</div>
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus aliquam condimentum mollis. Phasellus faucibus diam quis lorem efficitur, id egestas neque malesuada</div>
<div> Maecenas sollicitudin lacinia finibus. Integer vel varius eros. Morbi et ante eget est mollis sollicitudin.</div>
</div>
<div class="flex">
<h1>A title here</h1>
<div>
<img src="https://picsum.photos/id/10/200/200" >
</div>
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus aliquam condimentum mollis. Phasellus faucibus diam quis lorem efficitur, id egestas neque malesuada</div>
<div> Maecenas sollicitudin lacinia finibus. Integer vel varius eros. Morbi et ante eget est mollis sollicitudin.</div>
</div>
<canvas width="300" height="300" class="first" style="display:none;"></canvas>
<canvas width="300" height="300" class="second" style="display:none;"></canvas>
<canvas width="300" height="300" class="result"></canvas>
Użyjmy innego obrazu:
var node1 = document.querySelector(".flex");
var node2 = document.querySelector(".grid");
var canvas1 = document.querySelector(".first");
var canvas2 = document.querySelector(".second");
var canvas3 = document.querySelector(".result");
canvas1.height= node1.offsetHeight;
canvas2.height= node2.offsetHeight;
canvas3.height= node1.offsetHeight;
canvas1.width= node1.offsetWidth;
canvas2.width= node2.offsetWidth;
canvas3.width= node1.offsetWidth;
var ctx1 = canvas1.getContext("2d");
var ctx2 = canvas2.getContext("2d");
var ctx3 = canvas3.getContext("2d");
domtoimage.toPng(node1)
.then(function(dataUrl) {
var image = new Image();
image.onload = function() {
ctx1.drawImage(this, 0, 0);
};
image.src = dataUrl;
})
domtoimage.toPng(node2)
.then(function(dataUrl) {
var image = new Image();
image.onload = function() {
ctx2.drawImage(this, 0, 0);
};
image.src = dataUrl;
})
setTimeout(function() {
var im_r = ctx1.getImageData(0, 0, canvas1.width, canvas1.height).data;
var im_o = ctx2.getImageData(0, 0, canvas1.width, canvas1.height).data;
var diff = ctx3.createImageData(canvas1.width, canvas1.height);
var pixDiff = pixelmatch(im_r, im_o, diff.data, canvas1.width, canvas1.height, {
threshold: 0.2
});
ctx3.putImageData(diff, 0, 0);
console.log(pixDiff);
}, 3000);
.grid {
display:grid;
grid-template-columns:repeat(3,minmax(0,1fr));
border:2px solid red;
}
h1 {
text-align:center;
grid-column:1/-1;
flex-basis:100%;
}
.flex {
display:flex;
flex-wrap:wrap;
border:2px solid red;
}
.flex > div {
flex-grow:1;
flex-basis:0;
}
<script type="text/javascript" src="https://css-challenges.com/wp-content/themes/ronneby_child/js/dom-to-image.js"></script>
<script type="text/javascript" src="https://css-challenges.com/wp-content/themes/ronneby_child/js/pixel.js"></script>
<div class="grid">
<h1>A title here</h1>
<div>
<img src="https://picsum.photos/id/10/200/200" >
</div>
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus aliquam condimentum mollis. Phasellus faucibus diam quis lorem efficitur, id egestas neque malesuada</div>
<div> Maecenas sollicitudin lacinia finibus. Integer vel varius eros. Morbi et ante eget est mollis sollicitudin.</div>
</div>
<div class="flex">
<h1>A title here</h1>
<div>
<img src="https://picsum.photos/id/12/200/200" >
</div>
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus aliquam condimentum mollis. Phasellus faucibus diam quis lorem efficitur, id egestas neque malesuada</div>
<div> Maecenas sollicitudin lacinia finibus. Integer vel varius eros. Morbi et ante eget est mollis sollicitudin.</div>
</div>
<canvas width="300" height="300" class="first" style="display:none;"></canvas>
<canvas width="300" height="300" class="second" style="display:none;"></canvas>
<canvas width="300" height="300" class="result"></canvas>