Javascript-форум (https://javascript.ru/forum/)
-   jQuery (https://javascript.ru/forum/jquery/)
-   -   Скрипт получения координат для svg-линий (https://javascript.ru/forum/jquery/66044-skript-polucheniya-koordinat-dlya-svg-linijj.html)

EuRo1985 22.11.2016 16:39

Скрипт получения координат для svg-линий
 
Вложений: 1
Уважаемы знатоки Jquery, прошу помощи в реализации скрипта.

Задача такая: есть 5 окружностей - одна в центре и 4 по-краям. Все они заданы через position: absolute в процентном отношении отступов. Необходимо рассчитать координаты линий, соединяющих эти окружности для svg line. Сложность в том, чтобы посчитать точки пересечения этих окружностей и линий.

Сам алгоритм и его реализацию написал - все работает, скрин прилагаю. Но т.к. я в JS близок к нулю, реализовано все через одно место - для каждой координаты написаны свои правила, хотя уверен, что весь скрипт можно сократить ни в два и даже ни в три раза, при этом унифицировать его.

Может кто-нить помочь?

$(function(){
		var slideSize = $('#slide-business');
		var imgS1 = parseInt($('.circles img.img1').width());
		var imgS2 = parseInt($('.circles img.img2').width());
		var line1CoorX1 = parseInt($('.circles img.img1').css('left'));
		var line1CoorY1 = parseInt($('.circles img.img1').css('top'));
		var line2CoorX2 = slideSize.width()-parseInt($('.circles div.img2').css('right'))-imgS2/2;
		var line2CoorY2 = parseInt($('.circles div.img2').css('top'))+imgS2/2;
		var line3CoorX2 = slideSize.width()-parseInt($('.circles div.img3').css('right'))-imgS2/2;
		var line3CoorY2 = parseInt($('.circles div.img3').css('top'))+imgS2/2);
		var line4CoorX2 = parseInt($('.circles div.img4').css('left'))+imgS2/2;
		var line4CoorY2 = slideSize.height()-parseInt($('.circles div.img4').css('bottom'))-imgS2/2;
		var line5CoorX2 = parseInt($('.circles div.img5').css('left'))+imgS2/2;
		var line5CoorY2 = slideSize.height()-parseInt($('.circles div.img5').css('bottom'))-imgS2/2;

// Для правых кругов (X2 > X1). Математический расчет координат
	
		var line2Angle = Math.atan2(line2CoorX2-line1CoorX1,line1CoorY1-line2CoorY2); // Находим угол для линии 2
		var line2SideX1 = Math.abs(Math.sin(line2Angle)*(imgS1/2));  // Находим сдвиг X1
		var line2SideY1 = Math.abs(Math.cos(line2Angle)*(imgS1/2)); // Находим сдвиг Y1	
		var line2SideX2 = Math.abs(Math.sin(line2Angle)*(imgS2/2)); // Находим сдвиг X2
		var line2SideY2 = Math.abs(Math.cos(line2Angle)*(imgS2/2)); // Находим сдвиг Y2
		
		var line3Angle = Math.atan2(line3CoorX2-line1CoorX1,line1CoorY1-line3CoorY2);
		var line3SideX1 = Math.abs(Math.sin(line3Angle)*(imgS1/2));
		var line3SideY1 = Math.abs(Math.cos(line3Angle)*(imgS1/2));
		var line3SideX2 = Math.abs(Math.sin(line3Angle)*(imgS2/2));
		var line3SideY2 = Math.abs(Math.cos(line3Angle)*(imgS2/2));

// Для левых кругов (X2 < X1). Математический расчет координат
		
		var line4Angle = Math.atan2(line1CoorX1-line4CoorX2,line4CoorY2-line1CoorY1);
		var line4SideX1 = Math.abs(Math.sin(line4Angle)*(imgS1/2));
		var line4SideY1 = Math.abs(Math.cos(line4Angle)*(imgS1/2));
		var line4SideX2 = Math.abs(Math.sin(line4Angle)*(imgS2/2));
		var line4SideY2 = Math.abs(Math.cos(line4Angle)*(imgS2/2));
		
		var line5Angle = Math.atan2(line1CoorX1-line5CoorX2,line5CoorY2-line1CoorY1);
		var line5SideX1 = Math.abs(Math.sin(line5Angle)*(imgS1/2));
		var line5SideY1 = Math.abs(Math.cos(line5Angle)*(imgS1/2));
		var line5SideX2 = Math.abs(Math.sin(line5Angle)*(imgS2/2));
		var line5SideY2 = Math.abs(Math.cos(line5Angle)*(imgS2/2));

// Находим координаты линий по центру координат окружностей и сдвигам до краев + увеличиваем сдвиг на x0.3
		
		$('#slide-business svg .line2')
			.attr('x1',line1CoorX1+line2SideX1+line2SideX2*0.3)
			.attr('x2',line2CoorX2-line2SideX2-line2SideX2*0.3)
			.attr('y1',line1CoorY1-line2SideY1-line2SideY2*0.3)
			.attr('y2',line2CoorY2+line2SideY2+line2SideY2*0.3);
			
		if(line3CoorY2<line1CoorY1){ // Проверяем в какую сторону сдвигать линию от центра
			$('#slide-business svg .line3')
			.attr('x1',line1CoorX1+line3SideX1+line3SideX2*0.3)
			.attr('x2',line3CoorX2-line3SideX2-line3SideX2*0.3)
			.attr('y1',line1CoorY1-line3SideY1-line3SideY2*0.3)
			.attr('y2',line3CoorY2+line3SideY2+line3SideY2*0.3);
		} else {
			$('#slide-business svg .line3')
			.attr('x1',line1CoorX1+line3SideX1+line3SideX2*0.3)
			.attr('x2',line3CoorX2-line3SideX2-line3SideX2*0.3)
			.attr('y1',line1CoorY1+line3SideY1+line3SideY2*0.3)
			.attr('y2',line3CoorY2-line3SideY2-line3SideY2*0.3);
		}
				
		if(line4CoorY2>line1CoorY1){
			$('#slide-business svg .line4')
				.attr('x1',line1CoorX1-line4SideX1-line4SideX2*0.3)
				.attr('x2',line4CoorX2+line4SideX2+line4SideX2*0.3)
				.attr('y1',line1CoorY1+line4SideY1+line4SideY2*0.3)
				.attr('y2',line4CoorY2-line4SideY2-line4SideY2*0.3);
		} else {
			$('#slide-business svg .line4')
				.attr('x1',line1CoorX1-line4SideX1-line4SideX2*0.3)
				.attr('x2',line4CoorX2+line4SideX2+line4SideX2*0.3)
				.attr('y1',line1CoorY1-line4SideY1-line4SideY2*0.3)
				.attr('y2',line4CoorY2+line4SideY2+line4SideY2*0.3);
		}
		
		$('#slide-business svg .line5')
		.attr('x1',line1CoorX1-line5SideX1-line5SideX2*0.3)
		.attr('x2',line5CoorX2+line5SideX2+line5SideX2*0.3)
		.attr('y1',line1CoorY1+line5SideY1+line5SideY2*0.3)
		.attr('y2',line5CoorY2-line5SideY2-line5SideY2*0.3);
		
	});

Rise 22.11.2016 17:05

EuRo1985, нафига тебе margin-ы, ты что без них не можешь отпозиционировать через top, left, right, bottom у тебя же absolute, тогда тебе не придется в коде margin-ы еще учитывать пфф... сделай обертку просто relative и в контексте ее и позиционируй...

EuRo1985 22.11.2016 17:13

да, про маргины согласен, перемудрил тут... подправил код

Rise 22.11.2016 17:27

EuRo1985, lineCoorX1 и lineCoorY1 почему то названы не так line1CoorX1 и line1CoorY1, для чтения кода это существенная деталь исправь и сразу увидишь повторы кода...

EuRo1985 22.11.2016 17:59

Повторы я вижу, lineCoor подправил. Я думаю каким-то образом цикл нужно организовать и ввести переменную, которая будет увеличиваться на +1 и подставляться в необходимые места... или, скажем, пробежаться по img и оставить от класса цифру при помощи substring, которую подставлять далее в скрипт...

EuRo1985 22.11.2016 18:40

Максимально постарался сократить скрипт. Добавил все условия на примере одной линии - line2. Осталось научить его подставлять нужный порядковый номер в соответствующие места.

$(function(){
		var slideSize = $('#slide-business');
		var imgS1 = parseInt($('.circles img.img1').width());
		var imgS2 = parseInt($('.circles img.img2').width());
		var line1CoorX1 = parseInt($('.circles img.img1').css('left'));
		var line1CoorY1 = parseInt($('.circles img.img1').css('top'));
		var line2CoorX2 = slideSize.width()-parseInt($('.circles div.img2').css('right'))-imgS2/2;
		var line2CoorY2 = parseInt($('.circles div.img2').css('top'))+imgS2/2;
		var line3CoorX2 = slideSize.width()-parseInt($('.circles div.img3').css('right'))-imgS2/2;
		var line3CoorY2 = parseInt($('.circles div.img3').css('top'))+imgS2/2;
		var line4CoorX2 = parseInt($('.circles div.img4').css('left'))+imgS2/2;
		var line4CoorY2 = slideSize.height()-parseInt($('.circles div.img4').css('bottom'))-imgS2/2;
		var line5CoorX2 = parseInt($('.circles div.img5').css('left'))+imgS2/2;
		var line5CoorY2 = slideSize.height()-parseInt($('.circles div.img5').css('bottom'))-imgS2/2;
	
		if(line2CoorX2>line1CoorX1){
			var line2Angle = Math.atan2(line2CoorX2-line1CoorX1,line1CoorY1-line2CoorY2);
		} else {
			var line2Angle = Math.atan2(line1CoorX1-line2CoorX2,line2CoorY2-line1CoorY1);
		}

		var line2SideX1 = Math.abs(Math.sin(line2Angle)*(imgS1/2));
		var line2SideY1 = Math.abs(Math.cos(line2Angle)*(imgS1/2));	
		var line2SideX2 = Math.abs(Math.sin(line2Angle)*(imgS2/2));
		var line2SideY2 = Math.abs(Math.cos(line2Angle)*(imgS2/2));
				
		if(line2CoorX2>line1CoorX1){
			$('#slide-business svg .line2')
				.attr('x1',line1CoorX1+line2SideX1+line2SideX2*0.3)
				.attr('x2',line2CoorX2-line2SideX2-line2SideX2*0.3)
		} else {
			$('#slide-business svg .line2')
				.attr('x1',line1CoorX1-line2SideX1-line2SideX2*0.3)
				.attr('x2',line2CoorX2+line2SideX2+line2SideX2*0.3)
		}
		
		if(line2CoorY2>line1CoorY1){
			$('#slide-business svg .line2')
				.attr('y1',line1CoorY1+line2SideY1+line2SideY2*0.3)
				.attr('y2',line2CoorY2-line2SideY2-line2SideY2*0.3);
		} else {
			$('#slide-business svg .line2')
				.attr('y1',line1CoorY1-line2SideY1-line2SideY2*0.3)
				.attr('y2',line2CoorY2+line2SideY2+line2SideY2*0.3);
		}
		
	});

Rise 22.11.2016 19:17

EuRo1985, получается если поменять размеры окна браузера то линии останутся на своих старых местах...

EuRo1985 22.11.2016 21:20

Ну событие resize как раз не проблема добавить)

Rise 22.11.2016 22:36

EuRo1985, нарисуй просто свою картинку в svg (окружности, линии, фон и текст) и не мучайся...

EuRo1985 23.11.2016 14:48

Решил задачу следующим образом

$('.circles div img').each(function(i){
					
		var relParent = $('#slide-business');
		var ctrImg = $('.circles > img');
		var curImg = $(this);
		var curDiv = $(this).parent();
		var line = $('#slide-business svg line');
		var lineMargin = 0.3;
				
		var ctrImgCoorX = parseInt(ctrImg.css('left'));
		var ctrImgCoorY = parseInt(ctrImg.css('top'));
		
		if(curDiv.css('top') !== 'auto' || curDiv.css('top') < ctrImgCoorY) {
			var curImgCoorY = parseInt(curDiv.css('top'))+curImg.height()/2;
		} else {
			var curImgCoorY = relParent.height()-parseInt(curDiv.css('bottom'))-curImg.height()/2;
		}
		
		if(curDiv.css('left') !== 'auto' || curDiv.css('left') < ctrImgCoorX) {
			var curImgCoorX = parseInt(curDiv.css('left'))+curImg.width()/2;
		} else {
			var curImgCoorX = relParent.width()-parseInt(curDiv.css('right'))-curImg.width()/2;
		}
		
		if(curImgCoorX>ctrImgCoorX){
			var lineAngle = Math.atan2(curImgCoorX-ctrImgCoorX,ctrImgCoorY-curImgCoorY);
		} else {
			var lineAngle = Math.atan2(ctrImgCoorX-curImgCoorX,curImgCoorY-ctrImgCoorY);
		}

		var ctrSideX = Math.abs(Math.sin(lineAngle)*(ctrImg.width()/2));
		var ctrSideY = Math.abs(Math.cos(lineAngle)*(ctrImg.height()/2));	
		var curSideX = Math.abs(Math.sin(lineAngle)*(curImg.width()/2));
		var curSideY = Math.abs(Math.cos(lineAngle)*(curImg.height()/2));
				
		if(curImgCoorX>ctrImgCoorX){
			line.eq(i)
				.attr('x1',ctrImgCoorX+ctrSideX+(curSideX*lineMargin))
				.attr('x2',curImgCoorX-curSideX-(curSideX*lineMargin))
		} else {
			line.eq(i)
				.attr('x1',ctrImgCoorX-ctrSideX-(curSideX*lineMargin))
				.attr('x2',curImgCoorX+curSideX+(curSideX*lineMargin))
		}
		
		if(curImgCoorY>ctrImgCoorY){
			line.eq(i)
				.attr('y1',ctrImgCoorY+ctrSideY+(curSideY*lineMargin))
				.attr('y2',curImgCoorY-curSideY-(curSideY*lineMargin));
		} else {
			line.eq(i)
				.attr('y1',ctrImgCoorY-ctrSideY-(curSideY*lineMargin))
				.attr('y2',curImgCoorY+curSideY+(curSideY*lineMargin));
		}
		
	});


По сути вообще убрал классы и через ф-цию each перебираю элементы img и подставляю в координаты line с соответствующим индексом.


Часовой пояс GMT +3, время: 05:16.