├── screenshot └── movie.gif ├── src ├── index.js ├── component │ ├── Canvas.css │ ├── App.css │ ├── App.js │ └── Canvas.js ├── index.css └── services │ └── draw.js ├── .gitignore ├── README.md ├── public ├── manifest.json └── index.html ├── package.json └── LICENSE /screenshot/movie.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-canvas-ui/canvas2dDraw/HEAD/screenshot/movie.gif -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import App from "./component/App"; 4 | 5 | ReactDOM.render(, document.getElementById("root")); -------------------------------------------------------------------------------- /src/component/Canvas.css: -------------------------------------------------------------------------------- 1 | .canvas-wrap { 2 | height: 150px; 3 | } 4 | 5 | .button-wrap span { 6 | font-size: 14px; 7 | margin-right: 15px; 8 | line-height: 45px; 9 | } 10 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 10px; 3 | } 4 | 5 | body { 6 | background-color: black; 7 | margin: 0; 8 | padding: 0; 9 | font-family: sans-serif; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | 6 | # testing 7 | coverage 8 | 9 | # production 10 | build 11 | 12 | # misc 13 | .DS_Store 14 | npm-debug.log 15 | -------------------------------------------------------------------------------- /src/component/App.css: -------------------------------------------------------------------------------- 1 | .component-app { 2 | display: flex; 3 | flex-direction: column; 4 | flex-wrap: wrap; 5 | height: 100%; 6 | } 7 | 8 | .component-app h3 { 9 | line-height: 40px; 10 | text-align: center; 11 | color: #666; 12 | font-size: 16px; 13 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | canvas2dDraw 2 | --- 3 | 4 |
5 | 6 |
7 |
8 | Design Sketch 9 |
10 | 11 | Install 12 | --- 13 | 14 | `npm install` 15 | 16 | Usage 17 | --- 18 | 19 | `npm start` 20 | 21 | License 22 | --- 23 | 24 | MIT -------------------------------------------------------------------------------- /src/component/App.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Canvas from './Canvas'; 3 | import "./App.css"; 4 | 5 | export default class App extends React.PureComponent { 6 | 7 | render() { 8 | return ( 9 |
10 |

draw below

11 | 12 |
13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Calculator", 3 | "name": "React Calculator Example App", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "canvas2dDraw", 3 | "version": "0.1.0", 4 | "license": "MIT", 5 | "homepage": "https://github.com/open-canvas-ui/canvas2dDraw", 6 | "devDependencies": { 7 | "react-scripts": "^1.1.4" 8 | }, 9 | "dependencies": { 10 | "react": "^16.4.0", 11 | "react-dom": "^16.4.0" 12 | }, 13 | "scripts": { 14 | "start": "react-scripts start", 15 | "build": "react-scripts build", 16 | "test": "react-scripts test --env=jsdom", 17 | "eject": "react-scripts eject", 18 | "deploy": "gh-pages -d build" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | canvas2dDraw 9 | 10 | 11 | 14 |
15 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/component/Canvas.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Draw from "../services/draw"; 3 | import "./Canvas.css"; 4 | 5 | export default class App extends React.PureComponent { 6 | /* 重置功能 */ 7 | reset() { 8 | Draw.clear(); 9 | } 10 | 11 | /* 导出 */ 12 | exp() { 13 | let exportImg = Draw.exportImg(); 14 | console.log('exportImg: ', exportImg); 15 | if(exportImg === -1) { 16 | return console.log('please draw!'); 17 | } 18 | this.refs['imgC'].src = exportImg; 19 | } 20 | 21 | render() { 22 | return ( 23 |
24 |
25 |
26 | reset 27 | export 28 |
29 | 30 |
31 | ); 32 | } 33 | 34 | componentDidMount() { 35 | Draw.init(this.refs['canvas-wrap']); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Andrew H Farmer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/services/draw.js: -------------------------------------------------------------------------------- 1 | /* 此模块用于实现签名绘图功能 */ 2 | 3 | // 需要用到的变量定义 4 | let clickX = new Array(); 5 | let clickY = new Array(); 6 | let clickDrag = new Array(); 7 | let paint; 8 | let point = {notFirst:false}; 9 | 10 | let canvasDiv = null; // 初始化画布父盒子 11 | let canvas = document.createElement('canvas'); // 创建画板 12 | let context = canvas.getContext("2d"); // 创建2d画布 13 | let canvasWidth = 0; // 初始化画布宽度 14 | let canvasHeight = 0; // 初始化画布高度 15 | 16 | // 可导出图片的标识 17 | let _exportable = false; 18 | 19 | /* ------------ 需要用到的一些功能函数 ------------ */ 20 | function addClick(x, y, dragging) { 21 | clickX.push(x); 22 | clickY.push(y); 23 | clickDrag.push(dragging); 24 | } 25 | 26 | function draw(){ 27 | _exportable = true; 28 | while (clickX.length > 0 ) { 29 | point.bx = point.x; 30 | point.by = point.y; 31 | point.x = clickX.pop(); 32 | point.y = clickY.pop(); 33 | point.drag = clickDrag.pop(); 34 | context.beginPath(); 35 | if (point.drag && point.notFirst) { 36 | context.moveTo(point.bx, point.by); 37 | } else { 38 | point.notFirst = true; 39 | context.moveTo(point.x - 1, point.y); 40 | } 41 | context.lineTo(point.x, point.y); 42 | context.closePath(); 43 | context.stroke(); 44 | } 45 | } 46 | 47 | /* 创建画布背景和画笔 */ 48 | function create() { 49 | // 以下是创建画布背景 50 | context.rect(0, 0, canvasWidth, canvasHeight); 51 | context.fillStyle="#f2f2f2"; // 图片北京色是灰色,此处去除会变黑色 52 | context.fill(); 53 | // 设置画笔属性 54 | context.strokeStyle = "#666"; 55 | context.lineJoin = "round"; 56 | context.lineWidth = 2; 57 | // 默认值清理 58 | clickX = new Array(); 59 | clickY = new Array(); 60 | clickDrag = new Array(); 61 | _exportable = false; 62 | } 63 | 64 | export default { 65 | /* 初始化 */ 66 | init(canvasDivDom, classname) { 67 | canvasDiv = canvasDivDom; // 传入画布父盒子 68 | canvasWidth = canvasDiv.clientWidth; // 获取父盒子宽度 69 | canvasHeight = canvasDiv.clientHeight; // 获取父盒子高度 70 | // 设置属性并追加元素 71 | canvas.setAttribute('width', canvasWidth); 72 | canvas.setAttribute('height', canvasHeight); 73 | canvasDiv.appendChild(canvas); 74 | // 创建画布背景和画笔 75 | create(); 76 | // 开始监控画图 77 | this.listen(classname); 78 | }, 79 | 80 | /* 画图时的监控 */ 81 | listen(classname) { 82 | // 获取盒子需要的参数 83 | let left = canvas.getBoundingClientRect().left; 84 | let top = canvas.getBoundingClientRect().top; 85 | // 支持 移动端 86 | canvasDiv.addEventListener("touchstart", function(e){ 87 | paint = true; 88 | classname && (this.className = classname); 89 | (e.touches) && (e = e.touches[0]); 90 | addClick(e.pageX - left, e.pageY - top); 91 | draw(); 92 | }); 93 | 94 | canvasDiv.addEventListener("touchmove", function(e){ 95 | if(!paint) { 96 | return; 97 | } 98 | (e.touches) && (e = e.touches[0]); 99 | addClick(e.pageX - left, e.pageY - top, true); 100 | draw(); 101 | }); 102 | 103 | canvasDiv.addEventListener("touchend", function(e){ 104 | paint = false; 105 | }); 106 | 107 | // 支持 PC 端 108 | canvasDiv.addEventListener("mousedown", function(e){ 109 | paint = true; 110 | classname && (this.className = classname); 111 | addClick(e.pageX - left, e.pageY - top); 112 | draw(); 113 | }); 114 | 115 | canvasDiv.addEventListener("mousemove", function(e){ 116 | if(!paint) { 117 | return; 118 | } 119 | addClick(e.pageX - left, e.pageY - top, true); 120 | draw(); 121 | }); 122 | 123 | canvasDiv.addEventListener("mouseup", function(e){ 124 | paint = false; 125 | }); 126 | 127 | canvasDiv.addEventListener("mouseleave", function(e){ 128 | paint = false; 129 | }); 130 | }, 131 | 132 | /* 清理 */ 133 | clear() { 134 | // 使用此方式来清理画布 135 | canvas.width = canvas.width; 136 | canvas.height = canvas.height; 137 | create(); // 重新创建画布背景和画笔 138 | _exportable = false; // 清理之后无法导出 139 | }, 140 | 141 | /* 导出图片 */ 142 | exportImg() { 143 | if(!_exportable) { 144 | return -1; // 说明此处无法导出图片 145 | } 146 | return canvas.toDataURL("image/png"); 147 | } 148 | } --------------------------------------------------------------------------------