您身边的网站建设专家
成功案例

【建站服务】泽州网站优化【泽州开通400电话】泽州网站搭建、泽州微信公众号推文外包、泽州开通京东拼多多设计、泽州淘宝装修-域名申请

日期: 2022-09-20 15:44:25 浏览数:6


​

上往建站提供服务器空间服务商,百度快照排名,网站托管,百度推广运营,致力于设计外包服务与源代码定制开发,360推广,搜狗推广,增加网站的能见度及访问量提升网络营销的效果,主营:网站公司,百度推广公司电话,官网搭建服务,网站服务企业排名,服务器空间,英文域名等业务,专业团队服务,效果好。


泽州网站优化【泽州开通400电话】泽州网站搭建、泽州微信公众号推文外包、泽州开通京东拼多多设计、泽州淘宝装修

网站建设.jpg

泽州,古代州名,是今山西晋城市在隋、唐、五代、宋之称。 [1-4] 

尧舜时,属冀州畿内地。春秋属晋,战国属韩,后兼属赵与魏。秦兼天下,为河东上党二郡地,两汉因之。三国魏时,属平阳上党二郡地,西晋因之。永嘉之后,沦于十六国之前赵、后赵、前秦所据。

东晋太元十一年(386),西燕慕容永分上党置建兴郡。北魏永安二年改置建州,治高都城,辖高都、长平、安平、泰宁四郡。北齐改置建州道行台,北周复为建州。隋开皇三年(583),改建州为泽州,依境内获泽河为名。大业三年改置长平郡,义宁二年复为泽州。

唐仍为泽州,天宝初改高平郡,乾元初复为泽州,宋仍为泽州及高平郡,先后隶河东道、河东路。金灭北宋,改曰南泽州,金元光二年,升忠昌军节度。元置泽州司侯司,至元三年,罢司侯司复为泽州,隶中书省平阳路、晋宁路。明洪武二年,升泽州直隶州,直隶山西承宣布政使司。

清雍正六年(1728),升为山西省泽州府。

民国二年(1913),北洋袁世凯政府颁布《划一现行各省官厅组织令》,废府。

注:历代郡州府辖境与今晋城市辖6(县、市、区)大体一致。自北魏起治所均位于今城区。 [1-4] 


JS给导线描边-非样式属性

最近工作中做了个关于描边的故事,对,就是给导线描边,通俗的讲就是沿着线条勾勒出它的轮廓,细的线条貌似没什么意义,但是在较粗的导线上或者是细的线条放大后,就格外有用途了,比如说用线条给导线挖孔,给导线添加线条轮廓动画等等。

这里用到了一些技术知识点:

1. 三角函数、向量关系,线段关系在javascript中的应用,主要与三角函数为主体;

2. svg的属性和操作,当然描边不局限于svg,在任何场景都可以用,本文只是用svg举例;

原理开始剖析,供学习的人阅读。(如果你只是想把它应用到你的项目中,你可以跳过原理部分,直接到文尾找完整代码)

描边首先是基于坐标点来产生一些相对位置的点来勾勒出线条的走向。所以一条线段肯定有它的路径,比如svg中的polyline和path,它们的路径分别存在属性的points和d中。

类似这样:

复制代码<polyline points="80 50 100 100 60 90 88 200 188 30 200 300 250 200 300 200 300 100 350 150 600 20 500 330 600 400" stroke-linecap="round" fill="none" id="polyline" stroke-width="20" stroke="#FF0000" stroke-linejoin="round"></polyline><path stroke-width="15" fill="none" id="path" d="M 100 440 L 150 400 L 200 500 L 250 400 L 350 550 L 400 400" stroke="rgba(0,0,0,.5)" stroke-linejoin="round" stroke-linecap="round"></path>复制代码

我这里用圆角线段讲解,圆角比非圆角要复杂一些。

第一步就要用正则把路径的xy值成对匹配出来:

复制代码var line = document.getElementById('***');var points = line.getAttribute('points') || line.getAttribute('d');points = points.match(/d+(.d+)*s+d+(.d+)*/g);复制代码

取得的路径将会是个数组,类似:

复制代码['43 45', '56 41', '85 67', ...]复制代码

路径坐标是关键,接下来一切操作都将围绕坐标数组操作,因为一切的线条切点都参考导线中心点坐标位置来计算的。记得任何一条导线都是有宽度的,也就是我们所说的粗细,无论它再细都有一个stroke-width,这个也是要用到计算中的参考值的。

虽然画的只有两段线条,但要计算出导线每一个点的切点,总共只有两种情况,一种是端点,一种是拐点,所以图示包含了所有情况,无论线条怎么走,怎么拐,它都遵循这两个情况。

我们先看端点,每个点的切点必定与该点所在的下一条导线走向垂直,以端点的中心点画个虚拟坐标做参考。

A1 + A2 = 90

A1 + B2 = 90

那么A2 = B2, 而A1是可以求出来的,导线与水平方向的夹角。也即当前点与下一点连线与水平方向的夹角。用直角三角函数可求出。

复制代码var xy1 = nextPoint.split(' '), x1 = xy1[0] * 1, y1 = xy1[1] * 1;var atan = Math.atan2(y - y1, x - x1);var deg = 180 - atan * 180 / Math.PI;复制代码

正确的角度应该是,以线段的起点为原点,终点为旋转点,与水平线相对于原点的右侧水平线逆时针夹角。 所以直角三角形B的角度B2知道了,又知道斜边长度,也即是导线宽度的一半,那么切点的坐标相对于当前点的xy偏移量可以用直角三角函数可求出。

复制代码addX = Math.sin(deg * Math.PI / 180) * halfWidth * -1;addY = Math.cos(deg * Math.PI / 180) * halfWidth * -1;复制代码

切点坐标即:

复制代码X = addX + x; Y = addY + y;复制代码

如此该点的一侧切点就求出来了,要实现导线的描边,就意味着另一边也要求切点,不用急,先一边一边来。

有人说万一导线反着走斜度换一下,从上到下走,从下到上走,从左往右走,从右往左走,斜向上,斜向下,垂直90度走,水平0度走,不拐弯这些情况还能适用吗? 当然能,无论它怎么走,只要你计算上不乱添加正负符号,它都遵循这个计算方法。如果你去纠正一些正负符号或者纠正夹角,把95度纠正为180-95度,然后再通过其它方法去纠正xy偏移的正负值你就掉坑了,爬都爬不上来,那样的情况层出不穷,举都举不完。

以上我们计算了起点的一侧切点,那终点的切点如何计算,其实跟起点是一样的,只是计算起点要依赖下一个点来求夹角,而终点没有下一个点,如何处理,很简单,都省略计算夹角了直接取前一个点的夹角就ok:

复制代码var prePointInfo = getBorderPoint(points, index - 1, halfWidth, true);if(!nextPoint) {//最后一点deg = prePointInfo.deg;}复制代码

getBorderPoint是我们封装的一个函数,具体看完整代码,夹角有了,计算方式跟起点一样。 这样下来我们起点和终点都计算好了,还有起点跟终点之间的拐点。 导线拐点切点算法 拐点比较复杂,每个拐点一侧就有两个切点,那么整个拐点需要计算的是四个切点,我们先来看一侧的切点,两个切点分别是与上一个点斜线的切点和与下一个点斜线的切点,所以要三个点的信息才能确定切点的信息,与下一个点的切点跟起点的计算是一样的。与上一个点的切点,也是同理只是计算的参考点换一下:

复制代码if(prePoint && nextPoint) {//拐点//求与上一点的切点xy_1 = prePoint.split(' ');x_1 = xy_1[0];y_1 = xy_1[1];trend = lineDrection({x:x_1, y:y_1}, {x:x, y:y}, {x:x1,y:y1});atan = Math.atan2(y_1 - y, x_1 - x);deg_1 = 180 - atan * 180 / Math.PI;addX = Math.sin(deg_1 * Math.PI / 180) * halfWidth * -1;addY = Math.cos(deg_1 * Math.PI / 180) * halfWidth * -1;X_1 = addX + x; Y_1 = addY + y;}复制代码

trend是这三个点的走向,通过函数lineDrection可以求出,函数实现看完整代码,这个走向是有用的,拐点描边的时候,因为拐点是圆角描边需要使用圆弧连接两个切点,就需要用到这个走向,标志是顺时针还是逆时针。

端点的切点是不分凹侧和凸侧,自创词汇,希望能理解,从上图可以看出,凹侧连接点只有一个,就是当前拐点的切点与上一个点的切点和下一个点的切点的交叉点。而凸侧连接点有两个,直接取与上一个点连线的切点和与下一个点连线的切点。我们最终取到的是描边的连接点,而非切点,如何判断是凹侧和凸侧,用切点与切点之间的连线,计算是否相交即可。有交点就是凹侧没有交点就是凸侧。凹侧连接点取交点,凸侧连接点直接取切点。

复制代码var nxtPointInfo = getBorderPoint(points, index + 1, halfWidth, true);var intersection = getTwoSegmentsIntersection({x:prePointInfo.x, y:prePointInfo.y}, {x:X_1,y:Y_1}, {x:X,y:Y}, {x:nxtPointInfo.x_1,y:nxtPointInfo.y_1});if(intersection) {//如果有交点X = intersection.x; X_1 = intersection.x;Y = intersection.y; Y_1 = intersection.y;}复制代码

getTwoSegmentsIntersection函数是封装了的取两条线段交点的函数,具体看完整代码。由以上可以封装一个取导线描边连接点信息的函数:

复制代码function getBorderPoint(points,index,halfWidth,self) {//这是计算导线某侧的连接点信息,导线另一侧的计算得反着循环,即要把points数组顺序颠倒过来reverse()再用此函数计算,当然计算的路径也是反向的,如果想要路径同向则points顺序不需要变化,只需要halfWidth取负值就ok了	var point = points[index], x, y;	if(!point) {		return;	}	if(typeof point === 'string') {		var xy = point.split(' ');		x = xy[0] * 1;		y = xy[1] * 1;	} else {		x = point.x * 1;		y = point.y * 1;	}	var nextPoint = points[index + 1], xy1, x1, y1,//下一个点		prePoint = points[index - 1], xy_1, x_1, y_1,//上一个点		atan, deg, deg_1, trend,//与下一点的斜率和角度, deg_1与上一点的夹角		X, Y,//与下一点斜线的切点		addX, addY,		X_1, Y_1;//与上一点斜线的切点	var prePointInfo = getBorderPoint(points, index - 1, halfWidth, true);	if(nextPoint) {		xy1 = nextPoint.split(' '); x1 = xy1[0] * 1; y1 = xy1[1] * 1;		atan = Math.atan2(y - y1, x - x1);		deg = 180 - atan * 180 / Math.PI;	} else {//最后一点		deg = prePointInfo.deg;	}	//求与下一点的切点	addX = Math.sin(deg * Math.PI / 180) * halfWidth * -1;	addY = Math.cos(deg * Math.PI / 180) * halfWidth * -1;	X = addX + x; Y = addY + y;	if(!nextPoint) {//最后一点,与上一点一致		X_1 = X;		Y_1 = Y;	}	createPoint(X,Y);	if(prePoint && nextPoint) {//拐点		//求与上一点的切点		xy_1 = prePoint.split(' ');		x_1 = xy_1[0];		y_1 = xy_1[1];		trend = lineDrection({x:x_1, y:y_1}, {x:x, y:y}, {x:x1,y:y1});		atan = Math.atan2(y_1 - y, x_1 - x);		deg_1 = 180 - atan * 180 / Math.PI;		addX = Math.sin(deg_1 * Math.PI / 180) * halfWidth * -1;		addY = Math.cos(deg_1 * Math.PI / 180) * halfWidth * -1;		X_1 = addX + x; Y_1 = addY + y;		createPoint(X_1,Y_1);		createPoint(X,Y);		if(!self) {			var nxtPointInfo = getBorderPoint(points, index + 1, halfWidth, true);			var intersection = getTwoSegmentsIntersection({x:prePointInfo.x, y:prePointInfo.y}, {x:X_1,y:Y_1}, {x:X,y:Y}, {x:nxtPointInfo.x_1,y:nxtPointInfo.y_1});			if(intersection) {//如果有交点				X = intersection.x; X_1 = intersection.x;				Y = intersection.y; Y_1 = intersection.y;			}		}	}	return {		x: X,//当前点与下一个点斜线的切点x		y: Y,//当前点与下一点斜线的切点y		x_1: X_1,//当前点与上一点斜线的切点x		y_1: Y_1,//当前点与下一点斜线的切点x		deg: deg,//当前点与下一点斜线的角度		arc: intersection ? null : trend//返回该点是否是圆弧点以及圆弧的方向	}}复制代码

连接点这些都计算出来了,有了点之后描边当然要创建线条,只需要用线条把这些点连接起来就行了,创建连接线的函数:

复制代码function getBorderPath(points, halfWidth) {	var d;	function getSidePath(points) {		var pointInfo, path = 'M', firstPoint, lastPoint;		var nextPoint, prePoint;		points.forEach(function(point, index) {			nextPoint = points[index + 1];			prePoint = points[index - 1];			pointInfo = getBorderPoint(points, index, halfWidth);			if(index === 0) {				firstPoint = pointInfo;			}			if(index === points.length - 1) {				lastPoint = pointInfo;			}			var str = '';			if(prePoint && nextPoint) {				if(pointInfo.arc) {//凸点要生成圆弧					str = ' ' + pointInfo.x_1 + ' ' + pointInfo.y_1 + ' A' + halfWidth + ',' + halfWidth + (pointInfo.arc === '顺时针' ? ' 0 0 1 ' : ' 0 0 0 ') + pointInfo.x + ' ' + pointInfo.y;				} else {					str = ' ' + pointInfo.x + ' ' + pointInfo.y;				}			} else {				str = ' ' + pointInfo.x + ' ' + pointInfo.y;			}			path += str + (index === points.length - 1 ? '' : ' L');		});		return {			d: path,			first: firstPoint,			last: lastPoint		}	}	//计算导线的某侧的描边路径	var border1 =  getSidePath(points);	//计算导线的另一边描边路径	var border2 =  getSidePath(points.reverse());	d = border1.d + ' A' + halfWidth + ',' + halfWidth + ' 0 0 1 ' + border2.first.x + ' ' + border2.first.y + ' ' + border2.d + ' A' + halfWidth + ',' + halfWidth + ' 0 0 1 ' + border1.first.x + ' ' + border1.first.y;	return d;}复制代码

此函数也是我们最终要调用的函数getBorderPath(points, halfWidth),points是导线的路径坐标数组,halfWidth顾名思义是导线宽度的一半。

复制代码var path = getBorderPath(points, line.getAttribute('stroke-width') / 2);var borderLine = createSVGElement('path', {	class: 'line',	d: path,	"stroke-width": 1,	stroke: '#000000',	fill: 'none'});document.querySelector('svg').appendChild(borderLine);复制代码

我们在计算过程中需要用到的一些附加函数:

判断两条线段是否相交以及计算交点:

复制代码function getTwoSegmentsIntersection(a, b, c, d){// 如果分母为0 则平行或共线, 不相交var denominator = (b.y - a.y) * (d.x - c.x) - (a.x - b.x) * (c.y - d.y);if (denominator == 0) {return false;}// 线段所在直线的交点坐标 (x , y)var x = ((b.x - a.x) * (d.x - c.x) * (c.y - a.y) + (b.y - a.y) * (d.x - c.x) * a.x - (d.y - c.y) * (b.x - a.x) * c.x) / denominator ;var y = -((b.y - a.y) * (d.y - c.y) * (c.x - a.x) + (b.x - a.x) * (d.y - c.y) * a.y - (d.x - c.x) * (b.y - a.y) * c.y) / denominator;//2 判断交点是否在两条线段上/if (// 交点在线段1上(x - a.x) * (x - b.x) <= 0 && (y - a.y) * (y - b.y) <= 0// 且交点在线段2上|| (x - c.x) * (x - d.x) <= 0 && (y - c.y) * (y - d.y) <= 0){// 返回交点preturn {x: x,y: y}}//否则不相交return false}复制代码

创建调试点用于观察我们的计算是否正确:

复制代码function createPoint(x, y) {	if(!x | !y) {		return;	}	var dot = createSVGElement('circle', {		cx: x,		cy: y,		r: 2,		class: 'dot',		fill: 'blue'	});	document.querySelector('svg').appendChild(dot);}复制代码

创建svg元素:

复制代码function createSVGElement(tag, attributes) {	var elem = document.createElementNS('http://www.w3.org/2000/svg', tag);	if(attributes) {		for(var i in attributes) {			elem.setAttributeNS(null, i, attributes[i]);		}	}	return elem;}复制代码

查看完整案例和完整代码(打开该页面右键查看源码):请访问:http://resource.mizuiren.com/getborder.html


泽州网站优化【泽州开通400电话】泽州网站搭建、泽州微信公众号推文外包、泽州开通京东拼多多设计、泽州淘宝装修


上往建站提供搭建网站,域名注册,官网备案服务,网店详情页设计,企业网店,专业网络店铺管理运营全托管公司咨询电话,服务器空间,微信公众号托管,网页美工排版,致力于域名申请,竞价托管,软文推广,全网营销,提供标准级专业技术保障,了却后顾之忧,主营:虚拟主机,网站推广,百度竞价托管,网站建设,上网建站推广服务,网络公司有哪些等业务,专业团队服务,效果好。

服务热线:400-111-6878 手机微信同号:18118153152(各城市商务人员可上门服务)


全国咨询热线:400-111-6878

地址:全国各地都有驻点商务

Copyright © 2021 通陆科技

网站建设:上往建站