视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
html5自己做一个类似windows的画图软件的方法
2020-11-27 15:28:22 责编:小采
文档
 这个绘图工具,我还没有做完,不过已经实现了总架构,以及常见的简易图形绘制功能:

1,可以绘制直线,圆,矩形,正多边形【已完成】

2,填充颜色和描边颜色的选择【已完成】

3,描边和填充功能的选择【已完成】

后续版本:

橡皮擦,坐标系,线形设置,箭头,其他流程图形,裁剪与调整图形。。。

终极目标:

流程绘制软件

我是之前看见一位朋友在我的博客中留言说:

非常感谢这个朋友,今天终于抽出时间完成非常非常小的雏形!

完整的雏形代码,请自行打开,复制到本地测试.

<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <meta http-equiv="X-UA-Compatible" content="ie=edge">
 <title>windows简易画图工具 - by ghostwu</title>
</head>

<body>
 <div class="paint">
 <div class="paint-header">
 <ul>
 <li class="active">形状</li>
 <li>颜色</li>
 <li>绘制类型</li>
 <li>线条宽度</li>
 <li>橡皮擦</li>
 </ul>
 </div>
 <div class="paint-body">
 <div class="siderbar">
 <div class="item active" data-type="paint-shape">
 <ul>
 <li class="active" data-role="line">线条</li>
 <li data-role="circle">圆形</li>
 <li data-role="rect">矩形</li>
 <li data-role="polygon">正多边形</li>
 <li data-role="arrow">箭头</li>
 </ul>
 </div>
 <div class="item" data-type="paint-color">
 <ul>
 <li data-role="strokeStyle">
 <input type="color" data-role="strokeStyle">
 </li>
 <li data-role="fillStyle">
 <input type="color" data-role="fillStyle">
 </li>
 </ul>
 </div>
 <div class="item" data-type="paint-type">
 <ul>
 <li data-role="stroke">描边</li>
 <li data-role="fill">填充</li>
 </ul>
 </div>
 <div class="item" data-type="paint-line">
 <ul>
 <li data-role="1">小号</li>
 <li data-role="4">中号</li>
 <li data-role="7">大号</li>
 <li>
 <input type="number" data-role="line-size" placeholder="请输入数字">
 </li>
 </ul>
 </div>
 <div class="item" data-type="paint-erase">
 <ul>
 <li>
 <input type="number" data-role="erase-size" placeholder="请输入数字">
 </li>
 </ul>
 </div>
 </div>
 </div>
 </div>
 <script>// <![CDATA[
 var oPaintBody = document.querySelector( '.paint-body' );
 var oC = document.createElement( 'canvas' );
 oC.setAttribute( 'width', '830' );
 oC.setAttribute( 'height', '500' );
 oPaintBody.appendChild( oC );
 var aHeaderLi = document.querySelectorAll('.paint-header li'),
 aItem = document.querySelectorAll('.paint-body .item'),
 oCanvas = document.querySelector('.paint canvas'),
 oGc = oCanvas.getContext('2d'),
 cWidth = oCanvas.width, cHeight = oCanvas.height,
 curItem = aItem[0],
 aItemLi = curItem.querySelectorAll('li');

 for (let i = 0, len = aHeaderLi.length; i < len; i++) { //头部选项卡切换功能
 aHeaderLi[i].onclick = function () {
 for (let j = 0; j < len; j++) {
 aHeaderLi[j].classList.remove('active');
 aItem[j].style.display = 'none';
 }
 aItem[i].style.display = "block";
 this.classList.add('active');
 curItem = aItem[i];
 aItemLi = curItem.querySelectorAll('li');
 activeItem(aItemLi);
 }
 }
 activeItem(aItemLi);
 var role = null;
 function activeItem(aItemLi) { //canvas左侧选项卡切换功能
 for (let i = 0, len = aItemLi.length; i < len; i++) {
 aItemLi[i].onclick = function () {
 checkPaintType(this); //绘制类型
 for (let j = 0; j < len; j++) {
 aItemLi[j].classList.remove('active');
 }
 this.classList.add('active');
 }
 }
 }

 function Shape(canvasObj, cxtObj, w, h) {
 this.oCanvas = canvasObj;
 this.oGc = cxtObj;
 this.oCanvas.width = w;
 this.oCanvas.height = h;
 this.fillStyle = '#000';
 this.storkeStyle = '#000';
 this.lineWidth = 1;
 this.drawType = 'line';
 this.paintType = 'stroke';
 this.nums = 6; //正多边形的边数
 }

 Shape.prototype = {
 init: function () {
 this.oGc.fillStyle = this.fillStyle;
 this.oGc.strokeStyle = this.strokeStyle;
 this.oGc.lineWidth = this.lineWidth;
 },
 draw: function () {
 var _this = this;
 this.oCanvas.onmousedown = function (ev) {
 _this.init();
 var oEvent = ev || event,
 startX = oEvent.clientX - _this.oCanvas.offsetLeft,
 startY = oEvent.clientY - _this.oCanvas.offsetTop;
 _this.oCanvas.onmousemove = function (ev) {
 _this.oGc.clearRect(0, 0, _this.oCanvas.width, _this.oCanvas.height);
 var oEvent = ev || event,
 endX = oEvent.clientX - _this.oCanvas.offsetLeft,
 endY = oEvent.clientY - _this.oCanvas.offsetTop;
 _this[_this.drawType](startX, startY, endX, endY);
 };
 _this.oCanvas.onmouseup = function () {
 _this.oCanvas.onmousemove = null;
 _this.oCanvas.onmouseup = null;
 }
 }
 },
 line: function (x1, y1, x2, y2) {
 this.oGc.beginPath();
 this.oGc.moveTo(x1, y1);
 this.oGc.lineTo(x2, y2);
 this.oGc.closePath();
 this.oGc.stroke();
 },
 circle: function (x1, y1, x2, y2) {
 this.oGc.beginPath();
 var r = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
 this.oGc.arc(x1, y1, r, 0, 2 * Math.PI, false);
 this.oGc.closePath();
 this.oGc[this.paintType]();
 },
 rect: function (x1, y1, x2, y2) {
 this.oGc.beginPath();
 this.oGc.rect(x1, y1, x2 - x1, y2 - y1);
 this.oGc[this.paintType]();
 },
 polygon: function (x1, y1, x2, y2) {
 var angle = 360 / this.nums * Math.PI / 180;//边对应的角的弧度
 var r = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
 this.oGc.beginPath();
 for (var i = 0; i < this.nums; i++) {
 this.oGc.lineTo(x1 + r * Math.cos(angle * i), y1 + r * Math.sin(angle * i));
 }
 this.oGc.closePath();
 this.oGc[this.paintType]();
 }
 }

 var oShape = new Shape(oCanvas, oGc, cWidth, cHeight);
 function checkPaintType(liType) {
 var dataType = liType.parentNode.parentNode.dataset.type;
 var curType = liType.dataset.role;
 switch (dataType) {
 case 'paint-shape': //形状
 oShape.drawType = curType;
 if (curType == 'polygon') {
 oShape.nums = prompt("请输入边数", 6);
 }
 oShape.draw();
 break;
 case 'paint-color': //绘制颜色
 liType.children[0].onchange = function () {
 oShape[this.dataset.role] = this.value;
 }
 oShape.draw();
 break;
 case 'paint-type': //绘制类型
 oShape.paintType = curType;
 oShape.draw();
 break;
 }
 }
// ]]></script>
 <style>
 .paint * {
 margin: 0;
 padding: 0;
 }

 .paint ul,
 .paint li {
 list-style: none;
 }

 .paint li:hover {
 cursor: pointer;
 }

 .paint {
 width: 980px;
 margin: 20px auto;
 border: 1px solid #ccc;
 overflow: hidden;
 }

 .paint .paint-header ul {
 width: 980px;
 height: 40px;
 line-height: 40px;
 border-bottom: 1px solid #ccc;
 }

 .paint .paint-header li {
 float: left;
 width: 120px;
 height: 40px;
 line-height: 40px;
 text-align: center;
 }

 .paint li.active {
 box-shadow: #666 0px 1px 8px inset;
 }

 .paint .paint-body .siderbar {
 float: left;
 width: 150px;
 height: 500px;
 }

 .paint .paint-body .item {
 width: 150px;
 overflow: hidden;
 display: none;
 height: 500px;
 border-right: 1px solid #ccc;
 }

 .paint .paint-body canvas {
 float: right;
 }

 .paint .paint-body .item li {
 height: 40px;
 text-align: center;
 border-bottom: 1px solid #ccc;
 line-height: 40px;
 }

 .paint .paint-body .active {
 display: block;
 }
 </style>
</body>

关于流程设计,后期要做的功能,思路基本上已经有了,好了,圆规正传,想要完成这个终极目标,完成一个画图工具应该就能接近目标了。先体验下目前的简易功能,下面是可以正常画图的,【需要你的浏览器支持canvas才可以额】
主要来讲下目标的雏形架构:

1,图形绘制部分,我封装了一个类Shape

function Shape(canvasObj, cxtObj, w, h) {
 this.oCanvas = canvasObj;
 this.oGc = cxtObj;
 this.oCanvas.width = w;
 this.oCanvas.height = h;
 this.fillStyle = '#000';
 this.storkeStyle = '#000';
 this.lineWidth = 1;
 this.drawType = 'line';
 this.paintType = 'stroke';
 this.nums = 6; //正多边形的边数
 }

canvasObj: 就是canvas画布对象

cxtObj: 就是上下文绘图环境

w: canvas的宽度

h: canvas的高度

fillStyle: 填充颜色

strokeStyle: 描边颜色

lineWidth: 线宽

drawType: 默认为画直线

paintType: stroke/fill 两种选择( 描边/填充)

2,在原型对象上扩展一个公共方法draw用来绘制图形

draw方法,主要获取起始点坐标(startX, startY),以及终点坐标( endX, endY );

然后调用init方法来获取绘制状态,绘制具体的图形靠下面这个关键方法:

_this[_this.drawType](startX, startY, endX, endY)

这个方法的drawType会根据界面的实时选择,变换对应的绘制类型,如:

_this['line']( startX, startY, endX, endY )

调用的就是oShape对象中的line,画直线的方法

Shape.prototype = {
 init: function () {
 this.oGc.fillStyle = this.fillStyle;
 this.oGc.strokeStyle = this.strokeStyle;
 this.oGc.lineWidth = this.lineWidth;
 },
 draw: function () {
 var _this = this;
 this.oCanvas.onmousedown = function ( ev ) {
 _this.init();
 var oEvent = ev || event,
 startX = oEvent.clientX - _this.oCanvas.offsetLeft,
 startY = oEvent.clientY - _this.oCanvas.offsetTop;
 _this.oCanvas.onmousemove = function ( ev ) {
 _this.oGc.clearRect( 0, 0, _this.oCanvas.width, _this.oCanvas.height );
 var oEvent = ev || event,
 endX = oEvent.clientX - _this.oCanvas.offsetLeft,
 endY = oEvent.clientY - _this.oCanvas.offsetTop;
 _this[_this.drawType](startX, startY, endX, endY);
 };
 _this.oCanvas.onmouseup = function(){
 _this.oCanvas.onmousemove = null;
 _this.oCanvas.onmouseup = null;
 }
 }
 },
 line: function ( x1, y1, x2, y2 ) {
 this.oGc.beginPath();
 this.oGc.moveTo( x1, y1 );
 this.oGc.lineTo( x2, y2 );
 this.oGc.closePath();
 this.oGc.stroke();
 },
 circle : function( x1, y1, x2, y2 ){
 this.oGc.beginPath();
 var r = Math.sqrt( Math.pow( x2 - x1, 2 ) + Math.pow( y2 - y1, 2 ) );
 this.oGc.arc( x1, y1, r, 0, 2 * Math.PI, false );
 this.oGc.closePath();
 this.oGc[this.paintType]();
 },
 rect : function( x1, y1, x2, y2 ){
 this.oGc.beginPath();
 this.oGc.rect( x1, y1, x2 - x1, y2 - y1 );
 this.oGc[this.paintType]();
 },
 polygon : function( x1, y1, x2, y2 ){
 var angle = 360 / this.nums * Math.PI / 180;//边对应的角的弧度
 var r = Math.sqrt( Math.pow( x2 - x1, 2 ) + Math.pow( y2 - y1, 2 ) );
 this.oGc.beginPath();
 for( var i = 0; i < this.nums; i ++ ){
 this.oGc.lineTo( x1 + r * Math.cos( angle * i ), y1 + r * Math.sin( angle * i ) );
 }
 this.oGc.closePath();
 this.oGc[this.paintType]();
 }
 }

3,界面操作很简单,基本是选项卡的操作+html5的自定义属性+classList的应用

下载本文
显示全文
专题