Render ontop
Самый быстрый способ - использовать два холста.Один содержит все изображение и находится за пределами экрана, другой - холст дисплея.
Изображения отображаются на внеэкранном холсте как обычно.Затем, когда изображение будет готово, вы очистите экранный холст, нарисуете на нем холст за пределами экрана, затем нарисуйте выделенный элемент поверх него.
Это избавит вас от необходимости сортировать и перерисовывать все изображения только дляприведите один к вершине.
Пример
Демо показывает, что это сделано.Вместо того, чтобы найти кучу изображений, я создаю изображения через холст.Интересующий код - это только верхняя функция displayLoop
При необходимости он находит самое близкое изображение к мыши. Если это новое изображение, оно очищает холст, рисует холст offScreen
, а затем ближайшее изображение сверху.
Примечание: этот метод немного увеличит контрастность края для некоторых изображений.
requestAnimationFrame(displayLoop);
document.addEventListener("mousemove", mouseEvents);
const numImages = 100;
const ctx = canvas.getContext("2d");
const offScreen = createImage(512,true);
const offCtx = offScreen.getContext("2d");
var lastImage;
function displayLoop(){
if (images.length === 0) { createAllImages() }
if (mouse.update) {
mouse.update = false;
const img = images.getClosest(mouse.x, mouse.y);
if(img !== lastImage) {
ctx.clearRect(0,0,512,512);
ctx.drawImage(offScreen,0,0);
img.draw(ctx);
lastImage = img;
}
}
requestAnimationFrame(displayLoop);
}
/* Code below is support code not related directly to the answer */
const mouse = {x : 0, y : 0, update : true};
function mouseEvents(e){
const bounds = canvas.getBoundingClientRect();
mouse.x = e.pageX - bounds.left - scrollX;
mouse.y = e.pageY - bounds.top - scrollY;
mouse.update = true;
}
function createAllImages(){
var i = numImages;
while(i--){ images.add() }
images.draw(offCtx);
}
function createImage(size, noDraw = false){
const img = document.createElement("canvas");
img.width = size;
img.height = size;
if (noDraw) { return img }
const ctx = img.getContext("2d");
ctx.lineWidth = 4;
ctx.fillStyle = "#" + ((0x1000000+(Math.random() * 0xFFFFFF | 0)).toString(16).substr(1));
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 2 - 3, 0, Math.PI * 2);
ctx.stroke();
ctx.fill();
return img;
}
const image = {
pos : {x: 0, y: 0},
img : null,
init(){
this.img = createImage(Math.random() * 64 + 64 | 0);
this.pos ={ x : Math.random() * canvas.height | 0, y : Math.random() * canvas.width | 0 };
return this;
},
draw(ctx) { ctx.drawImage(this.img, this.pos.x- this.img.width / 2, this.pos.y-this.img.height / 2) },
distTo(x, y) { return ((x - this.pos.x) ** 2 + (y - this.pos.y) ** 2) ** 0.5 }
}
const images = Object.assign([],{
add() { this.push({...image}.init()) },
each(cb) { var index = 0; for(const item of this) { cb(item,index++) } },
getClosest(x, y) {
var minDist = Infinity;
var minIndex = -1;
this.each((img, i) => {
const dist = img.distTo(x, y);
if(dist < minDist){
minDist = dist;
minIndex = i;
}
});
return this[minIndex];
},
draw(ctx){ this.each(img=>img.draw(ctx)) }
})
<canvas id="canvas" width="512" height="512"></canvas>