效果如下



代码如下:

//index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>触摸事件</title>
<link href="style.css" rel="stylesheet" type="text/css" />
<script src="main.js" defer></script>
</head>
<body>
<canvas id="canvas">
当前浏览器不支持 canvas 元素
</canvas>
<br>记录:
<pre id="log"></pre>
</body>
</html>
//main.js
const ongoingTouches = [];
const el = document.getElementById("canvas");
const ctx = el.getContext("2d"); window.onload = () => {
el.width = 600;
el.height = 600;
el.addEventListener("touchstart", handleStart, false);
el.addEventListener("touchend", handleEnd, false);
el.addEventListener("touchcancel", handleCancel, false);
el.addEventListener("touchmove", handleMove, false);
log("初始化成功。");
}; function handleStart(evt) {
evt.preventDefault();
log("触摸开始。");
const touches = evt.changedTouches; for (let i = 0; i < touches.length; i++) {
log("开始第 " + i + " 个触摸 ...");
ongoingTouches.push(copyTouch(touches[i]));
ctx.beginPath();
ctx.fillStyle = colorForTouch(touches[i]);
ctx.arc(touches[i].pageX, touches[i].pageY, 4, 0, 2 * Math.PI, false);
// 在起点画一个圆
ctx.fill();
log("第 " + i + " 个触摸已开始。");
}
} function handleMove(evt) {
evt.preventDefault();
const touches = evt.changedTouches;
for (let i = 0; i < touches.length; i++) {
const color = colorForTouch(touches[i]);
const idx = ongoingTouchIndexById(touches[i].identifier);
if (idx >= 0) {
log("继续第 " + idx + " 个触摸。");
ctx.beginPath();
log("ctx.moveTo(" + ongoingTouches[idx].pageX + ", " +
ongoingTouches[idx].pageY + ");");
ctx.moveTo(ongoingTouches[idx].pageX, ongoingTouches[idx].pageY);
ctx.lineWidth = 4;
ctx.fillStyle = color;
log("ctx.lineTo(" + touches[i].pageX + ", " + touches[i].pageY + ");");
ctx.lineTo(touches[i].pageX, touches[i].pageY);
ctx.strokeStyle = color;
ctx.stroke();
ongoingTouches.splice(idx, 1, copyTouch(touches[i])); // 切换到新触摸
log(".");
} else {
log("无法确定下一个触摸点。");
}
}
} function handleEnd(evt) {
evt.preventDefault();
log("触摸结束。");
const touches = evt.changedTouches;
for (let i = 0; i < touches.length; i++) {
const color = colorForTouch(touches[i]);
const idx = ongoingTouchIndexById(touches[i].identifier);
if (idx >= 0) {
ctx.lineWidth = 4;
ctx.fillStyle = color;
ctx.beginPath();
ctx.moveTo(ongoingTouches[idx].pageX, ongoingTouches[idx].pageY);
ctx.lineTo(touches[i].pageX, touches[i].pageY);
ctx.fillRect(touches[i].pageX - 4, touches[i].pageY - 4, 8, 8);
// 在终点画一个正方形
ongoingTouches.splice(idx, 1); // 用完后移除
} else {
log("无法确定下一个触摸点。");
}
}
} function handleCancel(evt) {
evt.preventDefault();
log("触摸取消。");
const touches = evt.changedTouches; for (let i = 0; i < touches.length; i++) {
const idx = ongoingTouchIndexById(touches[i].identifier);
ongoingTouches.splice(idx, 1); // 用完后删除
}
} // 以下是便捷函数 function colorForTouch(touch) {
const r = (touch.identifier % 16).toString(16);
const g = (Math.floor(touch.identifier / 3) % 16).toString(16);
const b = (Math.floor(touch.identifier / 7) % 16).toString(16);
const color = "#" + r + g + b;
log("identifier " + touch.identifier + " 的颜色为:" + color);
return color;
} function copyTouch(touch) {
return {
identifier: touch.identifier,
pageX: touch.pageX,
pageY: touch.pageY
};
} function ongoingTouchIndexById(idToFind) {
for (let i = 0; i < ongoingTouches.length; i++) {
const id = ongoingTouches[i].identifier; if (id == idToFind) {
return i;
}
}
return -1; // 未找到
} function log(msg) {
const p = document.getElementById('log');
p.innerHTML =
new Date().toString().substring(16, 24) + ' ' + msg + "\n" + p.innerHTML;
}
//style.css
body {
padding: 0;
margin: 10px
} svg:not(:root) {
display: block
} .playable-code {
background-color: #f4f7f8;
border: none;
border-left: 6px solid #558abb;
border-width: medium medium medium 6px;
color: #4d4e53;
height: 100px;
width: 90%;
padding: 10px 10px 0
} .playable-canvas {
border: 1px solid #4d4e53;
border-radius: 2px
} .playable-buttons {
text-align: right;
width: 90%;
padding: 5px 10px 5px 26px
} #canvas {
border: 1px solid #000;
} #log {
border: 1px solid #ccc;
}

touch-paint的更多相关文章

  1. 【appium】根据accessibility_id定位元素

    如何获得AccessibilityId 可以通过UIAutomatorViewer或者Appium Inspector获得.Accessibility ID在Android上面就等同于contentD ...

  2. android中自定义view---实现竖直方向的文字功能,文字方向朝上,同时提供接口,判断当前touch的是哪个字符,并改变颜色

    android自定义view,实现竖直方向的文字功能,文字方向朝上,同时提供接口,判断当前touch的是哪个字符,并改变颜色. 由于时间比较仓促,因此没有对代码进行过多的优化,功能远远不如androi ...

  3. Android事件处理第一节(View对Touch事件的处理)

    http://ipjmc.iteye.com/blog/1694146 在Android里Touch是很常用的事件,尤其实在自定义控件中,要实现一些动态的效果,往往要对Touch进行处理.Androi ...

  4. Android Touch事件之一:Touch事件在父ViewGroup和子View之间的传递篇

    2015-11-26 17:00:22 前言:Android的Touch事件传递和View的实现紧密相连,因此理解Touch事件的传递,有助于我们更好的理解View的工作原理. 1. 几个重要的方法: ...

  5. Xamarin.Forms实现touch事件

    Xamarin.Forms的View没有touch事件,只能自己实现 首先,在共享项目里面,放入这几个类,结构大概是这样的: using System; using Xamarin.Forms; na ...

  6. 详解Paint的setXfermode(Xfermode xfermode)

    一.setXfermode(Xfermode xfermode) Xfermode国外有大神称之为过渡模式,这种翻译比较贴切但恐怕不易理解,大家也可以直接称之为图像混合模式,因为所谓的“过渡”其实就是 ...

  7. android Canvas 和 Paint用法

    自定义view里面的onDraw方法,在这里我们可以绘制各种图形,onDraw里面有两个API我们需要了解清楚他们的用法:Canvas 和 Paint. Canvas翻译成中文就是画布的意思,Canv ...

  8. mkdir,rmdir,cp,rm,mv,cat,touch用法

    一.mkdir新建目录 1.进入tmp目录,查看该目录下面的子目录 [root@localhost ~]# cd /tmp[root@localhost tmp]# lshsperfdata_root ...

  9. UC浏览器中touch事件的异常记录

    以前也在UC上面栽过几个坑,不过都是页面显示方面的.上个周的时候,商品详情页重做,要添加个上拉显示详情的效果. 有两个条件需要判断: 1.是否到达底部: 2.到达底部之后拖动的y轴距离. 效果写完后, ...

  10. 移动端web开发,click touch tap区别

    转自: http://blog.csdn.net/sly94/article/details/51701188 移动端用tap时会有穿透问题 一:click与tap比较 click与tap都会触发点击 ...

随机推荐

  1. MyCat数据库中间件 - 分库

    MyCat MyCat用于解耦分布式数据库与java,比如分库分表以后,需要查询某条数据时,需要java根据需要查的数据先计算去哪个库查,然而有了Mycat就不用自己计算怎么存储,怎么查询了.MyCa ...

  2. GlusterFS 安装配置

    1.磁盘格式化 mkfs.xfs -i size=512 /dev/vdb1 mkdir -p /data/brick1 cat > /etc/fstab <<EOF /dev/vd ...

  3. zabbix自定义监控项

    原因:zabbix监控系统自带的监控规则有限,如果需要更加灵活的定义监控项,可以通过修改配置文件实现 vim xxx/zabbix_agentd.conf UnsafeUserParameters=1 ...

  4. java构造器和构建器

    本文摘自:https://blog.csdn.net/wh2827991/article/details/79013115 在实例化一个类的过程中,通常会遇到多个参数的构造函数,但如果有些参数是非必需 ...

  5. LOADING Redis is loading the dataset in memory Redis javaAPI实例

    今天在实现Redis客户端API操作Jedis的八种调用方式详解中,遇到了LOADING Redis is loading the dataset in memory错误,经过多番查找资料,找到了解决 ...

  6. spring 在容器中一个bean依赖另一个bean 需要通过ref方式注入进去 通过构造器 或property

    spring  在容器中一个bean依赖另一个bean 需要通过ref方式注入进去 通过构造器 或property

  7. luoguP4035

    P4035 [JSOI2008]球形空间产生器 Description 有一个球形空间产生器能够在n维空间中产生一个坚硬的球体.现在,你被困在了这个n维球体中,你只知道球面上n+1个点的坐标,你需要以 ...

  8. THEPYTHONCHALLENG闯关记录

    由于是自己看视频学python,总觉得不写几行代码就什么都没有学到. 找了一个写代码的网站其实只是因为这个看起来好玩. 闯关地址http://www.pythonchallenge.com/index ...

  9. 前端nginx+Java后台ftp处理页面图片上传踩坑

    今天,将前端代码部署到服务器nginx上,在测试多图片上传时,报错413请求体空间太大,请求都没到后台,直接被nginx拦截,调整后又报错504. 整体而言,前端存在两处问题: 413 错误 :Req ...

  10. docker registry v2与harbor的搭建

    docker的仓库 1 registry的安装 docker的仓库我们可以使用docker自带的registry,安装起来很简单,但是可能有点使用起来不是很方便.没有图形化. 开始安装 使用镜像加速器 ...