Home  >  Article  >  Web Front-end  >  How to make a drawing software similar to windows using html5

How to make a drawing software similar to windows using html5

一个新手
一个新手Original
2017-10-19 09:56:212088browse

I haven’t finished this drawing tool yet, but it has implemented the general structure and common simple graphics drawing functions:

1. It can draw straight lines, circles, rectangles, and regular polygons [Completed]

2. Selection of fill color and stroke color [Completed]

3. Selection of stroke and fill functions [Completed]

Subsequent version:

Eraser, coordinate system, line settings, arrows, other process graphics, cropping and adjustment graphics. . . . .

Ultimate goal:

Process drawing software

I saw a friend leave a message on my blog before and said:

Thank you very much for this friend. Today I finally took the time to complete a very, very small prototype!

Please open the complete prototype code yourself and copy it to local testing.


<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( &#39;.paint-body&#39; );
        var oC = document.createElement( &#39;canvas&#39; );
        oC.setAttribute( &#39;width&#39;, &#39;830&#39; );
        oC.setAttribute( &#39;height&#39;, &#39;500&#39; );
        oPaintBody.appendChild( oC );
        var aHeaderLi = document.querySelectorAll(&#39;.paint-header li&#39;),
            aItem = document.querySelectorAll(&#39;.paint-body .item&#39;),
            oCanvas = document.querySelector(&#39;.paint canvas&#39;),
            oGc = oCanvas.getContext(&#39;2d&#39;),
            cWidth = oCanvas.width, cHeight = oCanvas.height,
            curItem = aItem[0],
            aItemLi = curItem.querySelectorAll(&#39;li&#39;);

        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(&#39;active&#39;);
                    aItem[j].style.display = &#39;none&#39;;
                }
                aItem[i].style.display = "block";
                this.classList.add(&#39;active&#39;);
                curItem = aItem[i];
                aItemLi = curItem.querySelectorAll(&#39;li&#39;);
                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(&#39;active&#39;);
                    }
                    this.classList.add(&#39;active&#39;);
                }
            }
        }

        function Shape(canvasObj, cxtObj, w, h) {
            this.oCanvas = canvasObj;
            this.oGc = cxtObj;
            this.oCanvas.width = w;
            this.oCanvas.height = h;
            this.fillStyle = &#39;#000&#39;;
            this.storkeStyle = &#39;#000&#39;;
            this.lineWidth = 1;
            this.drawType = &#39;line&#39;;
            this.paintType = &#39;stroke&#39;;
            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 &#39;paint-shape&#39;: //形状
                    oShape.drawType = curType;
                    if (curType == &#39;polygon&#39;) {
                        oShape.nums = prompt("请输入边数", 6);
                    }
                    oShape.draw();
                    break;
                case &#39;paint-color&#39;: //绘制颜色
                    liType.children[0].onchange = function () {
                        oShape[this.dataset.role] = this.value;
                    }
                    oShape.draw();
                    break;
                case &#39;paint-type&#39;: //绘制类型
                    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>

Regarding process design, the functions to be done in the later stage and the ideas are basically there. Well, Compass is telling the story. If you want to achieve this ultimate goal, complete it. A drawing tool should get you close. Let’s experience the current simple functions first. You can draw pictures normally below. [You need your browser to support canvas.]
Mainly talk about the prototype structure of the target:

1, for the graphics drawing part, I encapsulated a class Shape

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

canvasObj: It is the canvas object

cxtObj: It is the context drawing environment

w: width of canvas

h: height of canvas

fillStyle: fill color

strokeStyle: stroke color

lineWidth: line width

drawType: The default is to draw a straight line

paintType: two options of stroke/fill (stroke/fill)

2, extend a public method draw on the prototype object To draw graphics

draw method mainly obtains the starting point coordinates (startX, startY) and end point coordinates (endX, endY);

Then call the init method to obtain the drawing status, Drawing specific graphics relies on the following key method:

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

The drawType of this method will change according to the real-time selection of the interface. The drawing type, such as:

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

The line in the oShape object is called, the method of drawing a straight 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, the interface operation is very simple, basically the operation of tab + the custom attribute of html5 + the application of classList

The above is the detailed content of How to make a drawing software similar to windows using html5. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn