javascript-svg-在圆环上加入闪烁光标

问题描述

假设我某个页面上使用了<svg>,其中包括一个<circle>。我希望实现的是:在circle上点击某个位置,该位置出现一个闪烁的光标。
在这里插入图片描述

解决思路

要实现这个效果,需要考虑3个问题:

  1. 如何实现光标?
  2. 如何实现闪烁效果?
  3. 如何将光标移动到鼠标点击的位置?

对于第1个问题,最直观的想法就是用<line>实现,然后通过修改x1y1x2y2的数值(即线段两个端点的坐标)实现光标的移动。

对于第2个问题,可以使用 jQuery 的fadeOutfadeIn方法来实现元素的淡出和淡入效果,并且通过setInterval方法,在周期内重复淡出和淡入过程,从而实现持续的闪烁效果。

对于第3个问题,重点在于,计算鼠标点击位置e与圆心c的连线L,与通过c的垂线,顺时针方向的夹角,通过这个夹角,可以计算出line两个端点的坐标。需要注意的是,我的思路是将<line>放在<svg>标签下,所以计算夹角时,用的是窗口坐标系中的e、c和半径r,并非svg坐标系下的对象;但是计算line端点坐标时,使用的是svg坐标系下对应值。

3.1 计算L与圆的交点
首先需要考虑L是水平线和垂直线的情况,因为联立计算时,可能出现除0错误。假设圆心 C C C坐标为 ( x 0 , y 0 ) (x_0, y_0) (x0,y0),半径为 r r r,圆外某点 P P P坐标为 ( x 1 , y 1 ) (x_1, y_1) (x1,y1),要计算直线 P C PC PC与圆的交点,可以这样计算:
直线 P C 的斜率为 : k = y 1 − y 0 x 1 − x 0 直线PC的斜率为: k = \frac{y_1 - y_0}{x_1 - x_0} 直线PC的斜率为:k=x1x0y1y0 P C 的方程为: y = m ( x − x 0 ) + y 0 PC的方程为:y = m(x - x_0) + y_0 PC的方程为:y=m(xx0)+y0 圆的方程为: ( x − x 0 ) 2 + ( y − y 0 ) 2 = r 2 圆的方程为:(x - x_0)^2 + (y - y_0)^2 = r^2 圆的方程为:(xx0)2+(yy0)2=r2
将PC的方程代入圆的方程,整理得: ( 1 + m 2 ) x 2 − 2 x 0 ( 1 + m 2 ) x + ( 1 + m 2 ) x 0 2 − r 2 = 0 (1+m^2)x^2-2x_0(1+m^2)x+(1+m^2)x_0^2-r^2=0 (1+m2)x22x0(1+m2)x+(1+m2)x02r2=0
这样相当于已知一元二次方程的a、b和c了,所以可以直接使用公式求解: x = − b ± b 2 − 4 a c 2 a x=\frac{-b\pm\sqrt{b^2-4ac}}{2a} x=2ab±b24ac
此时可以根据 P P P点在 C C C点的左侧还是右侧判断选哪个根。

注意:窗口坐标系是向右为x增长方向,向下为y增长方向。

3.2 计算夹角
这里不展开了,主要是利用arcsin。js里方法是Math.asin(),计算结果是弧度。

3.3 已知夹角计算圆上某点的坐标
如下图所示(通过设置不同的r值可以计算两个端点的坐标):
在这里插入图片描述
P x = C x + r ∗ s i n ( θ ) P_x = C_x + r * sin(θ) Px=Cx+rsin(θ) P y = C y − r ∗ c o s ( θ ) P_y = C_y - r * cos(θ) Py=Cyrcos(θ)

其中js里用的方法是Math.sin()Math.cos(),参数都是弧度,需要注意转换。

代码结构

注意:已去除实现细节。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
	<div>
		<svg width="100%" height="1000" xmlns="http://www.w3.org/2000/svg">
			<circle id="myCircle1" cx="600" cy="480" r="285" fill="#fff" stroke="#ccc" stroke-width="1" />
			<!-- 先隐藏line -->
			<line x1="1" y1="11" x2="2" y2="2" id="cursor" stroke="#1F2744" stroke-width="1" style="display:none;"></line>
			</svg>
	</div>
<script>
	// 设置闪烁
    function startBlinkingJQuery(element, interval) {
      setInterval(() => {
        $(element).fadeOut(interval / 2).fadeIn(interval / 2);
      }, interval);
    }
	// 获取光标
    var cursor = document.getElementById("cursor");
	const intervalJQuery = 900; // 设置闪烁间隔,单位是毫秒
	
	// 获取svg和circle
	const svg = document.querySelector('svg');
	const circle = document.getElementById('myCircle1');
	// 添加监听
	circle.addEventListener('mousedown', (e) => {
    	const bbox = circle.getBoundingClientRect();
    	const centerX = bbox.x + bbox.width / 2;
    	const centerY = bbox.y + bbox.height / 2;
    	const radius = bbox.width / 2;
    	const clickX = e.clientX;
    	const clickY = e.clientY;
		// 使用窗口中的圆心和点击点计算夹角,省略函数的实现
		let angle = calculateCircleInfo(centerX, centerY, radius, clickX, clickY);
		// 根据夹角计算svg上两个端点的坐标,返回的是数组。省略函数的实现
		let result = calSvgLine(angle);
		//console.log(result);
		cursor.setAttribute('x1', result[0]);
		// 依次修改x1, y1, x2, y2, 此处省略
		// 设置闪烁
		startBlinkingJQuery(cursor, intervalJQuery);
	});
	
	
</script>
</body>
</html>	


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值