├── 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 |
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 |
11 |
12 |
102 |
103 |
--------------------------------------------------------------------------------
/ball-animation/ball2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
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 |
--------------------------------------------------------------------------------