#javascript #html #css
#javascript #HTML #css — код
Вопрос:
Я пытаюсь создать приложение, подобное paint, в котором вы можете рисовать базовые фигуры с предварительным просмотром. Я реализовал функцию рисования для эллипса, а затем хочу реализовать ее для линии и прямоугольника. Но я не знаю, как сохранить уже нарисованные фигуры и восстановить их после. Также я не знаю, зачем мне нужны два элемента canvas, если я хочу рисовать с предварительным просмотром. Спасибо!
//JavaScript FILE
let canvas = document.getElementById("canvas");
let tempcanvas = document.getElementById("tempcanvas")
var ctx = tempcanvas.getContext('2d');
var mainctx = canvas.getContext('2d');
ctx.fillStyle="aqua";
ctx.fillRect(0, 0, canvas.width, canvas.height);
var widthCns = canvas.width, heightCns = canvas.height, x1, y1;
var isDown = false;
var savedDrawings = [];
//Desenare cu un singur tip de instrument (elipsă)
function drawEllipse(x1, y1, x2, y2){
var radiusX = (x2 - x1) * 0.5, /// radius for x based on input
radiusY = (y2 - y1) * 0.5, /// radius for y based on input
centerX = x1 radiusX, /// calc center
centerY = y1 radiusY,
step = 0.01, /// resolution of ellipse
a = step, /// counter
pi2 = Math.PI * 2 - step; /// end angle
/// start a new path
ctx.beginPath();
/// set start point at angle 0
ctx.moveTo(centerX radiusX * Math.cos(0),
centerY radiusY * Math.sin(0));
/// create the ellipse
for(; a < pi2; a = step) {
ctx.lineTo(centerX radiusX * Math.cos(a),
centerY radiusY * Math.sin(a));
}
/// close it and stroke it for demo
ctx.closePath();
ctx.strokeStyle = '#000';
ctx.stroke();
}
//Desenare cu un singur tip de instrument (dreptunghi)
function drawRect(){
}
//Desenare cu un singur tip de instrument (linie)
function drawLine(){
}
//Desenare cu mouse cu preview(elipsa, dreptunghi, line)
//Implementat: elipsa
/// handle mouse down
tempcanvas.onmousedown = function(e) {
// if(savedDrawings !== null)
// savedDrawings.pop();
// while( ctx!== null){
// ctx.restore();
// }
ctx.restore();
/// get corrected mouse position and store as first point
var rect = tempcanvas.getBoundingClientRect();
x1 = e.clientX - rect.left;
y1 = e.clientY - rect.top;
isDown = true;
}
/// clear isDown flag to stop drawing
tempcanvas.onmouseup = function() {
// savedDrawings.push({X: x1, Y: y1});
ctx.save();
isDown = false;
}
/// draw ellipse from start point
tempcanvas.onmousemove = function(e) {
if (!isDown) return;
var rect = tempcanvas.getBoundingClientRect(),
x2 = e.clientX - rect.left,
y2 = e.clientY - rect.top;
/// clear temporal canvas
ctx.clearRect(0, 0, widthCns, heightCns);
/// draw ellipse
drawEllipse(x1, y1, x2, y2);
}
//HTML FILE
<canvas id="canvas" width="800" height="500" padding="15px" position="absolute" background-color="aqua" style="border: 1px solid black">
</canvas>
<!-- canvas temporal -->
<canvas id="tempcanvas" width=800 height=500 padding="15px" position="absolute" background-color="aqua" style="border: 1px solid black"></canvas>
Ответ №1:
Вопрос: Зачем вам нужны два холста для рисования с предварительным просмотром?
Ответ: Один холст используется для отображения предварительного просмотра при удержании кнопки мыши. Когда вы перемещаете курсор мыши, весь холст перерисовывается заново. Поэтому его всегда нужно очищать перед рисованием. Если вы прокомментируете строку с помощью ctx.clearRect, вы увидите, что для каждого перемещения мыши выполняется множество фигур.
Второй холст используется для хранения всех нарисованных фигур. Как вы можете видеть в нижнем примере, вы можете расположить временный холст с прозрачным фоном поверх основного холста, чтобы он выглядел так, как будто вы рисуете только в одном из них.
Вопрос: Как сохранить уже нарисованную фигуру на основной холст?
Ответ: Используйте метод drawImage для копирования изображения с временного холста на основной холст.
const canvas = document.getElementById("canvas");
const tempcanvas = document.getElementById("tempcanvas")
const ctx = tempcanvas.getContext('2d');
const mainctx = canvas.getContext('2d');
mainctx.fillStyle='#cec';
mainctx.fillRect(0, 0, canvas.width, canvas.height);
const widthCns = canvas.width, heightCns = canvas.height;
var isDown = false;
var savedDrawings = [];
var x1, y1;
//Desenare cu un singur tip de instrument (elipsă)
function drawEllipse(x1, y1, x2, y2){
let radiusX = (x2 - x1) * 0.5, /// radius for x based on input
radiusY = (y2 - y1) * 0.5, /// radius for y based on input
centerX = x1 radiusX, /// calc center
centerY = y1 radiusY,
step = 0.01, /// resolution of ellipse
a = step, /// counter
pi2 = Math.PI * 2 - step; /// end angle
/// start a new path
ctx.beginPath();
/// set start point at angle 0
ctx.moveTo(centerX radiusX * Math.cos(0),
centerY radiusY * Math.sin(0));
/// create the ellipse
for(; a < pi2; a = step) {
ctx.lineTo(centerX radiusX * Math.cos(a),
centerY radiusY * Math.sin(a));
}
/// close it and stroke it for demo
ctx.closePath();
ctx.strokeStyle = '#000';
ctx.stroke();
}
/// handle mouse down
tempcanvas.onmousedown = function(e) {
ctx.restore();
/// get corrected mouse position and store as first point
var rect = tempcanvas.getBoundingClientRect();
x1 = e.clientX - rect.left;
y1 = e.clientY - rect.top;
isDown = true;
}
/// clear isDown flag to stop drawing
tempcanvas.onmouseup = function() {
mainctx.drawImage(tempcanvas, 0, 0);
ctx.clearRect(0, 0, widthCns, heightCns);
ctx.save();
isDown = false;
}
/// draw ellipse from start point
tempcanvas.onmousemove = function(e) {
if (!isDown) return;
var rect = tempcanvas.getBoundingClientRect(),
x2 = e.clientX - rect.left,
y2 = e.clientY - rect.top;
/// clear temporal canvas
ctx.clearRect(0, 0, widthCns, heightCns);
/// draw ellipse
drawEllipse(x1, y1, x2, y2);
}
#canvas,
#tempcanvas {
position: absolute;
top: 0;
left: 0;
}
#tempcanvas {
}
<canvas id="canvas" width="800" height="500"></canvas>
<canvas id="tempcanvas" width=800 height=500></canvas>
Скрипка: https://jsfiddle.net/4v3r9pdt/3 /
Хорошая статья о сохранении и восстановлении контекста холста: https://html5.litten.com/understanding-save-and-restore-for-the-canvas-context /
Документация по рисованию изображений: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage
Комментарии:
1. Это сработало! Спасибо! Есть ли другой способ рисовать фигуры с предварительным просмотром без использования двух элементов canvas?
2. Также как я могу сделать так, чтобы мои кнопки выбирали фигуру при нажатии, а затем рисовали с этой формой?
3. Добро пожаловать. Да, есть способ использовать только один холст. Но, конечно, вы должны где-то сохранить результат, который вы не хотите перерисовывать (возможно, изображение). Для любых других несвязанных проблем, пожалуйста, создайте другое сообщение.