Умная адаптация под разрешение экрана на fileboard.ru
Многие знают про мой проект — fileboard.ru. Рассказывать про него не буду. Просто перейдите, зарегистрируйтесь, попробуйте.
Так вот, существовала проблема, до которой долго не доходили руки. Когда пользователь группирует файлы в одном разрешении, а потом открывает, например, на телефоне, в намного меньшем разрешении — все слепляется в кучу. Появляется эта проблема из-за того, что координаты файлов на экране не привязаны к разрешению, а имеют относительные координаты по осям от 0 до 1. Масштабировать текст и превьюшки — плохая идея, т.к. не хочется ограничивать пользователей 24″ мониторов огромными значками в угоду сохранения читаемости на мобильных.
Пример (1366×768):
превращается в (800х600):
нужно было разработать систему, которая бы сама решала такие конфликты и потихоньку двигала файлы (если это возможно), да так, чтоб пользователя не покидало ощущение того, что все так, как он и расположил раньше.
В результате была разработана отдельная от ООП структуры клиентского приложения функция, отвечающая за onload и onresize масштабирование.
В основу была положена идея: поскольку все файлы симметричны, то можно рассматривать 4 случая перекрытия файлами друг друга.
Назовем красный файл — ei, зеленый — ej.
Первый случай — левый верхний угол ej расположен внутри ei. Растаскивать нужно либо по вертикали либо по горизонтали, в зависимости от того что меньше.
Второй случай — правый верхний угол ej расположен внутри ei. Растаскивать нужно либо по вертикали либо по горизонтали, в зависимости от того что меньше.
Третий случай: верхняя сторона ej полностью перекрывает нижнюю ei. Растаскивать нужно по вертикали, ei вверх, ej вниз.
Четвертый случай: левая сторона ej полностью перекрывает праву ei. Растаскивать нужно по горизонтали, ei влево, ej вправо.
После анализа всех возможных вариантов была написана функция:
function compose(){ var elems = new Array; $(".template-download").each(function( i ){ elems[i] = {'x': parseInt( $(this).css('left') ), 'y': parseInt( $(this).css('top') ), 'width': $(this).width(), 'height': $(this).height(), }; }); var container = $('#files-container'); var minX = parseInt(container.css('left')); var minY = parseInt(container.css('top')); var maxX = $(window).width(); var maxY = $(window).height(); for( var k = 0; k < 3; k++ ){ var noConflicts = 1; for( var i = 0; i < elems.length; i++ ){ var ei = elems[i]; if( ei.x < ( minX ) ) ei.x = minX; if( ei.y < ( minY ) ) ei.y = minY; if( ei.x > ( maxX - ei.width ) ) ei.x = maxX - ei.width; if( ei.y > ( maxY - ei.height ) ) ei.y = maxY - ei.height; for( var j = 0; j < elems.length; j++ ){ if( i == j ) continue; var ej = elems[j]; if( ei.x < ej.x && (ei.x + ei.width) > ej.x && ei.y < ej.y && (ei.y + ei.height) > ej.y ){ //если левый верхний угол ej лежит внутри var delta_x = ( ei.x + ei.width ) - ej.x; var delta_y = ( ei.y + ei.height ) - ej.y; if( delta_x < delta_y ){ ei.x -= delta_x / 2; ej.x += delta_x / 2; } else { ei.y -= delta_y / 2; ej.y += delta_y / 2; } noConflicts = 0; } else if( ei.x < ( ej.x + ej.width ) && (ei.x + ei.width) > ( ej.x + ej.width) && ei.y < ej.y && (ei.y + ei.height) > ej.y ){ //если правый верхний угол ej лежит внутри var delta_x = (ej.x + ej.width) - ei.x; var delta_y = ( ei.y + ei.height ) - ej.y; if( delta_x < delta_y ){ ei.x += delta_x / 2; ej.x -= delta_x / 2; } else { ei.y -= delta_y / 2; ej.y += delta_y / 2; } noConflicts = 0; } else if( ( ( ei.x < ej.x && ( ei.x + ei.width ) > ( ej.x + ej.width ) ) || ( ei.x > ej.x && ( ei.x + ei.width ) < ( ej.x + ej.width ) ) ) && ei.y < ej.y && ( ei.y + ei.height ) > ej.y ){ //если ej верхней стороной перекрывает ei или ei нижней стороной перекрывает ej var delta_y = ( ei.y + ei.height ) - ej.y; ei.y -= delta_y / 2; ej.y += delta_y / 2; noConflicts = 0; } else if( ( ( ei.y < ej.y && ( ei.y + ei.height ) > ( ej.y + ej.height ) ) || ( ei.y > ej.y && ( ei.y + ei.height ) < ( ej.y + ej.height ) ) ) && ei.x < ej.x && ( ei.x + ei.width ) > ej.x ){ //если ej левой стороной перекрывает ei или ei правой стороной перекрывает ej var delta_x = ( ei.x + ei.width ) - ej.x; ei.x -= delta_x / 2; ej.x += delta_x / 2; noConflicts = 0; } } if( ei.x < ( minX ) ) ei.x = minX; if( ei.y < ( minY ) ) ei.y = minY; if( ei.x > ( maxX - ei.width ) ) ei.x = maxX - ei.width; if( ei.y > ( maxY - ei.height ) ) ei.y = maxY - ei.height; } if( noConflicts ) break; } $(".template-download").each(function( i ){ $(this).css('left', elems[i].x ); $(this).css('top', elems[i].y ); }); }
После ряда доработок, добавления ограничений, была получена функциональность, полностью удовлетворяющая поставленной задаче. С результатом вы всегда можете ознакомиться на fileboard.ru создав аккаунт и накачав файлов:) Так же хороший пример — мой аккаунт: nwr.fileboard.ru - переходим и ресайзим окошко браузера.