最近儿子学校教时间认知,动手做了这样一个小软件。功能很简单:在手机上使用,手指按住钮表针可以拖动表针,改变时间,点击下面按钮可显示时间,验证小朋友时间认知是否正确。
界面如下图所示:
用到的相关技术: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,猛戳下载全部程序。
手机体验,请使用微信扫描下面二维码,不需关注、不需注册、不需下载: