Какой алгоритм используется для отображения нескольких фото в виде мозаики?
1,00
р.
р.
Например, как в ВК при загрузке фотографий. Речь идет о таком отображении:
UPD: Возможно, для вывода изображения используется алгоритм TreeMap. Но не ясно, как задавать "веса" изображениям.
Ответ Я так и не нашел универсального решения, но опишу как это работает сейчас, может быть это кому-то поможет. Сейчас я исходя из кол-ва картиночек делю высоту (350 пикселей) на N-ое кол-во строк. Максимум - три, т.к. картиночек может быть всего 10. Далее, я заполняю строки следующим образом: Считаю для каждой строки суммарное соотношение сторон В строку у которой это значение самое низкое добавляю картинку Если картинки еще есть - пункт 1. Теперь я задаю ширину картинкам (высота, напомню, это просто 350 / кол-во строк). Делаю я это так: Выбираю очередную строку Достаю очередную картинку Ширина картинки = 510 * (соотношение_сторон_картинки / суммарное_соотношение_сторон_картинок_в_сроке) И т.д. Ну и код, который работает по этому алгоритму: 'use strict' angular.module('imageGrid').controller('imageGridController', function($scope) { var divWidth = 510 var divHeight = 350 var padding = 5 var imagesList = $scope.photos angular.forEach(imagesList, function(image, index) { image.aspectRatio = image.width / image.height image.blockWidth = 0 image.blockHeight = 0 image.marginBottom = 0 image.marginRight = 0 }, this) var sumOfWidth = function(set) { var totalWidth = 0 if (set.length > 0) { for (var i = 0 i < set.length i++) { totalWidth += set[i].width } } return totalWidth } var sumOfAspectRatio = function(set) { var totalAspectRatio = 0 if (set.length > 0) { for (var i = 0 i < set.length i++) { totalAspectRatio += set[i].aspectRatio } } return totalAspectRatio } var medianAspectRatio = function(set) { return this.sumOfAspectRatio(set) } var linearPartition = function(set) { var rows = Math.min(3, Math.ceil(set.length / 3)) var rowsArray = [] for (var i = 0 i < rows i++) { rowsArray.push([]) } for (var l = 0 l < set.length l++) { var rowsAspectRatio = [] for (var i = 0 i < rowsArray.length i++) { rowsAspectRatio.push(sumOfAspectRatio(rowsArray[i])) } var minIndex = 0, minValue = Infinity for (var i = 0 i < rowsArray.length i++) { if (rowsAspectRatio[i] < minValue) { minValue = rowsAspectRatio[i] minIndex = i } } rowsArray[minIndex].push(set[l]) } return rowsArray } var setByRows = linearPartition(imagesList) var rowsCount = setByRows.length var virtualHeight = Math.floor(divHeight / rowsCount) for (var i = 0 i < setByRows.length i++) { var rowAspectRatio = sumOfAspectRatio(setByRows[i]) var imagesCount = setByRows[i].length var virtualWidth = imagesCount > 1 ? divWidth - (imagesCount - 1) * padding : divWidth for (var l = 0 l < imagesCount l++) { var image = setByRows[i][l] image.blockWidth = Math.floor(virtualWidth / imagesCount) image.blockHeight = virtualHeight } } var resultList = [] for (var i = 0 i < rowsCount i++) { var imagesCount = setByRows[i].length for (var l = 0 l < setByRows[i].length l++) { var image = setByRows[i][l] image.marginBottom = rowsCount > 1 && i < rowsCount - 1 ? padding : 0 image.marginRight = imagesCount > 1 && l < imagesCount - 1 ? padding : 0 resultList.push(image) } } $scope.imageList = resultList }) Обновление 01.09.2016 16:50 По просьбе, поясню, что в моем понимании "не универсальное решение". Мой алгоритм не умеет разбивать картинки максимально эффективно. Вот так отображается три картинки с помощью моего алгоритма: Заметьте, у всех одинаковая ширина. Первая картинка (красная), обрезается очень, очень сильно, т.к. у нее самая большая ширина из всех картинок. А вот так эти же картинки отображает ВК: Не трудно заметить, что в этом варианте расположения отображается на много большая часть первой картинки (возможно, и всех остальных). Именно из за этого я и считаю свой алгоритм "не универсальным".