Skip to content

Instantly share code, notes, and snippets.

@muhsinokcu
Created November 16, 2021 10:17
Show Gist options
  • Save muhsinokcu/718098637897d086769ffbb2a4121554 to your computer and use it in GitHub Desktop.
Save muhsinokcu/718098637897d086769ffbb2a4121554 to your computer and use it in GitHub Desktop.
Paint w/ canvas
h1 Paint
p.legend Draw me like one of your french girl in the box below
canvas#paint(width=270)(height=150)
button#clear clear
h2 Painted base64
textarea#data-paint.data
/*
* This method returns the relative offset x/y for a mouse cursor position in an element such as canvas
* @param {object} e - the event object</param>
* @param {string} id - the id of the element in which the mouse is positioned
*/
function getMouseOffset (_e, _el) {
let xpos, ypos;
if (typeof _e.offsetX === 'undefined') { // ff hack
// dans ce cas, jQuery facilite l'appel d'offset
xpos = _e.pageX - $(_el).offset().left;
ypos = _e.pageY - $(_el).offset().top;
} else {
xpos = _e.offsetX;
ypos = _e.offsetY;
}
const pointerPos = { x: xpos, y: ypos };
console.log(pointerPos);
return pointerPos;
}
/**
* Extends Canvas element to use it as a paint element
*/
var extendCanvas = function (canvas) {
if (typeof canvas === 'string') {
canvas = document.getElementById(canvas);
}
try {
canvas.ctx = canvas.getContext('2d');
canvas.ctx.strokeStyle = "black";
canvas.ctx.lineWidth = 2;
canvas.lineJoin = "round";
canvas.ctx.scale(1, 1);
canvas.isLocked = false;
canvas.hasDrawn = false;
canvas.disableSave = true;
canvas.pixels = [];
canvas.cpixels = [];
canvas.xyLast = {};
canvas.xyAddLast = {};
canvas.calculate = false;
//start drawing a stroke from a position
canvas.draw = function (x, y) {
this.ctx.lineTo(x, y);
this.ctx.stroke();
};
//Get the mouse position in the canvas
canvas.getCursorCoords = function (e) {
return getMouseOffset(e, this);
};
//Clear the content of the canvas element
canvas.clear = function () {
if (!this.isLocked) {
this.ctx.clearRect(0, 0, this.width, this.height);
this.emptyRelatedField();
this.isModified(false);
}
};
//Lock the canvas element
canvas.lock = function (shouldLock) {
this.isLocked = shouldLock;
if (shouldLock) {
$(this).addClass('disabled');
} else {
$(this).removeClass('disabled');
}
};
canvas.isModified = function (wasModified) {
if (wasModified) {
this.fillRelatedField();
$(this).addClass('modified');
} else {
this.emptyRelatedField();
$(this).removeClass('modified');
}
};
//Empty the field that contains the base64 string
canvas.emptyRelatedField = function () {
var relatedField = document.getElementById('data-' + this.id);
if (relatedField) {
relatedField.value = "";
}
};
//Fill the filed that contains the base64 string
canvas.fillRelatedField = function () {
document.getElementById('data-' + this.id).value = this.toDataURL();
};
//Load a passed image
canvas.loadImage = function (base64Img) {
//if (!canvas.isLocked) {
var image = new Image();
var thisCanvas = this;
if (base64Img.indexOf("data:image/png;base64,") === -1) {
base64Img = "data:image/png;base64," + base64Img;
}
image.src = base64Img;
image.onload = function () {
var offset = { x: 0, y: 0 };
//center the image in the canvas
try {
offset.x = ((thisCanvas.width / 2) - (image.width / 2));
offset.y = ((thisCanvas.height / 2) - (image.height / 2));
if (offset.x < 0 || offset.y < 0) {
throw {
name: "Painting error",
message: "Image has a negativ offset.",
toString: function () { return this.name + ": " + this.message; }
};
}
} catch (err) {
offset = { x: 0, y: 0 };
}
thisCanvas.ctx.drawImage(image, offset.x, offset.y);
};
};
/**
* This method remove the event by default, to load them only when clicking in the canvas
*/
function remove_event_listeners() {
canvas.removeEventListener('mouseup', on_mouseup, false);
canvas.removeEventListener('touchend', on_mouseup, false);
canvas.removeEventListener('pointerup', on_mouseup, false);
canvas.removeEventListener('mousemove', on_mousemove, false);
canvas.removeEventListener('pointermove', on_mousemove, false);
document.body.removeEventListener('mouseup', on_mouseup, false);
document.body.removeEventListener('touchend', on_mouseup, false);
document.body.removeEventListener('pointerup', on_mouseup, false);
};
//Event when the mouse is clicked
function on_mousedown(e) {
console.log('mousedown');
if (!canvas.isLocked) {
e.preventDefault();
e.stopPropagation();
canvas.hasDrawn = false;
//we activate the mouse and touch events
canvas.addEventListener('mouseup', on_mouseup, false);
canvas.addEventListener('touchend', on_mouseup, false);
canvas.addEventListener('pointerup', on_mouseup, false);
canvas.addEventListener('mousemove', on_mousemove, false);
canvas.addEventListener('pointermove', on_mousemove, false);
document.body.addEventListener('mouseup', on_mouseup, false);
document.body.addEventListener('touchend', on_mouseup, false);
document.body.addEventListener('pointerup', on_mouseup, false);
var xy = canvas.getCursorCoords(e);
canvas.ctx.beginPath();
canvas.pixels.push('moveStart');
canvas.ctx.moveTo(xy.x, xy.y);
canvas.pixels.push(xy.x, xy.y);
canvas.xyLast = xy;
}
};
//Event when the mouse is moving.
function on_mousemove(e, finish) {
if (!canvas.isLocked) {
e.preventDefault();
e.stopPropagation();
canvas.hasDrawn = true;
var xy = canvas.getCursorCoords(e);
var xyAdd = {
x: (canvas.xyLast.x + xy.x) / 2,
y: (canvas.xyLast.y + xy.y) / 2
};
if (canvas.calculate) {
var xLast = (canvas.xyAddLast.x + canvas.xyLast.x + xyAdd.x) / 3;
var yLast = (canvas.xyAddLast.y + canvas.xyLast.y + xyAdd.y) / 3;
canvas.pixels.push(xLast, yLast);
} else {
canvas.calculate = true;
}
canvas.ctx.quadraticCurveTo(canvas.xyLast.x, canvas.xyLast.y, xyAdd.x, xyAdd.y);
canvas.pixels.push(xyAdd.x, xyAdd.y);
canvas.ctx.stroke();
canvas.ctx.beginPath();
canvas.ctx.moveTo(xyAdd.x, xyAdd.y);
canvas.xyAddLast = xyAdd;
canvas.xyLast = xy;
}
};
//Event when the click is released
function on_mouseup(e) {
console.log('mouseup');
if (!canvas.isLocked) {
if (!canvas.hasDrawn) {//If there was no move, draw a single point
var pos = canvas.getCursorCoords(e);
canvas.ctx.rect(pos.x, pos.y, 1, 1);
}
remove_event_listeners();
canvas.disableSave = false;
canvas.ctx.stroke();
canvas.pixels.push('e');
canvas.calculate = false;
canvas.isModified(true);
canvas.hasDrawn = false;
}
};
//We activate only the click or touch event.
// ReSharper disable once Html.EventNotResolved correspond à un événement de toucher sur écran tactile
canvas.addEventListener('mousedown', on_mousedown, false);
canvas.addEventListener('touchstart', on_mousedown, false);
canvas.addEventListener('pointerdown', on_mousedown, false);
} catch (err) {
//If someting went wrong, notify the user.
console.error("Canvas not initialized. Painting is not activated.");
}
return canvas;
};
var myC = extendCanvas('paint');
$('#clear').on('click', (e) => {
myC.clear();
myC.emptyRelatedField();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
body {
font-family: Arial;
}
#paint {
border: 1px solid #333;
display: block;
margin: 20px 0;
}
#clear {
margin: 8px 0;
padding: 4px 8px;
font-size: 1rem;
}
.data {
width: 266px;
height: 150px;
margin: 5px 0;
}
.legend {
font-style: italic;
color: grey;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment