I'm building a to-do list with a progress circle, using one of the alternatives given here (CSS Progress Circle). In my script.js I defined the function drawRingProgress() which renders the canvas when I execute it at the end of the script.
As the other functions of my script are executed to add tasks, edit, remove, or mark them as complete, the parameters pendingTasks and completedTasks get updated. However, if I call the function drawRingProgress() within the other mentioned functions, in order to update the progress, the canvas is wrongly drawn somewhere else multiple times (depending on the HTML elements these functions are acting on). What would be a correct approach to render the updated progress percentage?
Link to the working example: https://jsfiddle.net/tailslider13/f4qtmhzj/7/
let pendingTasks = 31;
let completedTasks = 69;
function drawRingProgress(pendingTasks, completedTasks) {
var el = document.getElementById('graph'); // get canvas
let progress_percentage = Math.floor((completedTasks / (completedTasks + pendingTasks)) * 100) || 0;
var options = {
// percent: el.getAttribute('data-percent') || 25,
percent: progress_percentage,
// size: 110,
size: el.getAttribute('data-size') || 220,
lineWidth: el.getAttribute('data-line') || 15,
rotate: el.getAttribute('data-rotate') || 0
}
var canvas = document.createElement('canvas');
var span = document.createElement('span');
span.textContent = options.percent + '%';
if (typeof (G_vmlCanvasManager) !== 'undefined') {
G_vmlCanvasManager.initElement(canvas);
}
var ctx = canvas.getContext('2d');
canvas.width = canvas.height = options.size;
el.appendChild(span);
el.appendChild(canvas);
ctx.translate(options.size / 2, options.size / 2); // change center
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI); // rotate -90 deg
//imd = ctx.getImageData(0, 0, 240, 240);
var radius = (options.size - options.lineWidth) / 3.2;
var drawCircle = function (color, lineWidth, percent) {
percent = Math.min(Math.max(0, percent || 1), 1);
ctx.beginPath();
ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, false);
ctx.strokeStyle = color;
ctx.lineCap = 'round'; // butt, round or square
ctx.lineWidth = lineWidth
ctx.stroke();
};
drawCircle('#efefef', options.lineWidth, 100 / 100);
drawCircle('#046582', options.lineWidth, options.percent / 100)
}
drawRingProgress(pendingTasks, completedTasks);
Here is how I would draw the graph. I have removed all of the other functions from this so it is only showing the graph progress based on what you set the variables to. Once you get your other functions figured out you can updated them via that method.
First I would get the canvas at the beginning of the script and also designate the variables a global.
Second I would draw the white doughnut flat out. Unless you plan on changing it in some way the function drawGraph() will get called once and that's it.
Third the function drawRingProgress() will get called from your other functions when you add, delete, or complete a task. Be sure those function also update pendingTasks and completedTasks prior to calling drawRingProgress().
Inside drawRingProgress() I added the text since canvas has that built in method so you don't need to use a <span>. As far as all your options I removed them for this but you can add them back as where you see fit.
const inputField = document.getElementById("addTask");
const taskList = document.getElementById("taskList");
var canvas = document.getElementById('graph');
var ctx = canvas.getContext('2d');
canvas.width = 200;
canvas.height = 200;
let pendingTasks = 20;
let completedTasks = 5;
//Progress ring
function drawGraph() {
ctx.beginPath();
ctx.strokeStyle = "white";
ctx.arc(canvas.width/2, canvas.height/2, 50, 0, Math.PI*2, false);
ctx.lineCap = 'round'; // butt, round or square
ctx.lineWidth = 15;
ctx.stroke();
ctx.closePath();
}
drawGraph();
function drawRingProgress(pendingTasks, completedTasks) {
let progress_percentage = (completedTasks / pendingTasks) * 100;
ctx.font = "30px sans-serif";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = "#046582";
ctx.fillText(progress_percentage+'%', canvas.width/2,canvas.height/2);
percent = Math.min(Math.max(0, (progress_percentage/100) || 1), 1);
ctx.beginPath();
ctx.save();
ctx.translate(0, canvas.height); // change center
ctx.rotate((-1 / 2 + 0 / 180) * Math.PI); // rotate -90 deg
ctx.arc(canvas.width/2, canvas.height/2, 50, 0, Math.PI * 2 * percent, false);
ctx.strokeStyle = "#046582";
ctx.lineCap = 'round'; // butt, round or square
ctx.lineWidth = 15;
ctx.stroke();
ctx.restore();
ctx.closePath();
}
drawRingProgress(pendingTasks, completedTasks);
#body {
background-color: #046582;
}
header {
background-color: #f39189;
padding: 50px;
margin: 50px;
position: sticky;
top: 0px;
}
h1 {
text-align: center;
}
.listItem {
margin: 20px 0px;
background-color: white;
}
.container {
background-color: #c4c4c4;
}
.taskList {
list-style-type: none;
background-color: transparent;
overflow: hidden;
margin-top: 150px;
}
.inputContainer {
margin: 50px;
padding: 20px;
max-width: 50%;
width: 100%;
background-color: #f39189;
}
#footer {
text-align: center;
position: sticky;
bottom: 0px;
background-color: #f39189;
padding: 20px;
}
.deleteButton {
background-image: url("/content/delete.png");
background-repeat: no-repeat;
background-size: cover;
cursor: pointer;
width: 30px;
height: 30px;
margin: 15px;
}
#addTask {
font-family: Verdana, Geneva, Tahoma, sans-serif;
font-size: 1.3rem;
}
.taskName {
font-family: Verdana, Geneva, Tahoma, sans-serif;
font-size: 1.2rem;
}
.listContainer {
height: 1080px;
}
.inputContainer {
position: fixed;
}
.checkedbox {
text-decoration: line-through;
color: #f39189;
}
/* START Styling Progress ring */
.chart {
position: relative;
/* margin:0px; */
width: 220px;
height: 220px;
}
canvas {
display: block;
position: absolute;
top: 0;
left: 0;
}
span {
color: #046582;
display: block;
line-height: 220px;
text-align: center;
width: 220px;
font-family: sans-serif;
font-size: 30px;
font-weight: 100;
margin-left: 5px;
}
/* Links progress ring */
/* https://stackoverflow.com/questions/14222138/css-progress-circle
http://jsfiddle.net/Aapn8/3410/ */
/* END Styling Progress ring */
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<!-- Required meta tags -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-wEmeIV1mKuiNpC+IOBjI7aAzPcEZeedi5yW5f2yOq55WWLwNGmvvx4Um1vskeMj0" crossorigin="anonymous" />
</head>
<div class="container">
<body id="body">
<header class="row justify-content-end">
<h1 class="col-4">Take note</h1>
<!-- Progress ring -->
<div class="col-4">
<canvas class="chart" id="graph"></canvas>
</div>
</header>
<!-- Input field and button -->
<div class="row inputContainer rounded">
<input class="col-auto" type="newTask" placeholder="Enter new Task" id="addTask" />
<button class="col-auto" id="btnAdd">Add</button>
</div>
<!-- List of tasks created -->
<div class="listContainer">
<ul class="taskList rounded" id="taskList"></ul>
</div>
<footer class="row" id="footer">
<h6 class="col w-100">2021</h6>
</footer>
<!-- BOOTSTRAP -->
<script src="https://cdn.jsdelivr.net/npm/#popperjs/core#2.9.2/dist/umd/popper.min.js" integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p" crossorigin="anonymous">
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0/dist/js/bootstrap.min.js" integrity="sha384-lpyLfhYuitXl2zRZ5Bn2fqnhNAKOAaM/0Kr9laMspuaMiZfGmfwRNFh8HlMy49eQ" crossorigin="anonymous">
</script>
</body>
</div>
</html>
I also wasn't sure what you intent was with using bootstraps chart. I haven't used it before but from checking the docs it didn't appear you were actually coding appropriatly for it. Also you had a <div> with the class of chart and not a <canvas> which appeared wrong to me (but like I said I haven't used it before). In the example here I changed it to <canvas> and also got rid of the canvas you were creating along with the span.
Hopefully this is what you wanted if not maybe you can still piece together what I have here with what exactly you want.
Hey Carlos and everybody interested in a solution.
After investigating the code I noticed the problem lies in creating the elements span and canvas everytime the function gets invoked but never removed.
The solution to that is to have these elements in place to begin with, namely in the html code || or create them once before the function is called.
As for the variables pendingTasks and completedTasks, I would suggest changing them to pendingTasks and totalAmountOfTasks. (Unless there is a third state in which they can be.)
Then the ratio you would feed into the circle is pendingTasks/totalAmountOfTasks.
Remember to check for dividing by zero, when there are no tasks!
Cheers,
Thomas
Related
I am attempting to create a drawing app in JS, however, whenever anything is drawn, it is positioned away from my cursor depending on where it is on the canvas, when I am on the furthest left/bottom side of the canvas, you can draw where your cursor is, but the further right/up I move, the more the brush begins to "drift" and go further than where my cursor is.
const canvas = document.getElementById("canvas");
const increaseBtn = document.getElementById("increase");
const decreaseBtn = document.getElementById("decrease");
const sizeEl = document.getElementById("size");
const colorEl = document.getElementById("color");
const clearEl = document.getElementById("clear");
//Core Drawing Functionality (with some research)
const ctx = canvas.getContext("2d");
let size = 5;
let isPressed = false;
let color = "black";
let x;
let y;
let fakeSize = 1;
canvas.addEventListener("mousedown", (e) => {
isPressed = true;
x = e.offsetX;
y = e.offsetY;
});
canvas.addEventListener("mouseup", (e) => {
isPressed = false;
x = undefined;
y = undefined;
});
canvas.addEventListener("mousemove", (e) => {
if (isPressed) {
const x2 = e.offsetX;
const y2 = e.offsetY;
drawCircle(x2, y2);
drawLine(x, y, x2, y2);
x = x2;
y = y2;
}
});
function drawCircle(x, y) {
ctx.beginPath();
ctx.arc(x, y, size, 0, Math.PI * 2);
ctx.fillStyle = color;
ctx.fill();
}
function drawLine(x1, y1, x2, y2) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.strokeStyle = color;
ctx.lineWidth = size * 2;
ctx.stroke();
}
function updateSizeOnScreen() {
sizeEl.innerHTML = fakeSize;
}
increaseBtn.addEventListener("click", () => {
size += 5;
fakeSize++;
if (fakeSize > 10) {
fakeSize = 10;
}
if (size > 50) {
size = 50;
}
updateSizeOnScreen();
});
decreaseBtn.addEventListener("click", () => {
size -= 5;
fakeSize--;
if (fakeSize < 1) {
fakeSize = 1;
}
if (size < 5) {
size = 5;
}
updateSizeOnScreen();
});
colorEl.addEventListener("change", (e) => {
color = e.target.value;
});
clearEl.addEventListener("click", () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
});
//Eraser and Pencil Actions (my own algorithm)
const eraser = document.getElementById("eraser");
const pencil = document.getElementById("pencil");
eraser.addEventListener("click", () => {
localStorage.setItem("colorEl", JSON.stringify(color));
color = "#fff";
colorEl.disabled = true;
canvas.classList.add("eraseractive");
eraser.classList.add("eraseractive");
colorEl.classList.add("eraseractive");
canvas.classList.remove("pencilactive");
eraser.classList.remove("pencilactive");
colorEl.classList.remove("pencilactive");
});
pencil.addEventListener("click", () => {
JSON.parse(localStorage.getItem("colorEl"));
color = colorEl.value;
colorEl.disabled = false;
canvas.classList.remove("eraseractive");
eraser.classList.remove("eraseractive");
colorEl.classList.remove("eraseractive");
canvas.classList.add("pencilactive");
eraser.classList.add("pencilactive");
colorEl.classList.add("pencilactive");
});
// Dark/Light Mode
const darkMode = document.getElementById("darkMode");
const lightMode = document.getElementById("lightMode");
const toolbox = document.getElementById("toolbox");
darkMode.addEventListener("click", () => {
darkMode.classList.add("mode-active");
lightMode.classList.remove("mode-active");
lightMode.classList.add("rotate");
darkMode.classList.remove("rotate");
toolbox.style.backgroundColor = "#293462";
document.body.style.backgroundImage =
"url('/assets/images/darkModeBackground.svg')";
document.body.style.backgroundSize = "1920px 1080px";
canvas.style.borderColor = "#293462";
toolbox.style.borderColor = "#293462";
});
lightMode.addEventListener("click", () => {
lightMode.classList.add("mode-active");
darkMode.classList.remove("mode-active");
darkMode.classList.add("rotate");
lightMode.classList.remove("rotate");
toolbox.style.backgroundColor = "#293462";
document.body.style.backgroundImage =
"url('/assets/images/lightModeBackground.svg')";
document.body.style.backgroundSize = "1920px 1080px";
canvas.style.borderColor = "#293462";
toolbox.style.borderColor = "#293462";
});
* {
box-sizing: border-box;
font-size: 20px !important;
}
body {
background: url("https://drawing-app-green.vercel.app/assets/images/lightModeBackground.svg");
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
margin: 0;
position: relative;
max-height: 100vh;
overflow: hidden;
}
::selection {
background: transparent;
}
::-moz-selection {
background: transparent;
}
.mode {
display: flex;
position: absolute;
top: 10px;
right: 25px;
cursor: pointer;
}
.light-mode {
color: yellow;
}
.dark-mode {
color: #16213e;
}
.container {
display: flex;
flex-direction: column;
max-width: 1200px;
width: 100%;
max-height: 600px;
height: 100%;
}
canvas {
display: flex;
border: 2px solid #293462;
cursor: url("https://drawing-app-green.vercel.app/assets/images/pencilCursor.png") 2 48, pointer;
background-color: #fff;
margin-top: 3rem;
width: 100%;
height: 600px;
}
.toolbox {
background-color: #293462;
border: 1px solid #293462;
display: flex;
width: 100%;
align-items: center;
justify-content: center;
padding: 0.2rem;
}
.toolbox > * {
background-color: #fff;
border: none;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 2rem;
height: 30px;
width: 30px;
margin: 0.25rem;
padding: 0.25rem;
cursor: pointer;
}
.toolbox > *:last-child {
margin-left: auto;
}
canvas.eraseractive {
cursor: url("https://drawing-app-green.vercel.app/assets/images/eraserCursor.png") 2 48, pointer;
}
#color.eraseractive {
cursor: not-allowed;
}
canvas.pencilactive {
cursor: url("https://drawing-app-green.vercel.app/assets/images/pencilCursor.png") 2 48, pointer;
}
.mode-active {
visibility: hidden;
}
.rotate {
transform: rotate(360deg);
transition: transform 1s linear;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Drawing App</title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"
integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
</head>
<body>
<i class="fa-solid fa-moon dark-mode fa-2x mode" id="darkMode"></i>
<i
class="fa-solid fa-sun light-mode fa-2x mode mode-active"
id="lightMode"
></i>
<div class="container">
<canvas id="canvas" width="1024" height="600"></canvas>
<div class="toolbox" id="toolbox">
<button id="decrease">-</button>
<span id="size">1</span>
<button id="increase">+</button>
<input type="color" id="color" />
<button id="pencil">
<img src="assets/images/pencilCursor.png" alt="" />
</button>
<button id="eraser">
<img src="assets/images/eraserCursor.png" alt="" />
</button>
<button id="clear">X</button>
</div>
</div>
<script src="assets/js/script.js"></script>
</body>
</html>
Your problem is that your canvas dimentions don't match with the dimentions of the HTML element that contains it. You see: your canvas has a fixed width="" and height="" attributes set. But in your HTML your canvas element has a width of 100%. So that means that the container vairies in dimentions but the canvas inside it not. This result in the canvas trying to resize to show inside the container thus giving you issues with calculating exacly what pixel you are clicking.
You have two options:
Option 1: calculate your click position taking into account canvas deformation
If you want your canvas to resize, then calculate the real position using a simple ratio formula. If for example your canvas has a width of 100 but right now its container is 10px wide, then if you click on pixel 5 you expect a dot to be drawn at pixel 50. In other words if your canvas is smaller by a factor of 10 then you need to multiply your position by a factor of 10.
In your code it would look something like this:
// this is your same code in lines 33 ana34 but see that I added a multiplication by the ratio between the canvas size and the canvas container
const x2 = e.offsetX * (canvas.width / ctx.canvas.getBoundingClientRect().width);
const y2 = e.offsetY * (canvas.height / ctx.canvas.getBoundingClientRect().height);
Option #2: Dont allow your canvas to deform
Remove the container class, and remove the width:100% from your canvas css. Your canvas will overflow and cause a scrollbar but the positions will be calculated properly with your code.
I have created a circle here so that when the screen is clicked, the circle will move there. And I also have a fixed point (vertex) that I want these two points to be the origin and destination of a line.
const coordinates = document.querySelector(".coordinates");
const circle = document.querySelector(".circle");
const result = document.querySelector(".result");
const numbers = document.querySelectorAll("p");
coordinates.addEventListener("click", e => {
circle.style.setProperty('--x', `${e.clientX}px`);
circle.style.setProperty('--y', `${e.clientY}px`);
})
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.moveTo(0,0);
ctx.lineTo(50,100);
ctx.stroke();
canvas {
color: rgb(255, 255, 255);
}
.circle {
width: 20px;
height: 20px;
border-radius: 50%;
position: fixed;
--x: 47px;
left: calc(var(--x) - 10px);
--y: 47px;
top: calc(var(--y) - 10px);
background-color: white;
}
.bg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #24232e;
}
.coordinates {
height: 100%;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div class="bg">
<div class="coordinates">
<canvas id="myCanvas" width="200" height="100" style=""></canvas>
</div>
</div>
<div class="circle">
</div>
</body>
</html>
How to do this with canvas?
! would appreciate <3
You can detect the mouse position on the canvas and draw a line to the coordinates. to get the canvas x and y of the mouse, you have to do some calculations because the site coordinates are a bit different than the canvas ones.
A more detailed description is here: https://stackoverflow.com/a/17130415/14076532
This will work only, if the canvas is big enough, logically...
Hope this helps:
const coordinates = document.querySelector(".coordinates");
const circle = document.querySelector(".circle");
const result = document.querySelector(".result");
const numbers = document.querySelectorAll("p");
coordinates.addEventListener("click", e => {
clicked(e);
circle.style.setProperty('--x', `${e.clientX}px`);
circle.style.setProperty('--y', `${e.clientY}px`);
})
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.strokeStyle = "#de7270"; // change your color here NOTE: this will remain until you change it
ctx.moveTo(0,0);
ctx.lineTo(50,100);
ctx.stroke();
function clicked(event) {
ctx.save(); // some canvas-safety-stuff
ctx.beginPath();
let mousepos = getMousePos(event); // get the mouse position in "canvas-cooridnates"
ctx.clearRect(0,0, c.width, c.height) // erease the canvas
ctx.moveTo(0, 0);
ctx.lineTo(mousepos.x, mousepos.y); // draw the line to the mouse
ctx.closePath();
ctx.stroke(); // closing of the canvas-safety-stuff
ctx.restore();
}
function getMousePos (evt) {
var rect = c.getBoundingClientRect(), // abs. size of element
scaleX = c.width / c.width, // relationship bitmap vs. element for X
scaleY = c.height / rect.height; // relationship bitmap vs. element for Y
return {
x: (evt.clientX - rect.left) * scaleX, // scale mouse coordinates after they have
y: (evt.clientY - rect.top) * scaleY // been adjusted to be relative to element
}
}
canvas {
color: rgb(255, 255, 255);
}
.circle {
width: 20px;
height: 20px;
border-radius: 50%;
position: fixed;
--x: 47px;
left: calc(var(--x) - 10px);
--y: 47px;
top: calc(var(--y) - 10px);
background-color: white;
}
.bg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #24232e;
}
.coordinates {
height: 100%;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div class="bg">
<div class="coordinates">
<canvas id="myCanvas" width="200" height="100" style=""></canvas>
</div>
</div>
<div class="circle">
</div>
</body>
</html>
I just recently uploaded my code files to a server. My website is a simple html5 drawing application where users are able to draw freely. I have this part done fine, however I am looking to implement a download button that simply downloads whatever the user has drawn as an image directly to their device i.e. phone, table, desktop. I have been looking for solutions to this for hours now and cant find anything. Is it a problem with my server? or anything like that? any help would be much appreciated. Below is my code
<!DOCTYPE html>
<html>
<head>
<title>Elemental</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
#import url('https://fonts.googleapis.com/css?family=Montserrat+Alternates');
#media screen and (max-width: 425px){
html,body{
overflow-x: hidden;
width: 100%;
margin: 0;
}
canvas { border: 3px solid #0BF446;
border-radius: 15px 0px 15px 0px;
display: block;
margin: 0 auto;
margin-top: 35px;
background-color:#313131;
position: relative;}
#download{background-color:#04A12B ;
border-radius: 0 15px 0 15px;
padding: 20px 40px;
margin: 0 auto;
display: block;
font-size: 14px;
margin-top: 35px;
color: white;
font-family: 'Montserrat Alternates', sans-serif;}
#clearbutton{background-color:#04A12B ;
border-radius: 0 15px 0 15px;
padding: 20px;
margin: 0 auto;
display: block;
font-size: 14px;
color: white;
font-family: 'Montserrat Alternates', sans-serif;
margin-top: 35px;}
</style>
</head>
<body>
<body onload="init()">
<img src="minilogo.png" id ="logo">
<canvas id="c" width="350px" height="350px"></canvas>
<button id = "download">Download</button>
<input type = "submit" value="Clear Sketchpad" id="clearbutton" onclick="clearCanvas(canvas,ctx);">
<script>
function init() {
// Get the specific canvas element from the HTML document
canvas = document.getElementById('c');
}
function midPointBtw(p1, p2) {
return {
x: p1.x + (p2.x - p1.x) / 2,
y: p1.y + (p2.y - p1.y) / 2
};
}
function getPattern() {
return ctx.createPattern(img, 'repeat');
}
var el = document.getElementById('c');
var ctx = el.getContext('2d');
ctx.lineWidth = 30;
ctx.lineJoin = ctx.lineCap = 'round';
var img = new Image;
img.onload = function() {
ctx.strokeStyle = getPattern();
};
img.src = "https://i.postimg.cc/rF2R0GRY/dick2.png";
var isDrawing, points = [];
var getXY = function(e) {
var source = e.touches ? e.touches[0] : e;
return {
x: source.clientX,
y: source.clientY
};
};
var startDrawing = function(e) {
isDrawing = true;
points.push(getXY(e));
event.preventDefault();
};
var keepDrawing = function(e) {
if (!isDrawing) return;
points.push(getXY(e));
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
var p1 = points[0];
var p2 = points[1];
ctx.moveTo(p1.x, p1.y);
for (var i = 1, len = points.length; i < len; i++) {
var midPoint = midPointBtw(p1, p2);
ctx.quadraticCurveTo(p1.x, p1.y, midPoint.x, midPoint.y);
p1 = points[i];
p2 = points[i + 1];
}
ctx.lineTo(p1.x, p1.y);
ctx.stroke();
event.preventDefault();
};
var stopDrawing = function() {
isDrawing = false;
points = [];
};
el.addEventListener('touchstart', startDrawing);
el.addEventListener('mousedown', startDrawing);
el.addEventListener('touchmove', keepDrawing);
el.addEventListener('mousemove', keepDrawing);
el.addEventListener('touchend', stopDrawing);
el.addEventListener('mouseup', stopDrawing);
function clearCanvas(canvas,ctx) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath()
}
</script>
</body>
</html>
You can use the Canvas#toDataURL method to generate a URL containing all the data of the canvas's current image. This can then be used in place of any URL -- a link's href, a window.open, etc. For a download link, you can use the download attribute on a link, which is an HTML5 addition. The value of the download attribute is the filename that will be used as the default save filename.
So to put all that together:
<a id='downloadLink' download='myDrawing.png'>Download Image</a>
<script>
function createDownload() {
const downloadURL = document.getElementById('c').toDataURL();
document.getElementById('downloadLink').href = downloadURL;
}
</script>
I have a canvas that is the only thing on a page I want really want to see. I'm trying to make it such that when I resize my window, I always have the entire canvas viewable with no scroll bars and maintain the aspect ratio.
MCVE
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let w = canvas.width;
let h = canvas.height;
ctx.fillStyle = 'teal';
ctx.fillRect(0, 0, w, h);
ctx.strokeStyle = 'red';
ctx.lineWidth = 10;
ctx.rect(5, 5, w - 5, h - 5);
ctx.stroke();
* {
background-color: white;
max-height: 100%;
max-width: 100%;
margin: 0;
padding: 0;
}
div#canvasDiv {}
canvas#canvas {
display: block;
margin: auto;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<div id="canvasDiv">
<canvas id="canvas" width="500" height="500" />
</div>
</body>
</html>
All here at jsfiddle
With this attempt, it rescales just fine when I resize the width. However, when I resize the height, I get overflow.
Resize Width with appropriate rescaling
Resize Height with unwanted overflow
You may like to read this article: [Centering in CSS: A Complete Guide](https://css-tricks.com/centering-css-complete-guide/
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let w = canvas.width;
let h = canvas.height;
ctx.fillStyle = 'teal';
ctx.fillRect(0, 0, w, h);
ctx.strokeStyle = 'red';
ctx.lineWidth = 10;
ctx.rect(5, 5, w - 5, h - 5);
ctx.stroke();
* {
background-color: white;
max-height: 100%;
max-width: 100%;
margin: 0;
padding: 0;
}
canvas#canvas {
display: block;
margin: auto;
position:absolute;
top:0;bottom:0;
left:0;
right:0;
}
<div id="canvasDiv">
<canvas id="canvas" width="500" height="500"/>
</div>
I'm having really big problems with canvas code that I'm using only 1 time in the page (in logo) working fine, and that I'm trying to use it as buttons for menu and here is the problem, I don't know really what's im doing wrong, hope some of u help me.
it's the code that I'm using for the logo and is working fine:
HTML CODE:
<html>
<head>
<title>canvas</title>
</head>
<body>
<div id="container">
<div id="logo">
<canvas style="" width="800" id="broken-glass"></canvas>
<h1 style="color: rgba(250, 250, 250, 0.95);" id="logo-title">Canvas</h1>
</div>
<script type="text/javascript">
(function() {
var isCanvasSupported = function () {
var elem = document.createElement('canvas');
return !!(elem.getContext && elem.getContext('2d'));
};
if( isCanvasSupported() ) {
var canvas = document.getElementById('broken-glass'),
context = canvas.getContext('2d'),
width = canvas.width = Math.min(800, window.innerWidth),
height = canvas.height,
numTriangles = 100,
rand = function(min, max){
return Math.floor( (Math.random() * (max - min + 1) ) + min);
};
window.drawTriangles = function(){
context.clearRect(0, 0, width, height);
var hue = rand(0,360);
var increment = 80 / numTriangles;
for(var i = 0; i < numTriangles; i++) {
context.beginPath();
context.moveTo(rand(0,width), rand(0,height) );
context.lineTo(rand(0,width), rand(0,height) );
context.lineTo(rand(0,width), rand(0,height) );
context.globalAlpha = 0.5;
context.fillStyle = 'hsl('+Math.round(hue)+', '+rand(15,60)+'%, '+ rand(10, 60) +'%)';
context.closePath();
context.fill();
hue+=increment;
if(hue > 360) hue = 0;
}
canvas.style.cssText = '-webkit-filter: contrast(115%);';
};
document.getElementById('logo-title').style.color = 'rgba(250, 250, 250, 0.95)';
drawTriangles();
var el = document.getElementById('logo');
el.onclick = function() {
drawTriangles();
};
}
})();
</script>
</div>
</body>
</html>
and it's CSS CODE:
#broken-glass
{
position: absolute;
left: 0px;
top: 0px;
width: 100%;
}
#logo h1
{
text-align: center;
font-weight: 700;
width: 100%;
color: #000;
position: absolute;
left: 0px;
-moz-user-select: none;
cursor: pointer;
margin-top: 27px;
font-size: 63px;
line-height: 1.4;
top: 0px;
margin-bottom: 5px;
text-rendering: optimizelegibility;
font-family: Calibri,"PT Sans","Trebuchet MS","Helvetica Neue",Arial;
}
the big problem comes when i change the id's (#) to classes (.) and the "id" tag to "class" tag in the html, the canvas is overlapped... the text of h1 tag is out of the canvas... and just the hell of problems, can someone tell me what I'm doing wrong?, how to fix it, I'm trying it during hours...
too much thanks in advance!.
you may try putting an !important in every code in your css.
example:
text-align: center !important;
font-weight: 700 !important;
this fixed my problem before, hopefully it will fix yours also.