<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>etwas</title>
    <script src="https://code.jquery.com/jquery-3.4.1.js"></script>
    <style>
        canvas {
            border: 1px solid black;
        }

        .colors {
            height: 20px;
            width: 40px;
        }

        hor {
            width: 1px;
            height: 100%;
            border: 1px solid black;
            margin-right: 5px;
            margin-left: 5px;
        }

        td {
            -ms-user-select: none;
            -moz-user-select: none;
            -khtml-user-select: none;
            -webkit-user-select: none;
            text-align: center;
        }

        #white {
            border: 1px solid black;
        }

        .ico {
            width: 25px;
        }

        #rgbColor {
            background-image: url('https://habrastorage.org/webt/-s/kq/ph/-skqphg-vs0139j4g8rylvgc0ja.png');
        }
    </style>
</head>

<body>
    <table>
        <tr>
            <td onclick='changeMode("draw"); buttsCss("drawButt")' id='drawButt'><img src="https://i.ibb.co/k4k5GmL/88a2f7af241898f681e799b501d1e881.png" class='ico'></td>
            <td onclick="changeMode('quadrat'); buttsCss('squareButt')" id='squareButt'><img src='https://upload.wikimedia.org/wikipedia/commons/thumb/a/a5/ГОСТ_2.410-68._Квадрат%2C_прямоугольник.svg/1200px-ГОСТ_2.410-68._Квадрат%2C_прямоугольник.svg.png' class='ico'></td>
            <td>
                <hor></hor>
            </td>
            <td onclick='changeColor("black")' class='colors' title='alt+b'></td>
            <td onclick='changeColor("red")' class='colors' title='alt+r'></td>
            <td>
                <hor></hor>
            </td>
            <td>Line width:</td>
            <td>
                <hor></hor>
            </td>
            <td onclick='deleteLast()' title="ctrl+z">
                <img src="https://habrastorage.org/webt/cv/g4/cq/cvg4cqypolpqtqpyfznhvcwhhki.png" class='ico'>
            </td>
            <td onclick='returnLast()' title='ctrl+y'>
                <img src="https://i.ibb.co/HzL1pDP/download-428690.png" class='ico'>
            </td>
            <td>
                <hor></hor>
            </td>
            <td id='fillButt' onclick='fillStroke("fill")' class='FS' title='f'>
                fill
            </td>
        </tr>
        <tr>
            <td onclick="changeMode('string'); buttsCss('lineButt')" id='lineButt'><img src="https://free-images.com/or/3d5c/u_1d360_svg.jpg" class='ico'></td>
            <td onclick="changeMode('rund'); buttsCss('circleButt')" id='circleButt'><img src="https://big-stirka.ru/wp-content/uploads/2017/08/pustoj-krug.png" class='ico'></td>
            <td>
                <hor></hor>
            </td>
            <td onclick='changeColor("blue")' class='colors' title='alt+n'></td>
            <td onclick='changeColor("green")' class='colors' title='alt+g'></td>
            <td>
                <hor></hor>
            </td>
            <td>
                <form name='selForm'>
                    <select id='selectWidth'>
                        <option value='1'>1</option>
                        <option value='2'>2</option>
                        <option value='5' selected>5</option>
                        <option value='7'>7</option>
                        <option value='10'>10</option>
                        <option value='12'>12</option>
                        <option value='15'>15</option>
                        <option value='20'>20</option>
                        <option value='30'>30</option>
                        <option value='40'>40</option>
                        <option value='60'>60</option>
                    </select>
                </form>
            </td>
            <td>
                <hor></hor>
            </td>
            <td></td>
            <td></td>
            <td>
                <hor></hor>
            </td>
            <td id='strokeButt' onclick='fillStroke("stroke")' class='FS' title='s'>
                stroke
            </td>
        </tr>
        <tr>
            <td onclick='changeMode("fill"); buttsCss("fillButt1")' id='fillButt1'><img src="https://www.pinclipart.com/picdir/big/534-5348253_bucket-icon-png-ms-paint-paint-bucket-tool.png" class='ico'></td>
            <td onclick='changeMode("triangle"); buttsCss("triangleButt")' id='triangleButt'><img src='https://i.ibb.co/vjCxp6J/aa29932f27044fe8b1140d111f525801.png' class='ico'></td>
            <td>
                <hor></hor>
            </td>
            <td onclick='changeColor("rgb(253, 254, 254)")' class='colors' id='white' title='alt+w'></td>
            <td onclick="changeColor('yellow')" class='colors' title='alt+y'></td>
            <td>
                <hor></hor>
            </td>
            <td></td>
            <td>
                <hor></hor>
            </td>
            <td></td>
            <td></td>
            <td>
                <hor></hor>
            </td>
            <td id='fill-strokeButt' onclick='fillStroke("fill-stroke")' class='FS' title='s'>
                fill+stroke (console version)
            </td>
        </tr>
        <tr>
            <td id='eraserButt' onclick='changeMode("eraser"); buttsCss("eraserButt")'><img src="https://habrastorage.org/webt/xt/nb/s1/xtnbs1cdcdf30vmf30eqhlueooo.png" class="ico" /></td>
            <td></td>
            <td>
                <hor></hor>
            </td>
            <td class='colors' id='rgbColor' onclick='rgbColor()'></td>
        </tr>
    </table>
    <canvas id='canvas'></canvas>
    <script>
class Line {
    constructor(color) {
        this.type = 'line';
        this.pointsX = [];
        this.pointsY = [];
        this.color = color;
        this.weight = weight;
        this.isDraw = true;
        this.i = 1;
    }
    draw() {
        if (this.isDraw) {
            ctx.lineWidth = this.weight;
            ctx.strokeStyle = this.color;
            ctx.beginPath();
            ctx.moveTo(this.pointsX[this.i - 1], this.pointsY[this.i - 1]);
            if (this.pointsX.length == this.pointsY.length) {
                while (this.pointsX.length > this.i) {
                    ctx.lineTo(this.pointsX[this.i], this.pointsY[this.i]);

                    this.i++;
                }
                ctx.stroke();
            }
        }
    }
}

class Eraser {
    constructor() {
        this.color = fillColor;
        this.weight = weight;
        this.pointsX = [];
        this.pointsY = [];
        this.type = 'eraser';
        this.isDraw = true;
        this.i = 1;
    }
    draw() {
        if (this.isDraw) {
            ctx.lineWidth = this.weight;
            ctx.strokeStyle = this.color;
            ctx.beginPath();
            ctx.moveTo(this.pointsX[this.i - 1], this.pointsY[this.i - 1]);
            if (this.pointsX.length == this.pointsY.length) {
                while (this.pointsX.length > this.i) {
                    ctx.lineTo(this.pointsX[this.i], this.pointsY[this.i]);

                    this.i++;
                }
                ctx.stroke();
            }
        }
    }
}

class String {
    constructor(color) {
        this.type = 'string';
        this.color = color;
        this.weight = weight;
        this.startX = 0;
        this.startY = 0;
        this.endX = 0;
        this.endY = 0;
        this.isDraw = true;
    }
    makingEnd(posX, posY, isShift) {
        if (!isShift) {
            this.endX = posX;
            this.endY = posY;
        } else {
            if (posX - this.startX > 0 && posY - this.startY > 0) { //правый низ
                if (posX > posY) {
                    this.endX = posX;
                    this.endY = this.startY;
                } else {
                    this.endX = this.startX;
                    this.endY = posY;
                }
            } else if (posX - this.startX < 0 && posY - this.startY > 0) { //левый низ
                if (-(this.startX - posX) < this.startY - posY) {
                    this.endX = posX;
                    this.endY = this.startY;
                } else {
                    this.endX = this.startX;
                    this.endY = posY;
                }
            } else if (posX - this.startX < 0 && posY - this.startY < 0) { //левый верх
                if (-(this.startX - posX) < -(this.startY - posY)) {
                    this.endX = posX;
                    this.endY = this.startY;
                } else {
                    this.endX = this.startX;
                    this.endY = posY;
                }
            } else if (posX - this.startX > 0 && posY - this.startY < 0) { //правый верх
                if (this.startX - posX < -(this.startY - posY)) {
                    this.endX = posX;
                    this.endY = this.startY;
                } else {
                    this.endX = this.startX;
                    this.endY = posY;
                }
            }
        }
    }
    draw() {
        if (this.isDraw) {
            ctx.strokeStyle = this.color;
            ctx.lineWidth = this.weight;
            ctx.beginPath();
            ctx.moveTo(this.startX, this.startY);
            ctx.lineTo(this.endX, this.endY);
            ctx.stroke();
        }
    }
}

class Quadrat {
    constructor(color) {
        this.type = 'quadrat';
        this.colorFill = color;
        this.colorStroke = color;
        this.FS = fillOrStroke;
        this.weight = weight;

        this.startX = 0;
        this.startY = 0;
        this.endX = 0;
        this.endY = 0;

        this.isDraw = true;
    }
    makingEnd(posX, posY, isShift = false) {
        if (!isShift) {
            this.endX = -(this.startX - posX);
            this.endY = -(this.startY - posY);
        } else {
            this.endX = -(this.startX - posX);
            if (posY > this.startY) {
                this.endY = this.endX;
            } else {
                this.endY = -this.endX;
            }
        }
    }
    draw() {
        if (this.isDraw) {
            ctx.strokeStyle = this.color;
            ctx.lineWidth = this.weight;
            if (this.FS == 'fill') {
                ctx.fillStyle = this.colorFill;
                ctx.fillRect(this.startX, this.startY, this.endX, this.endY);
            } else if (this.FS == 'stroke') {
                ctx.lineWidth = this.weight;
                ctx.strokeStyle = this.colorStroke;
                ctx.strokeRect(this.startX, this.startY, this.endX, this.endY);
            } else {
                ctx.lineWidth = this.weight;
                ctx.strokeStyle = this.colorStroke;
                ctx.strokeRect(this.startX, this.startY, this.endX, this.endY);
                ctx.fillStyle = this.colorFill;
                ctx.fillRect(this.startX, this.startY, this.endX, this.endY);
            }
        }
    }
}

class Rund {
    constructor(color) {
        this.type = 'rund';
        this.colorFill = color;
        this.colorStroke = color;
        this.FS = fillOrStroke;
        this.weight = weight;

        this.isDraw = true;
        this.isArc = false;

        this.startX = 0;
        this.startY = 0;
        this.radiusX = 0;
        this.radiusY = 0;
        this.rotation = 0;
    }
    makingEnd(radiusX, radiusY, isShift = false) {
        if (isShift) {
            this.radiusX = -(this.startX - radiusX);
            if (this.radiusX < 0) {
                this.radiusX = -this.radiusX;
            }
            this.isArc = true;
        } else {
            this.radiusX = -(this.startX - radiusX);
            if (this.radiusX < 0) {
                this.radiusX = -this.radiusX;
            }
            this.radiusY = -(this.startY - radiusY);
            if (this.radiusY < 0) {
                this.radiusY = -this.radiusY;
            }
            this.isArc = false;
        }
    }
    draw() {
        if (this.isDraw) {
            ctx.strokeStyle = this.color;
            ctx.lineWidth = this.weight;
            ctx.beginPath();
            if (this.isArc) {
                ctx.arc(this.startX, this.startY, this.radiusX, 0, Math.PI * 2);
            } else {
                ctx.ellipse(this.startX, this.startY, this.radiusX, this.radiusY, this.rotation, 0, Math.PI * 2);
            }
            if (this.FS == 'fill') {
                ctx.fillStyle = this.colorFill;
                ctx.fill();
            } else if (this.FS == 'stroke') {
                ctx.lineWidth = this.weight;
                ctx.strokeStyle = this.colorStroke;
                ctx.stroke();
            } else {
                ctx.lineWidth = this.weight;
                ctx.strokeStyle = this.colorStroke;
                ctx.stroke();
                ctx.fillStyle = this.colorFill;
                ctx.fill();
            }
        }
    }
}

class Fill {
    constructor(color) {
        this.color = color;
        this.isDraw = true;
    }
    draw() {
        this.isDraw = true;
        ctx.fillStyle = this.color;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        fillColor = this.color;
    }
}

class Triangle {
    constructor(color) {
        this.colorFill = color;
        this.colorStroke = color;
        this.weight = weight;
        this.FS = fillOrStroke;
        this.isDraw = true;

        this.startX = 0;
        this.startY = 0;
        this.endX = 0;
        this.endY = 0;
        this.posX = 0;
        this.posY = 0;
        
        this.type = 'triangle';
    }
    makingEnd(posX, posY, isShift = false) {
        if (!isShift) {
            this.endX = -(this.startX - posX);
            this.endY = -(this.startY - posY);
            this.posX = posX;
            this.posY = posY;
        } else {
            this.endX = -(this.startX - posX);
            this.posX = posX;
            if (posY > this.startY) {
                this.endY = this.endX;
                this.posY = this.startY + this.endY;
            } else {
                this.endY = -this.endX;
                this.posY = -(this.startY + this.endY);
            }
        }
    }
    draw() {
        if (this.isDraw) {
            ctx.beginPath();
            ctx.moveTo(this.startX, this.posY);
            ctx.lineTo(this.posX, this.posY);
            ctx.lineTo((this.posX - this.startX) / 2 + this.startX, this.startY);
            ctx.lineTo(this.startX, this.posY);
            if (this.FS == 'fill') {
                ctx.fillStyle = this.colorFill;
                ctx.fill();
            } else if (this.FS == 'stroke') {
                ctx.lineWidth = this.weight;
                ctx.strokeStyle = this.colorStroke;
                ctx.stroke();
            } else {
                ctx.lineWidth = this.weight;
                ctx.strokeStyle = this.colorStroke;
                ctx.stroke();
                ctx.fillStyle = this.colorFill;
                ctx.fill();
            }
        }
    }
}
function betterDelete(array = [], isMany = false, isPoints = false) {
    if (!isMany && !isPoints) {
        let newArr = [];
        for (let i = 0; i < array.length; i++) {
            if (array[i].isDraw) {
                if (array[i].type == 'line') {
                    if (array[i].pointsX.length > 0) {
                        newArr[newArr.length] = array[i];
                    }
                } else if (array[i].type == 'rund') {
                    if (array[i].endX != 0) {
                        newArr[newArr.length] = array[i];
                    }
                } else if (array[i].type == 'triangle') {
                    if (array[i].posX != 0 && array[i].posY != 0) {
                        newArr[newArr.length] = array[i];
                    }
                } else if (array[i].type == 'quadrat') {
                    if (array[i].endX != 0 && array[i].endY != 0) {
                        newArr[newArr.length] = array[i];
                    }
                } else {
                    newArr[newArr.length] = array[i];
                }
            }
        }
        return newArr;
    } else if (!isPoints) {
        let newArr = [];
        let count = 0;
        for (let i = array.length - 1; i > 0; i--) {
            if (!array[i].isDraw && count < 5) {
                count++;
            } else {
                newArr[newArr.length] = array[i];
            }
        }
        return newArr;
    } else {
        let newArr = [];
        for (let i = 0; i < array.length; i++) {
            if (array[i].pointsX != undefined) {
                if (array[i].pointsX > 1) {
                    newArr[newArr.length] = array[i];
                }
            }
        }
        return newArr;
    }
}
function deleteLast() {
    for (let i = points.length - 1; i >= 0; i--) {
        if (points[i].isDraw) {
            points[i].isDraw = false;
            i = -1;
        }
    }
    let empties = 0;
    for (let i = 0; i < points.length; i++) {
        if (!points[i].isDraw) {
            empties++;
        }
    }
    if (empties > 5) {
        points = betterDelete(points, true);
    }
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    draw();
}

function returnLast() {
    for (let i = 0; i < points.length; i++) {
        if (!points[i].isDraw) {
            points[i].isDraw = true;
            i = points.length;
        }
    }
    draw();
}

function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    for (let i = 0; i < points.length; i++) {
        points[i].draw();
        if (points[i].i != undefined) {
            points[i].i = 1;
        }
    }
}

function changeColor(nColor = '') {
    color = nColor;
}
function rgbColor(r = 0, g = 0, b = 0) {
    if (r != 0 && g != 0 && b != 0) {
        color = `rgb(${r}, ${g}, ${b})`;
    } else {
        let rgb = prompt('Enter three comma-separated numbers (rgb color)'); //три числа через запятую просто вставить
        if (rgb != null) {
            color = `rgb(${rgb})`;
        }
    }
}

function changeMode(cMode) {
    mode = cMode;
}

function chooseWidth(power) {
    weight = power;
}

function fillStroke(mode) {
    if (mode == 'fill') {
        fillOrStroke = 'fill';
        $('#fillButt').css('background-color', 'antiquewhite');
        $('#strokeButt').css('background-color', '');
        $('#fill-strokeButt').css('background-color', '');
    } else if (mode == 'stroke') {
        fillOrStroke = 'stroke';
        $('#fillButt').css('background-color', '');
        $('#strokeButt').css('background-color', 'antiquewhite');
        $('#fill-strokeButt').css('background-color', '');
    } else {
        fillOrStroke = 'fill-stroke';
        $('#fillButt').css('background-color', '');
        $('#strokeButt').css('background-color', '');
        $('#fill-strokeButt').css('background-color', 'antiquewhite');
    }
}
function buttsCss(clicked) {
    $('#drawButt').css('background-color', '')
    $('#squareButt').css('background-color', '')
    $('#lineButt').css('background-color', '')
    $('#circleButt').css('background-color', '')
    $('#fillButt1').css('background-color', '')
    $('#triangleButt').css('background-color', '')
    $('#eraserButt').css('background-color', '')
    $(`#${clicked}`).css('background-color', 'antiquewhite')
}

function save() {
    $('#canvas').contextmenu(function (e) {
        alert('')
    });
}
var canvas = document.getElementById('canvas');
var body = document.getElementsByTagName('body')[0];

var ctx = canvas.getContext('2d');

if (screen.width > 800 && screen.height > 500) {
    canvas.height = 500;
    canvas.width = 800;
} else {
    canvas.width = screen.width - 20;
    canvas.height = screen.height / 2;
}

var canvasPosX = canvas.getBoundingClientRect().left + pageXOffset + 2;
var canvasPosY = canvas.getBoundingClientRect().top + pageYOffset;

var points = [];

var color = 'black';
var fillColor = '';
var weight = 5;

var drawing = false;

var mode = 'draw';
var fillOrStroke = 'stroke';
fillStroke('stroke');

buttsCss("drawButt")

var colors = ['black', 'red', 'blue', 'green', 'rgb(253, 254, 254)', 'yellow'];
var tdsForColors = document.getElementsByClassName('colors');
for (let i = 0; i < tdsForColors.length - 1; i++) {
    tdsForColors[i].id = `tdForColors${i}`;
    $(`#tdForColors${i}`).css({ 'background-color': colors[i], 'border': '1px solid black' });
}

points[0] = new Fill('rgb(253, 254, 254)');

$('#selectWidth').change(function (e) {
    e.preventDefault();
    for (let i = 0; i < e.currentTarget.length; i++) {
        if (e.currentTarget[i].selected) {
            chooseWidth(e.currentTarget[i].value);
        }
    }
});
//сенсор
canvas.addEventListener('touchstart', function (e) {
    Start(e.touches[0]);
}, false);
body.addEventListener('touchmove', function (e) {
    Move(e.touches[0]);
}, false);
body.addEventListener('touchend', function (e) {
    End(e.touches[0]);
}, false);

//мышь
canvas.addEventListener('mousedown', function (e) {
    Start(e);
}, false)
body.addEventListener('mousemove', function (e) {
    Move(e);
}, false)
body.addEventListener('mouseup', function (e) {
    End(e);
}, false)

//управляшки
function Start(e) {
    if (mode == 'draw') {
        points[points.length] = new Line(color);
    } else if (mode == 'string') {
        points[points.length] = new String(color);
        points[points.length - 1].startX = e.clientX - canvasPosX + document.getElementsByTagName('html')[0].scrollLeft;
        points[points.length - 1].startY = e.clientY - canvasPosY + document.getElementsByTagName('html')[0].scrollTop;
    } else if (mode == 'quadrat') {
        points[points.length] = new Quadrat(color);
        points[points.length - 1].startX = e.clientX - canvasPosX + document.getElementsByTagName('html')[0].scrollLeft;
        points[points.length - 1].startY = e.clientY - canvasPosY + document.getElementsByTagName('html')[0].scrollTop;
    } else if (mode == 'rund') {
        points[points.length] = new Rund(color);
        points[points.length - 1].startX = e.clientX - canvasPosX + document.getElementsByTagName('html')[0].scrollLeft;
        points[points.length - 1].startY = e.clientY - canvasPosY + document.getElementsByTagName('html')[0].scrollTop;
    } else if (mode == 'fill') {
        points[0].color = color;
        for(let i = 1; i < points.length; i++) {
            if(points[i].type == 'eraser') {
                points[i].color = color;
            }
        }
        draw();
    } else if (mode == 'triangle') {
        points[points.length] = new Triangle(color);
        points[points.length - 1].startX = e.clientX - canvasPosX + document.getElementsByTagName('html')[0].scrollLeft;
        points[points.length - 1].startY = e.clientY - canvasPosY + document.getElementsByTagName('html')[0].scrollTop;
    } else if    (mode == 'eraser') {
        points[points.length] = new Eraser(color);
    }
    drawing = true;
}
function Move(e) {
    if (drawing && e.which == 1 || e.which == undefined) {
        if (mode == 'draw' || mode == 'eraser') {
            if (points.length > 0) {
                points[points.length - 1].pointsX[points[points.length - 1].pointsX.length] = e.clientX - canvasPosX + document.getElementsByTagName('html')[0].scrollLeft;
                points[points.length - 1].pointsY[points[points.length - 1].pointsY.length] = e.clientY - canvasPosY + document.getElementsByTagName('html')[0].scrollTop;
                points[points.length - 1].draw();
            }
        } else if (mode == 'string') {
            if (points.length > 0) {
                points[points.length - 1].makingEnd(e.clientX - canvasPosX + document.getElementsByTagName('html')[0].scrollLeft, e.clientY - canvasPosY + document.getElementsByTagName('html')[0].scrollTop, e.shiftKey);
                draw();
            }
        } else if (mode == 'quadrat' || mode == 'triangle') {
            points[points.length - 1].makingEnd(e.clientX - canvasPosX + document.getElementsByTagName('html')[0].scrollLeft, e.clientY - canvasPosY + document.getElementsByTagName('html')[0].scrollTop, e.shiftKey);
            draw();
        } else if (mode == 'rund') {
            points[points.length - 1].makingEnd(e.clientX - canvasPosX + document.getElementsByTagName('html')[0].scrollLeft, e.clientY - canvasPosY + document.getElementsByTagName('html')[0].scrollTop, e.shiftKey);
            draw();
        }
    }
}
function End(e) {
    if (mode == 'draw' || mode == 'eraser') {
        if (points.length > 0) {
            points[points.length - 1].i = 1;
        }
    }
    drawing = false;
    points = betterDelete(points);
    draw();
}

//клава
$('body').keydown(function (e) {
    //console.log(e.keyCode);
    switch (e.keyCode) {
        case 90:
            if (e.ctrlKey) {
                deleteLast();
            }
            break;
        case 89:
            if (e.ctrlKey) {
                returnLast();
            } else if (e.altKey) {
                changeColor('yellow');
            }
            break;
        case 70:
            fillStroke('fill');
            break;
        case 83:
            fillStroke('stroke');
            break;
        case 66:
            if (e.altKey) {
                changeColor('black')
            }
            break;
        case 82:
            if (e.altKey) {
                changeColor('red')
            }
            break;
        case 78:
            if (e.altKey) {
                changeColor('blue')
            }
            break;
        case 71:
            if (e.altKey) {
                changeColor('green')
            }
            break;
        case 87:
            if (e.altKey) {
                changeColor('rgb(253, 254, 254)')
            }
            break;

        default:
            break;
    }
});
    </script>
</body>

</html>

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.