├── README.md ├── hand-writting ├── index.css ├── index.html └── index.js ├── ball-animation ├── ball1.html └── ball2.html └── charts └── charts.html /README.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 3 | 此目录是canvas练习的demo 4 | 5 | ``` 6 | . 7 | |____ball-animation 球的运动demo 8 | | |____ball1.html 单个小球滚动 9 | | |____ball2.html 多个小球滚动 10 | |____charts canvas绘制图表demo 11 | | |____charts.html 柱状图,适配H5的分辨率 12 | |____hand-writting imooc学写一个字demo 13 | | |____index.css 14 | | |____index.html 15 | | |____index.js 16 | |____README.md 17 | 18 | ``` -------------------------------------------------------------------------------- /hand-writting/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | body { 6 | padding-top: 10px; 7 | } 8 | .write-area { 9 | display: block; 10 | margin: 0 auto; 11 | } 12 | .ctrl { 13 | width: 100%; 14 | max-width: 800px; 15 | padding: 0 10px; 16 | box-sizing: border-box; 17 | margin: 0 auto; 18 | } 19 | .op-btn { 20 | float: right; 21 | margin: 10px 0 0 10px; 22 | border: 2px solid #aaa; 23 | width: 80px; 24 | height: 40px; 25 | line-height: 40px; 26 | font-size: 20px; 27 | text-align: center; 28 | border-radius: 5px 5px; 29 | cursor: pointer; 30 | background-color: white; 31 | font-weight: bold; 32 | font-family: 'Microsoft Yahei', Arial; 33 | } 34 | .op-btn { 35 | background-color: #def; 36 | } 37 | .clearfix { 38 | clear: both; 39 | } 40 | .btn-color { 41 | float: left; 42 | margin: 10px 10px 0 0; 43 | border: 5px solid white; 44 | width: 40px; 45 | height: 40px; 46 | border-radius: 5px 5px; 47 | cursor: pointer; 48 | } 49 | .btn-color:hover { 50 | border: 5px solid violet; 51 | } 52 | .btn-color-selected { 53 | border: 5px solid blueviolet; 54 | } 55 | .btn-black { 56 | background-color: #000; 57 | } 58 | .btn-blue { 59 | background-color: blue; 60 | } 61 | .btn-green { 62 | background-color: green; 63 | } 64 | .btn-red { 65 | background-color: red; 66 | } 67 | .btn-orange { 68 | background-color: orange; 69 | } 70 | .btn-yellow { 71 | background-color: yellow; 72 | } -------------------------------------------------------------------------------- /hand-writting/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 学写一个字 6 | 7 | 8 | 9 | 10 | 11 | 你的浏览器不支持canvas 12 | 13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | 21 |
清除
22 |
23 |
24 | 25 | 52 | 53 | -------------------------------------------------------------------------------- /ball-animation/ball1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | canvas 6 | 7 | 8 | 9 | 当前浏览器不支持canvas功能,请升级浏览器 10 | 11 | 12 | 102 | 103 | -------------------------------------------------------------------------------- /ball-animation/ball2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 当前浏览器不支持Canvas,请更换浏览器后再试 10 | 11 | 12 | 113 | 114 | -------------------------------------------------------------------------------- /charts/charts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | canvas练习 7 | 21 | 22 | 23 | 24 | 180 | 181 | -------------------------------------------------------------------------------- /hand-writting/index.js: -------------------------------------------------------------------------------- 1 | var handWritting = function (params) { 2 | if (!(this instanceof handWritting)) { 3 | return new handWritting(params); 4 | } 5 | var defaultParams = { 6 | width: 800, //画布宽度 7 | height: 800, //画布高度 8 | color: '#000', //笔画颜色 9 | maxLineWidth: 30, //最大笔画宽度 10 | minLineWidth: 1, //最小笔画宽度 11 | maxStrokeV: 10, //最大笔画速度 12 | minStrokeV: 0.1 //最小笔画速度 13 | }; 14 | params = Object.assign({}, defaultParams, params); 15 | 16 | this.canvas = params.canvas; 17 | this.canvasWidth = params.width; 18 | this.canvasHeight = params.height; 19 | this.strokeColor = params.color; 20 | this.maxLineWidth = params.maxLineWidth; 21 | this.minLineWidth = params.minLineWidth; 22 | this.maxStrokeV = params.maxStrokeV; 23 | this.minStrokeV = params.minStrokeV; 24 | var context = canvas.getContext('2d'); 25 | 26 | canvas.width = this.canvasWidth; 27 | canvas.height = this.canvasHeight; 28 | 29 | var that = this; 30 | 31 | //画虚线算法 32 | var drawDashLine = function (ctx, x1, y1, x2, y2, dashLength){ 33 | var dashLen = dashLength === undefined ? 5 : dashLength, 34 | xpos = x2 - x1, //得到横向的宽度; 35 | ypos = y2 - y1, //得到纵向的高度; 36 | numDashes = Math.floor(Math.sqrt(xpos * xpos + ypos * ypos) / dashLen); 37 | //利用正切获取斜边的长度除以虚线长度,得到要分为多少段; 38 | for (var i = 0; i < numDashes; i++) { 39 | if (i % 2 === 0) { 40 | ctx.moveTo(x1 + (xpos/numDashes) * i, y1 + (ypos/numDashes) * i); 41 | //有了横向宽度和多少段,得出每一段是多长,起点 + 每段长度 * i = 要绘制的起点; 42 | } else { 43 | ctx.lineTo(x1 + (xpos/numDashes) * i, y1 + (ypos/numDashes) * i); 44 | } 45 | } 46 | ctx.stroke(); 47 | }; 48 | 49 | //画米字格 50 | var drawGrid = function (ctx, width, height) { 51 | //save和restore是为了还原两者之间的代码对ctx做的状态设置,如strokeStyle。 52 | ctx.save(); 53 | 54 | //画外框 55 | ctx.strokeStyle = 'rgb(230, 11, 9)'; 56 | ctx.beginPath(); 57 | ctx.moveTo(3, 3); 58 | ctx.lineTo(width - 3, 3); 59 | ctx.lineTo(width - 3, height - 3); 60 | ctx.lineTo(3, height - 3); 61 | ctx.closePath(); 62 | ctx.lineWidth = 6; 63 | ctx.stroke(); 64 | 65 | //画米字 66 | ctx.beginPath(); 67 | ctx.lineWidth = 1; 68 | var dashLength = 10; 69 | drawDashLine(ctx, 0, 0, width, height, dashLength); 70 | drawDashLine(ctx, width, 0, 0, height, dashLength); 71 | drawDashLine(ctx, width/2, 0, width/2, height, dashLength); 72 | drawDashLine(ctx, 0, height/2, width, height/2, dashLength); 73 | 74 | ctx.restore(); 75 | }; 76 | 77 | 78 | var isMouseDown = false; 79 | //记录上一时刻鼠标移动到的位置 80 | var lastLoc = { 81 | x: 0, 82 | y: 0 83 | }; 84 | //记录上一时刻触发动作的时间,用于计算运笔速度而设置笔画宽度 85 | var lastTimeStamp = 0; 86 | //记录上一时刻的笔画宽度,而让笔画值能平稳过渡 87 | var lastLineWidth = -1; 88 | 89 | //计算基于target的点击位置 90 | var parsePositionToWindow = function (target, x, y) { 91 | var bbox = target.getBoundingClientRect(); 92 | return { 93 | x: Math.round(x - bbox.left), 94 | y: Math.round(y - bbox.top) 95 | }; 96 | }; 97 | //计算两点之间的距离 98 | var calDistance = function (loc1, loc2) { 99 | return Math.sqrt((loc1.x - loc2.x) * (loc1.x - loc2.x) + 100 | (loc1.y - loc2.y) * (loc1.y - loc2.y)); 101 | }; 102 | var calcLineWidth = function (s, t, maxL, minL, maxV, minV) { 103 | var v = s / t; 104 | var resultLineWidth; 105 | if (v <= minV) { 106 | resultLineWidth = maxL 107 | } else if (v >= maxV) { 108 | resultLineWidth = minL; 109 | } else { 110 | resultLineWidth = maxL - (v - minV) / 111 | (maxV - minV) * (maxL - minL); 112 | } 113 | if (lastLineWidth === -1) { 114 | return resultLineWidth; 115 | } 116 | //平缓过渡笔画,需要上一次的笔画值做平均值 117 | return lastLineWidth * 2 / 3 + resultLineWidth / 3; 118 | }; 119 | //开始绘制 120 | var beginStroke = function (target, x, y) { 121 | lastLoc = parsePositionToWindow(target, x, y); 122 | lastTimeStamp = new Date().getTime(); 123 | isMouseDown = true; 124 | }; 125 | //结束绘制 126 | var endStroke = function () { 127 | isMouseDown = false; 128 | }; 129 | //移动过程中的绘制 130 | var moveStroke = function (target, x, y) { 131 | var curLoc = parsePositionToWindow(target, x, y); 132 | var distance = calDistance(curLoc, lastLoc); 133 | var currentTime = new Date().getTime(); 134 | var takeTime = currentTime - lastTimeStamp; 135 | var lineWidth = calcLineWidth(distance, takeTime, that.maxLineWidth, 136 | that.minLineWidth, that.maxStrokeV, that.minStrokeV); 137 | 138 | context.strokeStyle = that.strokeColor; 139 | context.lineWidth = lineWidth; 140 | context.lineCap = 'round'; 141 | context.lineJoin = 'round'; 142 | 143 | //每一点画一段直线 144 | context.beginPath(); 145 | context.moveTo(lastLoc.x, lastLoc.y); 146 | context.lineTo(curLoc.x, curLoc.y); 147 | context.stroke(); 148 | 149 | lastLoc = curLoc; 150 | lastTimeStamp = currentTime; 151 | lastLineWidth = lineWidth; 152 | }; 153 | canvas.addEventListener('mousedown', function(e) { 154 | e.preventDefault(); 155 | beginStroke(e.target, e.clientX, e.clientY); 156 | }); 157 | canvas.addEventListener('mouseup', function(e) { 158 | e.preventDefault(); 159 | endStroke(); 160 | }); 161 | canvas.addEventListener('mouseout', function(e) { 162 | e.preventDefault(); 163 | endStroke(); 164 | }); 165 | canvas.addEventListener('mousemove', function(e) { 166 | e.preventDefault(); 167 | if (isMouseDown) { 168 | moveStroke(e.target, e.clientX, e.clientY); 169 | } 170 | }); 171 | canvas.addEventListener('touchstart', function (e) { 172 | e.preventDefault(); 173 | //多点触控时只取第一个点的坐标信息; 174 | var touch = e.touches[0]; 175 | beginStroke(e.target, touch.pageX, touch.pageY); 176 | }); 177 | canvas.addEventListener('touchmove', function (e) { 178 | e.preventDefault(); 179 | if (isMouseDown) { 180 | var touch = e.touches[0]; 181 | moveStroke(e.target, touch.pageX, touch.pageY); 182 | } 183 | }); 184 | canvas.addEventListener('touchend', function (e) { 185 | e.preventDefault(); 186 | endStroke(); 187 | }); 188 | 189 | drawGrid(context, this.canvasWidth, this.canvasHeight); 190 | 191 | this.clear = function () { 192 | context.clearRect(0, 0, this.canvasWidth, this.canvasHeight); 193 | drawGrid(context, this.canvasWidth, this.canvasHeight); 194 | }; 195 | 196 | }; 197 | 198 | if (typeof exports !== 'undefined') { 199 | if (typeof module !== 'undefined' && module.exports) { 200 | exports = module.exports = handWritting; 201 | } else { 202 | exports.handWritting = handWritting; 203 | } 204 | } else { 205 | this.handWritting = handWritting; 206 | } 207 | --------------------------------------------------------------------------------