Страницы

Поиск по вопросам

понедельник, 1 октября 2018 г.

Какой алгоритм используется для отображения нескольких фото в виде мозаики?

Например, как в ВК при загрузке фотографий. Речь идет о таком отображении:

UPD: Возможно, для вывода изображения используется алгоритм TreeMap. Но не ясно, как задавать "веса" изображениям.


Ответ

Алгоритм с сохранением порядка следования картинок.
Определяем количество строк как sqrt( сумма отношений сторон всех картинок / отношение сторон блока ), где отношение сторон определяется как ширина делённая на высоту. Определяем высоту строки как высоту блока делённую на число строк. Определяем общую длину всех картинок масштабированных к высоте строки. Заполняем строки так чтобы ширина строки была максимально приближена к ширине оставшихся картинок делённой на количество оставшихся строк. Перераспределяем высоты строк. Для этого для каждой строки считаем новую высоту так, чтобы ширина строки стала равной ширине блока. разности между новыми и старыми высотами строк суммируем отдельно по переполненным и недозаполненным строкам. В зависимости от того какая разность больше пропорционально уменьшаем изменения высот в одной из этих групп, чтобы эти суммы сравнялись. (Галочка в примере отменяет последнее выравнивание, что позволяет сохранить соотношения сторон картинок, но нарушает высоту блока). Для строк у которых осталось свободное пространство (до ширины блока) масштабируем картинки так, чтобы занять всю ширину блока, после чего обрезаем их по высоте с центрированием по вертикали. В строках, где нет свободного пространства масштабируем картинки так, чтобы их высота была равна высоте строки, и обрезаем их по ширине с центрированием по горизонтали пропорционально их отношению сторон так, чтобы общая ширина строки была равна ширине блока.
var iimgs=document.getElementById("iimgs").childNodes; var c=document.getElementById("c"); var images=[]; function packimgs(freeH) { var padding = 5; var divWidth = 510+padding; var divHeight = 350+padding; var w=0; for(var i=0;i 1.5*w/nrows) nrows-= Math.round(images[i].aspect*nrows/w)-1; if(nrows<1) nrows=1; var rows= []; var rowHeight= divHeight/nrows - padding; w= rowHeight*w + padding*images.length; for(var j=0; j0 && Math.abs(rowWidth-w/(nrows-1-j)) < Math.abs(rowWidth-w/(nrows-1-j)+imgWidth*2)) { rowWidth=0; j++; } rows[j].push(images[i]); rows[j].space-= imgWidth; rowWidth+= imgWidth; w-= imgWidth; } // Подгон высот var dhp=0, dhm=0, pn=0; for(j=0; jrowHeight) { dhp+= rows[j].height-rowHeight; pn++; } else dhm+= rowHeight-rows[j].height; } // второй этап подгона высот (пропустить если не нужно точно соблюдать высоту блока) if(!freeH&&dhp!=dhm) for(j=0; jrowHeight && dhp>dhm) rows[j].height= rowHeight + (rows[j].height-rowHeight)*dhm/dhp; else if(rows[j].height0? rowHeight*rowWidth1/rowWidth : rows[j].height; for(i=0;i0) { cell.style.height= rows[j].height+"px"; rows[j][i].style.marginTop= (rows[j].height-rowHeight1)/2+"px"; } else { var cwidth= rows[j][i].aspect*rowWidth1*rowHeight/rowWidth; cell.style.width= cwidth+"px"; rows[j][i].style.marginLeft= (cwidth-rows[j][i].width)/2+"px"; } } } } function chlimit(i) { c.innerHTML=""; packimgs(i.checked); } images.loaded=0; for(i=0;i


Алгоритм с изменением порядка картинок.
Определяем количество строк как sqrt( сумма отношений сторон всех картинок / отношение сторон блока ), где отношение сторон определяется как ширина делённая на высоту. Определяем высоту строки как высоту блока делённую на число строк. Сортируем картинки по соотношению сторон, ставя в начало самые широкие. Распределяем картинки по строкам, помещая очередную картинку в строку с наибольшим свободным пространством, которое определяется как ширина блока минус сумма ширин картинок смасштабированных так, чтобы их высота была равна высоте строки Для строк у которых осталось свободное пространство (до ширины блока) масштабируем картинки так, чтобы занять всю ширину блока, после чего обрезаем их по высоте с центрированием по вертикали. В строках, где нет свободного пространства масштабируем картинки так, чтобы их высота была равна высоте строки, и обрезаем их по ширине с центрированием по горизонтали пропорционально их отношению сторон так, чтобы общая ширина строки была равна ширине блока.
var iimgs=document.getElementById("iimgs").childNodes; var c=document.getElementById("c"); var images=[]; function packimgs() { var divWidth = 510; var divHeight = 350; var padding = 5; var w=0; for(var i=0;i 1.5*w/nrows) nrows-= Math.round(images[i].aspect*nrows/w)-1; if(nrows<1) nrows=1; var rows= []; var rowHeight= (divHeight-padding*(nrows-1))/nrows; for(var j=0; j1) rows[maxj].space-= padding; } for(j=0; j0? rowHeight*rowWidth1/rowWidth : rowHeight; for(i=0;i0) { cell.style.height= rowHeight+"px"; rows[j][i].style.marginTop= (rowHeight-rowHeight1)/2+"px"; } else { var cwidth= rows[j][i].width*rowWidth1/rowWidth; cell.style.width= cwidth+"px"; rows[j][i].style.marginLeft= (cwidth-rows[j][i].width)/2+"px"; } } } } for(i=0;i

Комментариев нет:

Отправить комментарий