`

snap.svg.js学习------时间认知

阅读更多
  wallimn原创,欢迎转载,原文地址:http://wallimn.iteye.com/blog/2374931
  最近儿子学校教时间认知,动手做了这样一个小软件。功能很简单:在手机上使用,手指按住钮表针可以拖动表针,改变时间,点击下面按钮可显示时间,验证小朋友时间认知是否正确。
  界面如下图所示:




  用到的相关技术:snap.svg.js、hammer.js、jQuery.js。对于svg绘制、svg动画、触屏事件处理有一定的借鉴意义。
  代码没有仔细推敲与封装,随便玩玩而已。

  所有代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<!--
	作者: wallimn, http://wallimn.iteye.com
	时间:2017年1月7日
	功能:snap.svg.js学习之-时间认知
-->
<html lang="zh-cn">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
	<meta http-equiv="pragma" content="no-cache">  
	<meta http-equiv="cache-control" content="no-cache">  
	<meta http-equiv="expires" content="0">     
	<c:set var="ctx" value="${pageContext.request.contextPath}"></c:set>
    <title>时间认知-wallimn</title>

    <!-- Bootstrap -->
    <link href="${ctx}/css/bootstrap.min.css" rel="stylesheet">

    <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
      <script type="text/javascript" src="${ctx}/js/html5shiv.min.js"></script>
      <script type="text/javascript" src="${ctx}/js/respond.min.js"></script>
    <![endif]-->
    <style type="text/css">
    	html,body{
    		width:100%;
    		height:100%;
    	}
		#svg {
			margin:0;
			position:relative;
			top:50%;
			border-radius:5px;
			border:1px solid #efefef;
		}
		text{
			font-size:14px;
		}
    </style>
  </head>
  <body>
  
 
	<svg id='paper'></svg>
  
  
    <script type="text/javascript" src="${ctx}/js/jquery-1.11.1.min.js"></script>
	<script type="text/javascript" src="${pageContext.request.contextPath}/js/snap.svg.js"></script>
	<script type="text/javascript" src="${pageContext.request.contextPath}/js/hammer-2.0.8.js"></script>
    
	<script type="text/javascript">
	
	    $(function(){
	    	//阻止长按网页出现菜单
	    	window.ontouchstart = function(e) { e.preventDefault(); }
	    	var clientWidth=document.body.clientWidth;
	    	var clientHeight=document.body.clientHeight;
			$("#paper").css("width",clientWidth+"px").css("height",clientHeight+"px");
	    	var minsize = Math.min(clientWidth,clientHeight);
	    	var paper = Snap("#paper");
	    	
	    	var centerX=clientWidth/2, centerY=clientHeight/2 ;
	    	
	    	
	    	var radius =Math.round( minsize/2*0.8);
	    	var hourLen = Math.round(radius*0.65),hourDeta=6;//时针长度
	    	var minLen = Math.round(radius*0.8),minDeta=12;//分针长度
	    	var numLen =  Math.round(radius*0.86);//数字半径
	    	
	    	var clock = paper.circle(centerX,centerY,radius);
	    	clock.attr({fill:'#0000cc',stroke:'#0000ff',strokeWidth:6,'fill-opacity':0.6});
	    	
	    	var x,y,ang;
	    	for(var i=0; i<12; i++){
	    		ang = Math.PI/2-i*2*Math.PI/12-30*Math.PI/180;
	    		x = centerX+numLen*Math.cos(ang);
	    		y = centerY-numLen*Math.sin(ang);
	    		paper.text(x,y,i+1).attr({'text-anchor':'middle','dominant-baseline':'middle','font-size':32});
	    	}
	    	
	    	var hourHand = paper.polygon(centerX-hourDeta*2,centerY,centerX,centerY+hourDeta,centerX+hourLen,centerY,centerX,centerY-hourDeta,centerX-hourDeta*2,centerY).attr({stroke:'black',"data-id":'hourHand',"data-selected":'false',"data-angle":0,strokeWidth:2,strokeOpacity:0.8,'fill-opacity':0.5,fill:'black'});
	    	var minHand = paper.polygon(centerX-minDeta*2,centerY,centerX,centerY+minDeta,centerX+minLen,centerY,centerX,centerY-minDeta,centerX-minDeta*2,centerY).attr({stroke:'black',"data-id":'minHand',"data-selected":'false',"data-angle":0,strokeWidth:2,strokeOpacity:0.8,'fill-opacity':0.5,fill:'black'});
	    	
	    	window.hourHand = hourHand;
	    	window.minHand = minHand;
	    	
	    	//旋转表针的函数
	    	function rotateHand(hand,resultAng){
	    		var oldang = hand.attr("data-angle");
	    		if(resultAng<0)resultAng=360+resultAng;
	    		else if (resultAng>360)resultAng = resultAng-360;
	    		//console.log("初始角度:",oldang,",最终角度:",resultAng);
	    		//Snap.Matrix().rotate()函数中指定的角度是最终结果的角度。
	    		//hand.transform(new Snap.Matrix().rotate(resultAng,centerX,centerY));
	    		Snap.animate(oldang,resultAng,function(value){
	    			hand.transform(new Snap.Matrix().rotate(value,centerX,centerY));
	    		},100);
	    		hand.attr({"data-angle":resultAng});
	    	}
	    	
	    	//初始状态设置
	    	rotateHand(hourHand,-90);
	    	rotateHand(minHand,-90);
	    	
	    	
	    	var minHanmmer = new Hammer($('[data-id=minHand]')[0]);
	    	minHanmmer.add(new Hammer.Pan({direction:Hammer.DIRECTION_ALL,threshold:0}));
	    	minHanmmer.on("panstart",function(ev){
	    		var element = $(ev.target);
	    		element.attr("stroke","red");
	    		element.attr("data-selected",'true');
	    	});
	    	minHanmmer.on("panend",function(ev){
	    		$(ev.target).attr("stroke","black").attr("data-selected",'false');
	    	});
	    	minHanmmer.on("panmove",function(ev){
	    		if(minHand.attr("data-selected")=='true' && ev.pointers.length>=1){
	    			var px = ev.pointers[0].clientX;
	    			var py = ev.pointers[0].clientY;
	    			var ang = Math.atan2((py-centerY),(px-centerX))*180/Math.PI;
	    			if(ang<0)ang=360+ang;
	    			var deta =ang- parseFloat(minHand.attr("data-angle"));
	    			if(deta<-300)deta=deta+360;
	    			else if(deta>300)deta=deta-360;
	    			var hourAng = parseFloat(hourHand.attr("data-angle"))+deta/12.0;
	    			
	    			rotateHand(minHand,ang);
	    			rotateHand(hourHand,hourAng);
	    		}
	    	});

	    	
	    	var hourHanmmer = new Hammer($('[data-id=hourHand]')[0]);
	    	hourHanmmer.add(new Hammer.Pan({direction:Hammer.DIRECTION_ALL,threshold:0}));
	    	hourHanmmer.on("panstart",function(ev){
	    		var element = $(ev.target);
	    		element.attr("stroke","red");
	    		element.attr("data-selected",'true');
	    	});
	    	hourHanmmer.on("panend",function(ev){
	    		$(ev.target).attr("stroke","black").attr("data-selected",'false');
	    	});
	    	hourHanmmer.on("panmove",function(ev){
	    		if(hourHand.attr("data-selected")=='true'){
	    			var px = ev.pointers[0].clientX;
	    			var py = ev.pointers[0].clientY;
	    			var ang = Math.atan2((py-centerY),(px-centerX))*180/Math.PI;
	    			if(ang<0)ang=360+ang;
	    			var deta =ang- parseFloat(hourHand.attr("data-angle"));
	    			if(deta<-300)deta=deta+360;
	    			else if(deta>300)deta=deta-360;
	    			var hourAng = parseFloat(minHand.attr("data-angle"))+deta*12;
	    			
	    			rotateHand(hourHand,ang);
	    			rotateHand(minHand,hourAng);
	    		}
	    	});
	    	
	    	//输出提示文字
	    	var tipText = paper.text(centerX,centerY*2-8,"按住表针拖动可移动表针").attr({'text-anchor':'middle','dominant-baseline':'middle',fill:'red','font-size':12});
	    	//绘制按钮、并设置事件
	    	var textdeta=40;//文字中心跟底端的距离
	    	var whenText = paper.text(centerX,centerY*2-textdeta,"几点了?").attr({'text-anchor':'middle','dominant-baseline':'middle','font-size':24});
	    	var bbox = whenText.getBBox();
	    	var detax=5,detay=8;
	    	var whenRect = paper.rect(centerX-bbox.width/2-detax,centerY*2-textdeta-bbox.height/2-detay,
	    			bbox.width+detax*2,bbox.height+detay*2,3,3);
	    	whenRect.attr({fill:'#00ff00',stroke:'#00ff00',strokeWidth:1,'fill-opacity':0.1});
	    	var whenHanmmer = new Hammer(whenRect.node);
	    	//阻止了touchstart事件后,click事件就不好使用了。只能用tap事件了。
	    	whenHanmmer.on("tap",function(){
	    		var hourAng = hourHand.attr("data-angle");
	    		hourAng = hourAng-270;//与指针相匹配的角度
	    		if(hourAng<0)hourAng=hourAng+360;
	    		var hourNum = Math.floor(hourAng/30);
	    		if(hourNum==0)hourNum=12;
	    		
	    		
	    		var minAng = minHand.attr("data-angle");
	    		minAng = minAng-270;
	    		if(minAng<0)minAng=minAng+360;
	    		var minNum = Math.round(minAng/6);
	    		if(minNum==60)minNum=0;
	    		//console.log("时针角度:",hourAng,",分针角度:",minAng,",时间",hourNum+":"+minNum);
	    		alert("时间:"+hourNum+":"+minNum);
	    	});
		});
	</script>
  </body>
</html>


  代码上传到github.com,访问地址:https://github.com/wallimn/snapcat,猛戳下载全部程序。

  手机体验,请使用微信扫描下面二维码,不需关注、不需注册、不需下载:


  • 大小: 27.9 KB
  • 大小: 8.3 KB
1
1
分享到:
评论

相关推荐

    Kaedwen-Redania-Nilfgaard-SVG-Icons-animations:АнимацияSVGиконокКаэдвена,РеданиииНильфгаарда

    另外,JavaScript库如Snap.svg或GreenSock也可以帮助更复杂动画的实现,提供更精细的控制和丰富的功能。 在实际应用中,这些SVG图标动画不仅可以用作导航菜单的指示器,还可以作为页面加载进度的可视化元素,或是...

    matlab实现四旋翼无人机自抗扰姿态容错控制-飞行器控制-四旋翼无人机-自抗扰控制-UAV-扰动识别-matlab

    内容概要:文章深入探讨了四旋翼无人机(UAV)在复杂环境下面临的挑战,特别是在面对风力、气流及传感器故障等情况时的稳定性问题。通过引入自抗扰姿态容错控制策略,解决了传统PID控制方法鲁棒性和容错能力不足的问题。该控制策略涵盖传感器测量、姿态估计、理想模型构建、扰动识别、控制设计及自抗扰控制等内容,并利用MATLAB进行了详细仿真实验,验证了策略的有效性。具体而言,传感器数据经过卡尔曼滤波融合处理,提高了姿态估计准确性;采用扩张状态观测器(ESO)实时估算扰动,增强抗干扰能力;通过故障检测与恢复机制,确保飞行安全可靠。 适用人群:从事无人飞行器研究的技术人员、高校教师及研究生,特别是关注无人机控制系统设计和优化的人群。 使用场景及目标:适用于科研实验室及工业环境中对四旋翼无人机飞行控制系统的开发测试;目标是在提高四旋翼无人机飞行稳定性和可靠性的同时,优化控制参数,满足不同场景的任务需求。 其他说明:文中不仅介绍了理论知识和技术细节,还给出了详细的MATLAB源代码实现方式,帮助读者更快理解和实践相关概念。同时指出未来的研究方向,为进一步探索四旋翼无人机的控制技术和实际应用提供指导。

    【毕业设计】Python-Django-html深度学习文本相似度检测系统(bert)源码(完整前后端+mysql+说明文档+LW+PPT).zip

    【毕业设计】Python-Django-html深度学习文本相似度检测系统(bert)源码(完整前后端+mysql+说明文档+LW+PPT).zip

    外卖侠v5.0.5小程序源码+前端.zip

    外卖侠小程序v5.05 前端 1、修复美团联盟不显示二维码的问题; 2、修复电商搜索京东商品翻页商品重复的问题; 3、优化联营用户同步机制; ***本次更新【需要】重新上传前端审核*** 外卖模块使用文档: https://docs.qq.com/doc/DS0JmWFNYdHZZWEVS 外卖模块z新全套视频教程: 链接:https://pan.baidu.com/s/1qMBzn-csUTpTFZ4hekbMtQ 提取码:waim 外卖侠小程序v5.05 前端%插图%

    web api 全局动态路由处理

    web api 全局动态路由处理 一个api controller通过全局配置,适配多个路由,

    VSTD 19-1 Flammability of the interior materials for motor vehicle.pdf

    VSTD 19-1 Flammability of the interior materials for motor vehicle.pdf

    基于改进粒子群算法的微电网多目标优化调度策略:降低能耗与环保成本的有效方案,基于改进粒子群算法的微电网多目标优化调度策略:降低能耗与环保成本的有效方案,基于改进粒子群算法的微电网多目标优化调度 微电

    基于改进粒子群算法的微电网多目标优化调度策略:降低能耗与环保成本的有效方案,基于改进粒子群算法的微电网多目标优化调度策略:降低能耗与环保成本的有效方案,基于改进粒子群算法的微电网多目标优化调度 微电网优化调度作为智能电网优化的重要组成部分,对降低能耗、环境污染具有重要意义。 微电网的发展目标既要满足电力供应的基本需求,又要提高经济效益和环境保护。 对此,提出了一种综合考虑微电网系统运行成本和环境保护成本的并网模式下微电网多目标优化调度模型。 同时采用改进的粒子群算法对优化模型进行求解。 仿真结果表明,该模型可以有效降低用户的用电成本和环境污染,促进微电网的优化运行,并验证了改进的粒子群算法的优越性能 ,基于改进粒子群算法;微电网多目标优化调度;微电网优化;降低能耗;环境保护成本。,基于改进粒子群算法的微电网多目标优化调度与环境保护的协同策略

    清华大学DeepSeek手册:政企与创业者必备的AI发展指南及应用路径

    内容概要:本文详细解读了清华大学DeepSeek课堂内容,探讨AI在政企、创业领域的重大发展机遇与应用场景,特别强调了大模型的发展及其对企业转型和智能化的重要意义。文中通过具体案例介绍了AI在各个行业的应用,包括但不限于智能制造、科学研究等,突出了AI在重塑社会经济结构中的关键地位,并针对当前和未来的AI应用提出了明确的发展路径与策略指导。 适合人群:政府机构工作人员、企业管理者、创业者和技术研发人员。 使用场景及目标:用于理解AI在政企中的应用场景,探索基于DeepSeek的企业转型升级策略;帮助企业制定智能化发展规划;推动科技创新和社会经济发展。 其他说明:课程内容还涉及AI的安全性和伦理道德等问题,提供了关于构建负责任的AI系统的见解,并对未来可能出现的新形势给予了预测与分析。

    SpringBoot 3.x + Netty + MQTT 实战物联网智能充电桩

    一、什么是物联网(IoT) 物联网(Internet of Things,简称 IoT)是指通过互联网连接和通信的物理设备和对象的网络。它是一个由传感器、软件和通信设备组成的系统,可以使各种设备和物品相互连接,并通过数据交换和分析来提供更智能、高效和自动化的功能。 物联网的主要目标是将真实世界的物体与互联网相连,使其具备感知、交互和通信的能力。通过物联网,可以实现智能家居、智慧城市、工业自动化、农业监测、智能交通等应用。 二、为什么需要物联网? 物联网的出现主要是为了解决日常生活和工作中的一些实际问题。例如,在智能家居中,可以通过物联网连接家中的各种设备,如智能灯泡、智能插座、智能门锁等,从而实现远程控制、自动化调节和能源管理,提高家居的舒适度和能源利用效率。 此外,物联网在工业领域也发挥着重要作用。传统的工业生产过程通常需要大量的人力和物力投入,而物联网可以通过连接和监控各种设备和环境参数,实现生产过程的自动化和优化,提高生产效率和产品质量。例如在石油行业,可以利用物联网技术来监测阀门的状态和运行情况。通过安装传感器和执行器在阀门上,可以实时监测阀门的开启、关闭状态、温度、压力

    通过使用AGM迭代公式和高精度数学计算开源库gmp计算圆周率小数点后1000位C语言代码

    通过使用AGM迭代公式和高精度数学计算开源库gmp计算圆周率小数点后1000位C语言代码

    DDR4 DQ 不同参数 波形眼图对比 20230505

    仿真笔记

    【毕业设计】基于Python的Django-html开放领域事件抽取系统源码(完整前后端+mysql+说明文档+LW+PPT).zip

    【毕业设计】基于Python的Django-html开放领域事件抽取系统源码(完整前后端+mysql+说明文档+LW+PPT).zip

    奶牛的行为识别数据集,可识别牛在吃,躺着,站着,喝水等行为,平均正确识别率在83.0%, yolov11格式标注

    奶牛的行为识别数据集,可识别牛在吃,躺着,站着,喝水等行为,平均正确识别率在83.0%, yolov11格式标注

    轻量级年会抽奖系统源码

    项目采用轻量级架构,采用的是Springboot3.x、html + elementUI + vue.js + Three.js + axios、H2 database、jdk21等技术实现,接口请求访问使用了jwt验证,直接运行即可使用

    hymenoptera-data 数据集

    hymenoptera_data

    【毕业设计】SpringBoot+vue仓储物流管理系统【源码+论文+答辩ppt+开题报告+任务书】.zip

    【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。

    移动应用开发全攻略:工具选用、环境搭建与调试技巧

    内容概要:本文详述了移动应用开发过程中所需的各种工具、环境设置方法以及调试技术与注意事项。首先介绍了常见的几种开发工具——针对iOS和Android的原生开发工具如Xcode和Android Studio,以及跨平台开发工具如React Native、Flutter、Xamarin,还有适用于初学者的低代码平台Appery.io。其次讨论了不同系统下开发环境的具体配置步骤及其所用到的重要集成开发环境。接着,讲解了几种主流的调试手段,从网络请求、性能瓶颈、布局展示等方面提出针对性解决办法。最后指出开发时要注意用户实际操作体验的安全便捷性和法规遵从等问题。 适用人群:有一定编程基础和技术背景的学习者,想要深入移动开发领域的工程师。 使用场景及目标:①作为新手或转行者学习移动应用程序的制作;②有经验开发者希望提升效率,改善产品品质;③企业内部培训资料帮助成员掌握最新的技术和规范标准。 其他说明:移动开发领域不断变化更新速度快,在理解和掌握了文中提到的内容基础上还需要持续关注行业的前沿动态和技术进步。

    Deepseek满血版API接入

    Deepseek满血版API接入

    MATLAB下电转气协同与碳捕集垃圾焚烧虚拟电厂优化调度复现程序及仿真结果展示,MATLAB下电转气协同与碳捕集垃圾焚烧虚拟电厂优化调度复现程序及仿真结果展示,MATLAB代码:计及电转气协同的含碳捕

    MATLAB下电转气协同与碳捕集垃圾焚烧虚拟电厂优化调度复现程序及仿真结果展示,MATLAB下电转气协同与碳捕集垃圾焚烧虚拟电厂优化调度复现程序及仿真结果展示,MATLAB代码:计及电转气协同的含碳捕集与垃圾焚烧电厂优化调度 关键词:碳捕集 电厂 需求响应 优化调度 电转气协同调度 参考文档:《计及电转气协同的含碳捕集与垃圾焚烧电厂优化调度》复现程序 仿真平台:MATLAB+CPLEX 使用的是yalmip+cplex求解器完成求解,拿后前可以看运行结果,可以看参考文档 ,碳捕集; 虚拟电厂; 需求响应; 优化调度; 电转气协同调度; YALMIP+CPLEX求解器; MATLAB复现程序。,基于YALMIP+CPLEX的碳捕集与垃圾焚烧虚拟电厂协同优化调度程序

    永磁同步电机PMSM模型搭建与Simulink仿真分析,自己搭建的Simulink永磁同步电机PMSM模型解析与实践体验,自己搭的永磁同步电机PMSM模型 simulink模型 ,PMSM模型; Si

    永磁同步电机PMSM模型搭建与Simulink仿真分析,自己搭建的Simulink永磁同步电机PMSM模型解析与实践体验,自己搭的永磁同步电机PMSM模型 simulink模型 ,PMSM模型; Simulink模型; 永磁同步电机模型搭建。,基于Simulink的PMSM(永磁同步电机)模型构建与仿真

Global site tag (gtag.js) - Google Analytics