首頁 >web前端 >html教學 >html5自己做一個類似windows的畫圖軟體的方法

html5自己做一個類似windows的畫圖軟體的方法

一个新手
一个新手原創
2017-10-19 09:56:212136瀏覽

這個繪圖工具,我還沒做完,不過已經實現了總架構,以及常見的簡易圖形繪製功能:

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( &#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>

關於流程設計,後期要做的功能,思路基本上已經有了,好了,圓規正傳,想要完成這個終極目標,完成一個畫圖工具應該就能接近目標了。先體驗下目前的簡易功能,下面是可以正常畫圖的,【需要你的瀏覽器支援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 = &#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: 就是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的應用程式

以上是html5自己做一個類似windows的畫圖軟體的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn