some image

Умная адаптация под разрешение экрана на 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 - переходим и ресайзим окошко браузера.

Related Posts