目录
前言
编程语言的选择
具体算法分析
根据上面的步骤开始码代码
结语
作为一个机械行业的人,总是会充满好奇,总会想知道一个物体的具体尺寸,还有它们相关角度。
但是有些东西吧,可能是体积巨大,也可能是长相奇特,还可能需要特殊工具才能测量,尤其是出门在外,身上也没啥东西,但还有好奇心,就不是很方便。
以下为两张操作截图:
作为一个标准的普通人,手机出门从来不敢离手,尤其是我这种经常喜欢拍照片的,如果拍下了某些事物的视图(禁止拍摄的东西当然是不能去拍了),有了这个照片,只要图片是正视,角度是很容易得到的,如果旁边还有一个知道尺寸的参照物(手掌不就是一个相当好的参照物么),那两点间的实际长度也是可以得到的,这些东西的算法也很简单,中学就学过了。如下:
由以上两个公式,即可求出长度与角度。
既然算法这么简单,软件还不是一大堆,那找度娘应该也是有的吧,的确,是有的,而且功能远比这两个多,像是数据记录之类的,但是软件吧,需要安装,安装后我发现大部分都没有比例计算的功能。
安装劝退,那在线的总应该有吧,实际上我没找到,要是有谁知道的话,告诉我一下。
那我自己写总应该可以了吧,嗯,可是语言那么多,选啥呢?要求有以下三条
emmm,有没有感觉,这就是在线的那种东西,那用浏览器就好了嘛,所以写个HTML就可以了,我用 Sublime Text 编辑的。而且我写的这个代码,肯定很烂,我是逮着啥能用就用啥(能跑起来就好),如果有啥建议的话,请不吝赐教。
可是我懒得去整网站,那就自己写写自己用吧(如果有大牛看到了,把这个功能做成工具网页,挂在服务器上,然后给我个网址,感激不尽)。
首先,分析分析这个代码该怎么写
本着怎么简单怎么来的原则,我们要花最小的力气,得到这些结果,当然,关于记录,我们可以在电脑前放一个草稿纸,用笔标一下就好了,这年头,纸和笔还是不能被淘汰掉的,要练字啊,写一手好字,自信心也就上来了。
分析一下操作上不可或缺的操作步骤:
嗯,有着三种操作就可以了,其他的我们都可以在点选完之后,直接给出结果。
于是,界面上应该有:
嗯,有着三个要素也就足够了。结果可以直接写在图片上。
步骤与界面相关联,获取操作步骤:
最简单的HTML,就是打开之后是空白的,上面有个标题,就这样
长度与角度的测量
然后往里面填东西就行。
在里面填上css的东西,设置一下网页文本的居中,定义一块画布
p {
text-align:center;
}
/* #XX,叫做“id类型的选择器” */
/* .XX,叫做“class类型的选择器”*/
/* XX,叫做“标签类型的选择器” */
#oc {
background-color:#595959;
display:block;
margin:0 auto;
}
在
里,写上下面的代码。把刚才要的那三个必须元素显示出来:
参照物长度: mm
接下来所有的东西就都是用JS写的了,都放在里:
定义一些后续要用的变量,直接显示帮助文档
var circleNum = 0;
var scale = -1;
var fileURL = "";
var thePoint = [];
var yImg = new Image();
var isAngle = true;
var CalCompleted = false; // 计算完成标志
var VerticalMode = false;
var reff = "";
var T$ = function(id){return document.getElementById(id);};//匿名函数
(function (){
var canvas = T$("oc");
var ctx = canvas.getContext('2d');
ctx.font = "italic 35px 黑体";
ctx.fillStyle = "red";
ctx.fillText("1、要打开一个图片才行;",60,60,200);
ctx.fillText("2、输入标定块大小就是测长度;",60,120,240);
ctx.fillText("3、不输入就是测第二个点的角度。",60,180,280);
ctx.fillText("4、shift,绘制直线",60,240,180);
}()); //匿名自执行函数,即定义后即执行,俗称“匿名包裹器”,只是为了保护canvas这几个变量与外面的变量不会起冲突,用上没啥坏处
function selectImage(file) {
if (!file.files || !file.files[0]) {
return;
}
fileURL =window.URL.createObjectURL(file.files[0]) //转换为url对象
displayImage(fileURL);
//T$('file1').hidden="hidden" //隐藏标签
}
function displayImage(filePath){
document.getElementById("ref").value="";
circleNum = 0;
scale = -1;
thePoint = [];
isAngle = true;
CalCompleted = false;
var Oc=T$("oc");
var Gc=Oc.getContext("2d");
yImg.src=filePath;
yImg.onload=function(){
Oc.width= yImg.width;
Oc.height=yImg.height;
Gc.drawImage(yImg,0,0);//插入图片,给某一个区域插入背景图片,并设置平铺方式
};
}
function getPointOnCanvas(canvas,x,y){
var bbox = canvas.getBoundingClientRect();
return{x: (x-bbox.left) *(canvas.width / bbox.width),//求出鼠标的真实位置,然后乘以画布比例尺
y: (y-bbox.top) * (canvas.height / bbox.height)
};
}
function drawCircle(ctx,x,y,r,color){
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI*2);
ctx.lineWidth=2;
ctx.strokeStyle=color;//属性定义必须有,要不然重绘的时候,会以上一段线为蓝本
ctx.moveTo(x-2*r,y);
ctx.lineTo(x+2*r,y);
ctx.moveTo(x,y-2*r);
ctx.lineTo(x,y+2*r);
ctx.stroke();//绘制
ctx.closePath();//如果
}
document.onkeydown = function(e){
var e = e||event;
var currKey = e.keyCode||e.which||e.charCode;
if(currKey == 16){VerticalMode = true;}//shift 快捷键
};
document.onkeyup = function(e){
var e = e||event;
var currKey = e.keyCode||e.which||e.charCode;
if(currKey == 16){VerticalMode = false;}
}
鼠标点击事件:
此部分主要功能为1、更改当前模式;2、采集选定的点;3、计算长度与角度。
oc.onmousedown = function(e){//获取在画布上的鼠标点击事件
if(fileURL==""){
circleNum = 0;
return;
}//没有图片,直接返回
if(T$("ref").value == ""){
isAngle = true; // 设置当前模式为角度测量
scale = -1; // 清空比例
}else{ //否则判断是否需要重新计算比例
isAngle = false; // 设置当前模式为长度测量
if (T$("ref").value != reff){ //如果数字变了,后面要重新计算的
scale = -1;
reff = T$("ref").value
}
}
var canvas = T$("oc");
var ctx = canvas.getContext('2d');
var mpos = getPointOnCanvas(canvas,e.x,e.y);
var po = {
X: mpos.x,
Y: mpos.y
};
if(circleNum > 0 && VerticalMode){
if(Math.abs(thePoint[circleNum-1].X - po.X)>Math.abs(thePoint[circleNum-1].Y - po.Y)){
po.Y = thePoint[circleNum-1].Y;
}else if(Math.abs(thePoint[circleNum-1].X - po.X) 3){
ctx.drawImage(yImg,0,0);
circleNum = 0;
CalCompleted = false;
}
}else{ //计算距离
if(circleNum == 2){ //采集到两个点就能计算长度
if(scale == -1){
var dis = ((thePoint[0].X-thePoint[1].X)**2+(thePoint[0].Y-thePoint[1].Y)**2)**(1/2);
scale = reff/dis;
ctx.fillText("计算了比例:"+scale,10,50,200);
CalCompleted = true;
//T$('ca').hidden="hidden" //隐藏标签
}else{
var disRes = ((thePoint[0].X-thePoint[1].X)**2+(thePoint[0].Y-thePoint[1].Y)**2)**(1/2)*scale;
var xx = (thePoint[0].X+thePoint[1].X)/2;
var yy = (thePoint[0].Y+thePoint[1].Y)/2;
ctx.beginPath();
ctx.fillStyle="rgb(73,72,62)";
ctx.rect(0,10,210,50);
ctx.rect(xx-25,yy-15,50,30);
ctx.fill();
ctx.fillStyle="rgb(185,248,242)";
ctx.fillText("距离是:"+disRes.toFixed(3)+"mm",10,50,200);
ctx.fillText(disRes.toFixed(3),xx-25,yy+10,50);
CalCompleted = true;
}
}else if(circleNum > 2){
ctx.drawImage(yImg,0,0);
circleNum = 0;
CalCompleted = false;
}
}
}
鼠标移动事件:
此部分主要负责绘制给人看的东西
oc.onmousemove = function(e){
if (CalCompleted || circleNum == 0 || fileURL==""){return;} //屏蔽响应
var canvas = T$("oc");
var ctx = canvas.getContext('2d');
var mpos = getPointOnCanvas(canvas,e.x,e.y);
//ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(yImg,0,0);
ctx.beginPath(); //要改变线型,必须重新开始一个轨迹
ctx.lineWidth=2;
ctx.strokeStyle="rgb(2,100,30)";
ctx.moveTo(thePoint[0].X,thePoint[0].Y);
for (var i = 1; i <= circleNum; i++){
if (i == circleNum){
if(VerticalMode){
if(Math.abs(thePoint[circleNum-1].X - mpos.x)>Math.abs(thePoint[circleNum-1].Y - mpos.y)){
ctx.lineTo(mpos.x,thePoint[circleNum-1].Y)
}else if(Math.abs(thePoint[circleNum-1].X - mpos.x)
还是一贯的态度,非主业人士,需要用最简单的办法,解决想解决的问题,当然,还是要高标准,严要求的,所以抱着要好好学习的心态,经常要反过头来修改代码,增加功能,每当想要增加功能的时候,就能意识到写代码需要模块化的重要性,如果乱七八糟的一堆代码,相加任何一个小功能都要大改,与其如此,不如一开始就规划好,每一步写什么功能,完成后不再修改,直接增加新功能,如此这般才能让自己的代码健康长寿。