Save Canvas as Image Internet Explorer - javascript

I've built a couple of web resources to add signature functionality to a Microsoft Dynamics CRM 2011 form one bit built in silverlight as a file uploader etc. and the other in javascript and HTML to do the signature on the screen and save as an image but the code only works in google chrome.
I've done some reading around looked on endless amounts of stackoverflow threads but can't find any answers.
Is there anyway in which I can somehow either
save the canvas image in IE, the way the current solution already works in chrome
Open up a new window so the canvas image appears and can be right clicked and saved
I've tried doing both of the above already but had no luck.
It has to be in javascript also
<html><head>
<script type="text/javascript">
var canvas, ctx, flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
dot_flag = false;
var x = "black",
y = 2;
function init() {
canvas = document.getElementById('can');
ctx = canvas.getContext("2d");
w = canvas.width;
h = canvas.height;
canvas.addEventListener("mousemove", function (e) {
findxy('move', e)
}, false);
canvas.addEventListener("mousedown", function (e) {
findxy('down', e)
}, false);
canvas.addEventListener("mouseup", function (e) {
findxy('up', e)
}, false);
canvas.addEventListener("mouseout", function (e) {
findxy('out', e)
}, false);
}
function color(obj) {
switch (obj.id) {
case "black":
x = "black";
break;
case "white":
x = "white";
break;
}
if (x == "white") y = 50;
else y = 2;
}
function draw() {
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(currX, currY);
ctx.strokeStyle = x;
ctx.lineWidth = y;
ctx.stroke();
ctx.closePath();
}
function erase() {
var m = confirm("Want to clear");
if (m) {
ctx.clearRect(0, 0, w, h);
document.getElementById("canvasimg").style.display = "none";
}
}
function findxy(res, e) {
if (res == 'down') {
prevX = currX;
prevY = currY;
currX = e.clientX - canvas.offsetLeft;
currY = e.clientY - canvas.offsetTop;
flag = true;
dot_flag = true;
if (dot_flag) {
ctx.beginPath();
ctx.fillStyle = x;
ctx.fillRect(currX, currY, 2, 2);
ctx.closePath();
dot_flag = false;
}
}
if (res == 'up' || res == "out") {
flag = false;
}
if (res == 'move') {
if (flag) {
prevX = currX;
prevY = currY;
currX = e.clientX - canvas.offsetLeft;
currY = e.clientY - canvas.offsetTop;
draw();
}
}
}
function downloadCanvas(link, canvasId, filename) {
var test = document.getElementById(canvasId).toDataURL();
link.href = document.getElementById(canvasId).toDataURL();
link.download = filename;
window.open(test);
}
/**
* The event handler for the link's onclick event. We give THIS as a
* parameter (=the link element), ID of the canvas and a filename.
*/
document.getElementById('download').addEventListener('click', function() {
downloadCanvas(this, 'can', 'signature.png');
}, false);
</script>
<meta><meta><meta charset="utf-8"></head>
<body onload="init()">
<canvas width="400" height="200" id="can" style="border: 2px solid currentColor; left: 10px; top: 10px; position: absolute; background-color: rgb(255, 255, 255);"></canvas>
<div style="left: 450px; top: 10px; position: absolute;">Choose Color</div>
<div id="black" style="background: black; left: 550px; top: 15px; width: 19px; height: 19px; position: absolute;" onclick="color(this)"></div>
<div style="left: 450px; top: 40px; position: absolute;">Eraser</div>
<div id="white" style="background: white; border: 2px solid currentColor; left: 550px; top: 45px; width: 15px; height: 15px; position: absolute;" onclick="erase()"></div>
<img id="canvasimg" style="left: 52%; top: 10%; position: absolute;">
<a class="button" id="download" style="left: 10px; top: 220px; position: absolute;" onclick="downloadCanvas(this, 'can', 'test.png')" href="#">Download</a>
</body></html>

[FINAL ANSWER/EDIT]
Open a new window, and set the innerHTML property of the body to:
<img src="[DATA URI GOES HERE]"/>
According to MSDN, the toDataURL() method works in IE >= 9.
canvasElement.toDataURL(imageMimeType,quality)
imageMimeType can be "image/png", " image/jpg", "image/webp" and I believe "image/gif" as well.
To achieve what you wish to do, you could set an anchor with the href of the canvas data URI, or even use window.open to open the data URI in a new tab.
Saving Image in Same Tab: Another StackOverflow Question
Resources for Data URIs:
http://en.wikipedia.org/wiki/Data_URI_scheme
https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs

Related

I need some help increasing the height of HTML canvas lines

I am doing a project where the user selects what programming language they enjoy out of a radio box. It sets an object to the Local Storage and creates a bar graph and the bars go up depending on what choice the select. I'm having trouble though where if the user selects the language for the third time, it turns out what is in the image. I change the height each time and for some reason it also goes over the axis. I just want the height to change. I'm not super familiar with the canvas. Is there a way I could go about doing this? I just simply want the bar to start at the origin and go up, but not down.
Code below:
<!--
Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
Click nbfs://nbhost/SystemFileSystem/Templates/Other/html.html to edit this template
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Extra Credit Challenge</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
#entryArea{
border: 1px solid black;
width: 30%;
border-radius: 100px;
text-align: center;
margin: auto;
}
#myCanvas{
border-radius: 25px;
border: 1px;
}
#submitButton{
border-radius: 15px;
background-color:lightblue;
font-size: 25px;
width: 30%;
}
input{
font-size: 25px;
}
#resetButton{
border-radius: 15px;
background-color:lightblue;
font-size: 25px;
width: 30%;
}
</style>
</head>
<body onload="init()">
<canvas id="myCanvas" width="500" height="450" style="border:1px solid #000000;"></canvas>
<div id="entryArea">
<p style="font-size: 20px">What is your favorite programming language?</p>
<p><input name="language" type="radio" value="Web Design">Web Design</p>
<p><input name="language" type="radio" value="Java">Java</p>
<p><input name="language" type="radio" value="Python">Python</p>
<p><input name="language" type="radio" value="Other">Other</p>
<button id="submitButton">Submit</button><br><br>
<button id="resetButton">Reset</button>
</div>
<script>
function init(){
unCheckItems();
drawAxes();
walkThroughStorage();
document.getElementById("submitButton").addEventListener("click", setItemToStorage);
document.getElementById("resetButton").addEventListener("click", clearCanvas);
}
function walkThroughStorage(){
var ele = document.getElementById("entryArea").querySelectorAll("input");
var curTextStorage = localStorage.getItem("ClickedBoxes");
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
curTextStorage = JSON.parse(curTextStorage);
if(curTextStorage !== null){
for(let i = 0; i<ele.length; i++){
let height = (curTextStorage[ele[i].value] || 0) * 40;
if(ele[i].value === "Web Design"){
if(curTextStorage[ele[i].value] > 1){
ctx.rect(80, 310-(height/2), 30, height);
ctx.lineWidth = 1;
ctx.stroke();
}
if(curTextStorage[ele[i].value] === 1){
ctx.rect(80, 310, 30, 40);
ctx.lineWidth = 1;
ctx.stroke();
}
}
else if(ele[i].value === "Java"){
if(curTextStorage[ele[i].value] > 1){
ctx.rect(180, 310-(height/2), 30, height);
ctx.lineWidth = 1;
ctx.stroke();
}
if(curTextStorage[ele[i].value] === 1){
ctx.rect(180, 310, 30, 40);
ctx.lineWidth = 1;
ctx.stroke();
}
}
else if(ele[i].value === "Python"){
if(curTextStorage[ele[i].value] > 1){
ctx.rect(255, 310-(height/2), 30, height);
ctx.lineWidth = 1;
ctx.stroke();
}
if(curTextStorage[ele[i].value] === 1){
ctx.rect(255, 310, 30, 40);
ctx.lineWidth = 1;
ctx.stroke();
}
}
else{
if(curTextStorage[ele[i].value] > 1){
ctx.rect(335, 310-(height/2), 30, height);
ctx.lineWidth = 1;
ctx.stroke();
}
if(curTextStorage[ele[i].value] === 1){
ctx.rect(335, 310, 30, 40);
ctx.lineWidth = 1;
ctx.stroke();
}
}
}
}
ctx.closePath();
}
function drawAxes(){
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
//draw x axis
ctx.moveTo(20,350);
ctx.lineTo(500,350);
ctx.lineWidth = 4;
ctx.stroke();
ctx.closePath();
//draw y axis
ctx.beginPath();
ctx.moveTo(40,400);
ctx.lineTo(40,0);
ctx.stroke();
ctx.closePath();
//draw names at the bottom
ctx.font = "15px Arial";
ctx.fillText("Web Design", 60,370);
ctx.fillText("Java", 180,370);
ctx.fillText("Python", 250,370);
ctx.fillText("Other", 330,370);
}
function unCheckItems(){
var ele = document.getElementById("entryArea").querySelectorAll("input");
for(let i = 0; i < ele.length; i++) {
if(ele[i].checked){
ele[i].checked = false;
}
}
}
function setItemToStorage(){
var savedClicks = localStorage.getItem("ClickedBoxes");
let clickDict = JSON.parse(savedClicks) || {};
var ele = document.getElementById("entryArea").querySelectorAll("input");
for(let i = 0; i < ele.length; i++){
if(ele[i].checked){
if(!clickDict[ele[i].value]){
clickDict[ele[i].value]=1;
}
else//the key of 1,2,3,4 or 5 (contents of curRandNum) exist in theDict so add one to its value
{
clickDict[ele[i].value] += 1;
}
}
localStorage.setItem("ClickedBoxes",JSON.stringify(clickDict));
}
drawBars();
}
function drawBars(){
var savedClicks = localStorage.getItem("ClickedBoxes");
savedClicks = JSON.parse(savedClicks);
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
var ele = document.getElementById("entryArea").querySelectorAll("input");
for(let i = 0; i < ele.length; i++) {
let height = (savedClicks[ele[i].value] || 0) * 40;
if(ele[i].checked){
if(ele[i].value === "Web Design"){
if(savedClicks[ele[i].value] > 1){
clearBar();
//ctx.clearRect(80, 300, 30, 40);
ctx.rect(80, 310-(height/2), 30, height);
ctx.lineWidth = 0;
ctx.stroke();
}
if(savedClicks[ele[i].value] === 1){
ctx.rect(80, 310, 30, 40);
ctx.lineWidth = 1;
ctx.stroke();
}
}
else if(ele[i].value === "Java"){
if(savedClicks[ele[i].value] > 1){
clearBar();
ctx.rect(180, 310-(height/2), 30, height);
ctx.lineWidth = 0;
ctx.stroke();
}
if(savedClicks[ele[i].value] === 1){
ctx.rect(180, 310, 30, 40);
ctx.lineWidth = 1;
ctx.stroke();
}
}
else if(ele[i].value === "Python"){
if(savedClicks[ele[i].value] > 1){
clearBar();
ctx.rect(255, 310-(height/2), 30, height);
ctx.lineWidth = 0;
ctx.stroke();
}
if(savedClicks[ele[i].value] === 1){
ctx.rect(255, 310, 30, 40);
ctx.lineWidth = 1;
ctx.stroke();
}
}
else{
if(savedClicks[ele[i].value] > 1){
clearBar();
ctx.rect(335, 310-(height/2), 30, height);
ctx.lineWidth = 0;
ctx.stroke();
}
if(savedClicks[ele[i].value] === 1){
ctx.rect(335, 310, 30, 40);
ctx.lineWidth = 1;
ctx.stroke();
}
}
}
}
ctx.closePath();
}
function clearBar(){
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.clearRect(0, 0, c.width, c.height);
init();
}
function clearCanvas(){
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.clearRect(0, 0, c.width, c.height);
localStorage.clear();
init();
}
</script>
</body>
</html>
Here is the image photo
Thanks in advance!
You have a miscalculation when drawing your rectanlges.
The lines
ctx.rect(255, 310-(height/2), 30, height);
should be changed to
ctx.rect(255, 350 - height, 30, height);
That's a bit too much copy-paste. The basic issue is what #Ruan shows: if you want to draw a rectangle which ends at y=350, you just subtract its height from 350, without any division.
Other things added/removed here are:
0-1-many are not handled separately any more, a zero-sized rectangle conveniently stays inside the horizontal axis, so you can draw it, and 40 doesn't differ from 1*40, so there is no need to draw it separately
the code parts for drawing the 4 bars differred in their x coordinates only, even if their spacing is irregular, they can be picked from an array, see the [80, 180, 255, 335][i] part - bit nasty, but does the job
walkwhatever was removed, it was doing the same as drawBars()
a single reDraw() method was added for handling redraw of everything
duplicated canvas clearing removed
instead a clear() method was added for clearing existing data and calling reDraw()
init() is not reused anymore, as that would add click handlers again, which usually leads to interesting behaviour.
(And a fake localStorage has been added, simply because it's disabled for snippets hosted here on StackOverflow)
// this is just for simulating localStorage here on StackOverflow
const localStorage = {m: new Map(),
getItem: function(k) {return this.m.has(k) ? this.m.get(k) : null;},
setItem: function(k, v) {this.m.set(k, v);},
clear: function() {this.m.clear();}};
function init() {
unCheckItems();
drawAxes();
drawBars();
document.getElementById("submitButton").addEventListener("click", setItemToStorage);
document.getElementById("resetButton").addEventListener("click", clear);
}
function drawAxes() {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
//draw x axis
ctx.moveTo(20, 350);
ctx.lineTo(500, 350);
ctx.lineWidth = 4;
ctx.stroke();
ctx.closePath();
//draw y axis
ctx.beginPath();
ctx.moveTo(40, 400);
ctx.lineTo(40, 0);
ctx.stroke();
ctx.closePath();
//draw names at the bottom
ctx.font = "15px Arial";
ctx.fillText("Web Design", 60, 370);
ctx.fillText("Java", 180, 370);
ctx.fillText("Python", 250, 370);
ctx.fillText("Other", 330, 370);
}
function unCheckItems() {
var ele = document.getElementById("entryArea").querySelectorAll("input");
for (let i = 0; i < ele.length; i++) {
if (ele[i].checked) {
ele[i].checked = false;
}
}
}
function setItemToStorage() {
var savedClicks = localStorage.getItem("ClickedBoxes");
let clickDict = JSON.parse(savedClicks) || {};
var ele = document.getElementById("entryArea").querySelectorAll("input");
for (let i = 0; i < ele.length; i++) {
if (ele[i].checked) {
if (!clickDict[ele[i].value]) {
clickDict[ele[i].value] = 1;
} else //the key of 1,2,3,4 or 5 (contents of curRandNum) exist in theDict so add one to its value
{
clickDict[ele[i].value] += 1;
}
}
localStorage.setItem("ClickedBoxes", JSON.stringify(clickDict));
}
reDraw();
}
function drawBars() {
var savedClicks = localStorage.getItem("ClickedBoxes");
savedClicks = JSON.parse(savedClicks) || {};
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.lineWidth = 1;
var ele = document.getElementById("entryArea").querySelectorAll("input");
for (let i = 0; i < ele.length; i++) {
let height = (savedClicks[ele[i].value] || 0) * 40;
ctx.strokeRect([80, 180, 255, 335][i], 350 - height, 30, height);
}
}
function clearCanvas() {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.clearRect(0, 0, c.width, c.height);
}
function reDraw() {
unCheckItems();
clearCanvas();
drawAxes();
drawBars();
}
function clear() {
localStorage.clear();
reDraw();
}
init(); // "onload"
#entryArea {
border: 1px solid black;
width: 30%;
border-radius: 100px;
text-align: center;
margin: auto;
}
#myCanvas {
border-radius: 25px;
border: 1px;
}
#submitButton {
border-radius: 15px;
background-color: lightblue;
font-size: 25px;
width: 30%;
}
input {
font-size: 25px;
}
#resetButton {
border-radius: 15px;
background-color: lightblue;
font-size: 25px;
width: 30%;
}
<canvas id="myCanvas" width="500" height="450" style="border:1px solid #000000;"></canvas>
<div id="entryArea">
<p style="font-size: 20px">What is your favorite programming language?</p>
<p><input name="language" type="radio" value="Web Design">Web Design</p>
<p><input name="language" type="radio" value="Java">Java</p>
<p><input name="language" type="radio" value="Python">Python</p>
<p><input name="language" type="radio" value="Other">Other</p>
<button id="submitButton">Submit</button><br><br>
<button id="resetButton">Reset</button>
</div>

HTML5 Canvas stroke not following mouse Y point

I'm writing a drawing app in HTML5 Canvas, which includes a freehand draw with the mouse.
I have a problem whereby the mouse move to draw the stroke is not under the crosshair cursor. The X co-ordinate is fine, but the Y coordinate is offset by a varying amount as the mouse pointer is moved (closer at the top of the page, drifts further away as we closer to the bottom).
It has something to do with the 'header bar' div at the top.
Here is the code.
<style>
#divContainer {
width: 100%;
height: 100%;
}
#divHeader {
position: absolute;
left: 0px;
top: 0px;
right: 0px;
height: 28px;
background-color: #333;
}
#divContentArea {
position: absolute;
left: 0px;
top: 29px;
right: 0px;
bottom: 5px;
}
#divContentCenter {
position: absolute;
top: 0px;
left: 0px;
bottom: 0px;
right:0px;
}
.canvascontainer {
position: relative;
overflow: auto;
width:100%;
height:100%;
}
.canvas {
cursor: crosshair;
width: 100%;
height: 100%;
position:absolute;
left:0px;
top:0px;
z-index: 2;
}
.maincanvas {
cursor: crosshair;
width: 100%;
height: 100%;
position:absolute;
left:0px;
top:0px;
z-index: 1;
}
</style>
<div id="divContainer">
<div id="divHeader">
The Header
</div>
<div id="divContentArea">
<div id="divContentCenter">
<div id='canvascontainer' class='canvascontainer' >
<canvas id="canvas" class='canvas'>
Sorry, your browser does not support a canvas object.
</canvas>
<canvas id="maincanvas" class='maincanvas'>
Sorry, your browser does not support a canvas object.
</canvas>
</div>
</div>
</div>
</div>
<script>
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
const canrect = canvas.getBoundingClientRect();
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var maincanvas = document.getElementById('maincanvas');
var maincontext = maincanvas.getContext('2d');
maincanvas.width = window.innerWidth;
maincanvas.height = window.innerHeight;
var lastPoint;
var startPoint;
var isDrawing = false;
context.lineWidth = 3;
context.lineJoin = context.lineCap = 'round';
context.setLineDash([0, 0]);
context.globalAlpha = 1.0;
function drawGuideLines() {
for ( i = 0; i < canvas.height; i += 20 ) {
context.beginPath();
context.setLineDash([2, 2]);
context.lineWidth = 1;
if ( i % 60 == 0 ) {
context.lineWidth = 2;
}
context.strokeStyle = '#ccc';
context.moveTo(0,i);
context.lineTo(canvas.width,i);
context.stroke();
}
for ( i = 0; i < canvas.width; i += 20 ) {
context.beginPath();
context.setLineDash([2, 2]);
context.lineWidth = 1;
if ( i % 60 == 0 ) {
context.lineWidth = 2;
}
context.strokeStyle = '#ccc';
context.moveTo(i,0);
context.lineTo(i, canvas.height);
context.stroke();
}
}
function getMousePos(e) {
return {
x: e.offsetX - canrect.left,
y: e.offsetY + canrect.top
};
}
function clearPage() {
context.clearRect(0, 0, canvas.width, canvas.height);
}
function copyToMain () {
maincontext.drawImage(canvas, 0, 0);
clearPage();
}
canvas.onmousedown = function(e) {
isDrawing = true;
canvas.addEventListener("mousemove", drawDirectPath, false);
lastPoint = { x: e.clientX, y: e.clientY };
lastPoint = { x: e.offsetX, y: e.offsetY };
// lastPoint = { x: e.offsetX, y: e.PageY };
lastPoint = getMousePos(e);
};
function drawDirectPath(e) {
if (!isDrawing) return;
context.beginPath();
context.setLineDash([0, 0]);
context.lineWidth = 3;
context.strokeStyle = 'red';
context.fillStyle = 'red';
//show_mouse_info(e, 'GetMousePos:' + getMousePos(e).x + ', ' + getMousePos(e).y);
//show_mouse_info(e, 'boundrect:' + canrect.x + ', ' + canrect.y);
//mx = e.clientX;
//my = e.clientY;
mx = e.offsetX;
my = e.offsetY;
context.moveTo(lastPoint.x, lastPoint.y);
context.lineTo(mx, my);
context.stroke();
lastPoint = { x: mx, y: my };
}
canvas.onmouseup = function() {
isDrawing = false;
copyToMain ();
};
canvas.onmouseleave = function() {
isDrawing = false;
copyToMain ();
};
drawGuideLines();
</script>
I have tried using OffsetX/Y, PageX/Y, clinetX/Y to see if these make a difference but I cannot solve the problem.
The test, click the mouse in the top right or top left and drag/draw down diagonally to the opposite bottom corner to see the effect.
Don't give the canvas a width and height of 100% using CSS.
.canvas {
cursor: crosshair;
position:absolute;
left:0px;
top:0px;
z-index: 2;
}
Couple other things you may want to consider
Always declare variables for (let i =...
Don't make getBoundingClientRect() a const. The reason for this is if you needed to add a resize function you wouldn't be able to change the bounds because the variable holds the original bounds.
You are assigning lastPoint over and over. Not really sure what this is about.
lastPoint = { x: e.clientX, y: e.clientY };
lastPoint = { x: e.offsetX, y: e.offsetY };
// lastPoint = { x: e.offsetX, y: e.PageY };
lastPoint = getMousePos(e);

Zoom the canvas with respect to mouse cordinates

I have a very simple application, on which I draw the image on canvas perfectly. I am translating the context by image.width/2, image.height/2 and set the destination point as -image.width/2, -image.height/2.
function draw() {
window.canvas = document.getElementById('canvas');
window.ctx = canvas.getContext('2d');
window.image = document.createElement("img");
image.onload = function() {
canvas.width = image.width;
canvas.height = image.height;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.translate(image.width/2,image.height/2);
ctx.drawImage(image,-image.width/2,-image.height/2);
};
image.src = 'rec.JPG';
}
This is displaying the image as it supposed to be. So considering this conept that if I want to make the center point of image in center of canvas I should do this as I did above. Now, I want user to click on canvas, I am getting mouse coordinates. Then I want to scale this image and redraw the canvas such that user will see that part of the image in center (zoomed version). The code is as follow:
function zoom(evt) {
var x = getMousePos(canvas, evt).x;
var y = getMousePos(canvas, evt).y;
canvas.width = image.width;
canvas.height = image.height;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.translate(x,y);
ctx.scale(1.5, 1.5);
ctx.drawImage(image,-x,-y);
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
But I am not getting the right results somehow. I want to see the region where user clicked and then I again want to click to zoom out and thats it. I can do a later part easily but having problem with zooming the perfect region. I saw similiar questions on stackoverflow, but they aren't meeting my requirement. This is my html and css:
<style>
.container {
height: 500px;
}
.container .image-container {
height: 500px;
width: 50%;
overflow: auto;
position: absolute;
border: 1px solid;
}
img {
display: none;
}
canvas {
width: 100%;
}
</style>
<body onload="draw()">
<div class="container">
<div class="image-container">
<canvas
id="canvas"
onclick="zoom(event)"
>
</canvas>
</div>
</div>
</body>
P.S: I don't want panning. Just zoom-in and out on clicks. You can play with the snippet.
function draw() {
window.canvas = document.getElementById('canvas');
window.ctx = canvas.getContext('2d');
window.image = document.createElement("img");
window.isZoom = false;
image.onload = function() {
canvas.width = image.width;
canvas.height = image.height;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.translate(image.width/2,image.height/2);
ctx.drawImage(image,-image.width/2,-image.height/2);
};
image.src = 'https://d85ecz8votkqa.cloudfront.net/support/help_center/Print_Payment_Receipt.JPG';
}
function zoom(evt) {
if(!isZoom) {
var x = getMousePos(canvas, evt).x;
var y = getMousePos(canvas, evt).y;
canvas.width = image.width;
canvas.height = image.height;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.translate(x,y);
ctx.scale(2, 2);
ctx.drawImage(image,-x,-y);
canvas.style.cursor = 'zoom-out';
isZoom = true;
} else {
canvas.width = image.width;
canvas.height = image.height;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.translate(image.width/2,image.height/2);
ctx.drawImage(image,-image.width/2,-image.height/2);
isZoom=false;
canvas.style.cursor = 'zoom-in';
}
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
<style>
.container {
height: 500px;
}
.container .image-container {
height: 500px;
width: 50%;
overflow: auto;
position: absolute;
border: 1px solid;
}
img {
display: none;
}
canvas {
width: 100%;
cursor: zoom-in;
}
</style>
<body onload="draw()">
<div class="container">
<div class="image-container">
<canvas
id="canvas"
onclick="zoom(event)"
>
</canvas>
</div>
</div>
</body>
You where really close, just have to mix the scale into your drawing of the image
function draw() {
window.canvas = document.getElementById('canvas');
window.ctx = canvas.getContext('2d');
window.image = document.createElement("img");
window.isZoom = false;
image.onload = function() {
canvas.width = image.width;
canvas.height = image.height;
ctx.drawImage(image, 0,0);
};
image.src = 'https://d85ecz8votkqa.cloudfront.net/support/help_center/Print_Payment_Receipt.JPG';
}
function zoom(evt) {
canvas.width = image.width;
canvas.height = image.height;
ctx.clearRect(0, 0, canvas.width, canvas.height);
var scale = 2
if (!isZoom) {
var pos = getMousePos(canvas, evt);
ctx.scale(scale, scale);
ctx.drawImage(image, -pos.x*scale*scale, -pos.y*scale*scale);
canvas.style.cursor = 'zoom-out';
} else {
ctx.drawImage(image, 0, 0);
canvas.style.cursor = 'zoom-in';
}
isZoom = !isZoom
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
.container {
height: 500px;
}
.container .image-container {
height: 500px;
width: 50%;
overflow: auto;
position: absolute;
border: 1px solid;
}
img {
display: none;
}
canvas {
width: 100%;
cursor: zoom-in;
}
<body onload="draw()">
<div class="container">
<div class="image-container">
<canvas id="canvas" onclick="zoom(event)">
</canvas>
</div>
</div>
</body>
Besides the addition of var scale I did some cleanup to your code:
var x = getMousePos(canvas, evt).x;
var y = getMousePos(canvas, evt).y;
That was kind of a wasteful double call to getMousePos

canvas drawing margin correction

I'm trying some draw techniques I found in this URL:
http://perfectionkills.com/exploring-canvas-drawing-techniques/
I just noticed that the higher level css properties are not applied to the canvas element mouse events. Is there a easy way to fix this?
<head>
<meta charset="utf-8">
<title>Spray Can</title>
<style>
body {
margin: 0;
padding: 0;
}
#container {
border: 1px solid #ccc;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
#canvas {
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function () {
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var isDrawing;
canvas.onmousedown = function(e) {
isDrawing = true;
context.moveTo(e.clientX, e.clientY);
};
canvas.onmousemove = function(e) {
if (isDrawing) {
var k = 4;
var radgrad = context.createRadialGradient(e.clientX, e.clientY, k, e.clientX, e.clientY, k * 2);
radgrad.addColorStop(0, 'rgba(0,0,0,1)');
radgrad.addColorStop(0.5, 'rgba(0,0,0,0.5)');
radgrad.addColorStop(1, 'rgba(0,0,0,0)');
context.fillStyle = radgrad;
context.fillRect(e.clientX - k * 2, e.clientY - k * 2, k * 2 * 2, k * 2 * 2);
}
};
canvas.onmouseup = function() {
isDrawing = false;
};
});
</script>
</head>
<body>
<div id="container">
<canvas id="canvas" width="400" height="400"></canvas>
</div>
</body>
https://jsfiddle.net/crpq8t5q/1/
What you need is to convert your mouse event's coordinates to be relative to the canvas ones.
Since here you don't touch the scale nor rotation this is just a simple canvasX = mouseX - canvas.offsetLeft and canvasY = mouseY - canvas.offsetTop.
These offsetXXX properties are available on the canvas, but you can also use getBoundingClientRect()which will return better results if your css is more complicated (e.g nested elements with different scrollable areas).
But since this offset will change each time you scroll or resize the page, you need to update these values.
Also, it is a very bad idea to create a readialGradient in a mouse event. This event can fire at really high rate, and creating gradients eats memory.
It is then better to create a single gradient, and modify your whole context's matrix so that the gradient be placed at the mouse coordinates :
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var isDrawing;
var k = 4;
// create the gradient only once
var radgrad = context.createRadialGradient(0, 0, k, 0, 0, k * 2);
radgrad.addColorStop(0, 'rgba(0,0,0,1)');
radgrad.addColorStop(0.5, 'rgba(0,0,0,0.5)');
radgrad.addColorStop(1, 'rgba(0,0,0,0)');
// get our canvas margins;
var rect;
function getRect() {
rect = canvas.getBoundingClientRect();
}
canvas.onmousedown = function(e) {
isDrawing = true;
context.moveTo(e.clientX, e.clientY);
};
canvas.onmousemove = function(e) {
if (isDrawing) {
// normalize our mouse event's coordinates
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
// change the canvas matrix coordinates so we draw at mouse positions
context.setTransform(1, 0, 0, 1, x, y)
context.fillStyle = radgrad;
context.fillRect(-k * 2, -k * 2, k * 2 * 2, k * 2 * 2);
}
};
canvas.onmouseup = function() {
isDrawing = false;
};
var debouncing = false;
function resizeHandler() {
debouncing = false;
getRect();
}
window.onscroll = window.onresize = function() {
// debounce the events
if (!debouncing) {
requestAnimationFrame(resizeHandler);
}
debouncing = true;
}
getRect();
body {
margin: 0;
padding: 0;
}
#container {
border: 1px solid #ccc;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
#canvas {}
<div id="container">
<canvas id="canvas" width="400" height="400"></canvas>
</div>

how to add tools to my canvas app

I have a fully working canvas app but its a bit plain at the moment and i would like to add tool, i am very new to java, but still now alot so i will be able to understand most of it, all i want to add is like shapes like rectangle and triangle and squares.
Here is a working demo of it so far.
HTML
<!doctype html>
<html>
<head>
<link rel="shortcut icon" type="image/x-icon" href="SiteIcon.ico">
<title>Canvas</title>
<link rel="stylesheet" href="style.css">
<span style="cursor:crosshair">
</head>
<body>
<div id="toolbar">
<div id="rad">
Radius <span id="radval">10</span>
<div id="decrad" class="radcontrol">-</div>
<div id="incrad" class="radcontrol">+</div>
<font color="white">BACK</font>
<font color="white">CLEAR</font>
</div>
<div id="colors">
. Colour:
<input type="color" name="color1" id="color1" />
<br />
<br />
</div>
<canvas id="canvas" style="display: block;">sorry, your browser does not support our canvas tag.</canvas>
<script src="jQuery.js"></script>
</body>
</html>
CSS
* {
box-sizing: border-box;
-moz-box-sizing: border-box;
font-family: sans-serif;
margin: 0;
user-select:none;
-webkit-user-select:none;
-moz-user-select:none;
-ms-user-select:none;
}
#toolbar {
width: 100%;
height: 50px;
padding: 10px;
position: fixed;
top: 0;
background-color: #2f2f2f;
color: white;
}
.radcontrol {
width: 30px;
height: 30px;
background-color: #4f4f4f;
display: inline-block;
text-align: center;
padding: 5px;
}
#rad {
float: left;
}
#colors {
}
.swatch {
width: 30px;
height: 30px;
border-radius: 15px;
box-shadow: inset 0px 1px 0px rgba(255, 255, 255, 0.5), 0px 2px 2px rgba(0, 0, 0, 0.5);
display: inline-block;
margin-left: 10px;
}
.swatch.active {
border: 2px solid white;
box-shadow: inset 0px 1px 2px rgba(0, 0, 0, 0.5);
}
#back {
width: 60px;
height: 5px;
padding: 5%;
background-color: white;
}
JavaScript
function processData(c1, c2) {
var cv1 = document.getElementById(c1).value;
var cv2 = document.getElementById(c2).value;
alert(cv1 + "\n" + cv2);
}
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var radius = 10;
var dragging = false;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
context.lineWidth = radius * 2;
var putPoint = function (e) {
if (dragging) {
var bounds = canvas.getBoundingClientRect();
var mouseX = e.clientX + bounds.left;
var mouseY = e.clientY - bounds.top;
var mouseX = e.clientX + bounds.left - 20;
context.lineTo(mouseX, mouseY)
context.strokeStyle = document.getElementById('color1').value;
context.stroke();
context.beginPath();
context.arc(mouseX, mouseY, radius, 0, Math.PI * 2);
context.fillStyle = document.getElementById('color1').value;
context.fill();
context.beginPath();
context.moveTo(mouseX, mouseY);
}
}
var engage = function (e) {
dragging = true;
putPoint(e);
}
var disengage = function () {
dragging = false;
context.beginPath();
}
canvas.addEventListener('mousedown', engage);
canvas.addEventListener('mousemove', putPoint);
canvas.addEventListener('mouseup', disengage);
var setRadius = function (newRadius) {
if (newRadius < minRad) newRadius = minRad;
else if (newRadius > maxRad) newRadius = maxRad;
radius = newRadius;
context.lineWidth = radius * 2;
radSpan.innerHTML = radius;
}
var minRad = 1,
maxRad = 100,
defaultRad = 20,
interval = 5,
radSpan = document.getElementById('radval'),
decRad = document.getElementById('decrad'),
incRad = document.getElementById('incrad');
decRad.addEventListener('click', function () {
setRadius(radius - interval);
});
incRad.addEventListener('click', function () {
setRadius(radius + interval);
});
setRadius(defaultRad);
The first step would be extending the engage (mousedown) function because the way you have it now only works for a single functionality (putPoint). Then, you need to set a different event handler for mousemove for the same reason.
Your app needs to have states, like free drawing, rectangle, triangle, etc. The engage function first needs to read the current state (you can store the state in a variable), so if it's free drawing, it would work just as it works now, but if it is, for example, rectangle, then it would call a different function that you use for drawing rectangles.
You can go different ways about the implementation: you can simply click on the starting coordinates and click another time on the ending coordinates. Or you can start drawing the rectangle on mousedown and finish drawing it on mouseup. Both approaches still use 2 parameters: starting coordinates and ending coordinates.
With triangles it's a bit different since you obviously can't use the second approach from above (holding the mouse down while creating it) because the triangle requires three parameters (three dots).
UPDATE
And here is a super simple example of rectangle drawing using the mouse-down method I described above.
http://jsfiddle.net/egpr99k9/45/
This is the function that does the trick - it's call both on mouseup and mousedown events:
var rectData = {};
function drawRect(e, start) {
var bounds = canvas.getBoundingClientRect();
var mouseX = e.clientX + bounds.left - 20;
var mouseY = e.clientY - bounds.top;
if (start) {
rectData.start = {
x: mouseX,
y: mouseY
}
}
else {
if (rectData.start) {
context.beginPath();
context.rect(
rectData.start.x,
rectData.start.y,
mouseX - rectData.start.x,
mouseY - rectData.start.y
);
context.fillStyle = document.getElementById('color1').value;
context.fill();
}
rectData.start = {};
}
}
The next step here would be creating a live preview of the rectangle you're currently drawing (currently you won't see anything until you actually finish drawing it by releasing the mouse button). The best way to do it would be to use a temporary canvas on top of the main one, so that you can avoid problems with keeping the content "below" the rectangle you're currently drawing because you'd need to clear the canvas and refresh the preview on each mouse move while the button is down.
And once you release the mouse button, you would simply draw the contents of the temporary canvas to the main one, and delete or remove the temporary canvas.
I hope this is enough to get you started.
UPDATE
I went ahead and wrote you a simple example with live preview on a temporary canvas: http://jsfiddle.net/egpr99k9/46/
function processData(c1, c2) {
var cv1 = document.getElementById(c1).value;
var cv2 = document.getElementById(c2).value;
alert(cv1 + "\n" + cv2);
}
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var radius = 10;
var dragging = false;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
context.lineWidth = radius * 2;
var putPoint = function (e) {
if (dragging) {
var bounds = canvas.getBoundingClientRect();
var mouseX = e.clientX + bounds.left;
var mouseY = e.clientY - bounds.top;
var mouseX = e.clientX + bounds.left - 20;
context.lineTo(mouseX, mouseY)
context.strokeStyle = document.getElementById('color1').value;
context.stroke();
context.beginPath();
context.arc(mouseX, mouseY, radius, 0, Math.PI * 2);
context.fillStyle = document.getElementById('color1').value;
context.fill();
context.beginPath();
context.moveTo(mouseX, mouseY);
}
}
var tmpCanvas = document.getElementById('tmp');
tmpCanvas.width = canvas.width;
tmpCanvas.height = canvas.height;
tmpCanvas.id = 'tmp';
document.body.appendChild(tmpCanvas);
var tmpCtx = tmpCanvas.getContext('2d');
var rectData = {};
function drawRect(e, start, move) {
var bounds = canvas.getBoundingClientRect();
var mouseX = e.clientX + bounds.left - 20;
var mouseY = e.clientY - bounds.top;
if (start) {
rectData.start = {
x: mouseX,
y: mouseY
}
} else if (move) {
tmpCanvas.width = tmpCanvas.width;
tmpCtx.beginPath();
tmpCtx.rect(
rectData.start.x,
rectData.start.y,
mouseX - rectData.start.x,
mouseY - rectData.start.y);
tmpCtx.fillStyle = document.getElementById('color1').value;
tmpCtx.fill();
} else {
if (rectData.start) {
tmpCanvas.width = tmpCanvas.width;
context.beginPath();
context.rect(
rectData.start.x,
rectData.start.y,
mouseX - rectData.start.x,
mouseY - rectData.start.y);
context.fillStyle = document.getElementById('color1').value;
context.fill();
}
rectData.start = {};
}
}
var engage = function (e) {
dragging = true;
//putPoint(e);
drawRect(e, true);
}
var disengage = function (e) {
dragging = false;
context.beginPath();
drawRect(e, false);
}
canvas.addEventListener('mousedown', engage);
canvas.addEventListener('mousemove', function(e){
drawRect(e, false, true);
});
canvas.addEventListener('mouseup', disengage);
var setRadius = function (newRadius) {
if (newRadius < minRad) newRadius = minRad;
else if (newRadius > maxRad) newRadius = maxRad;
radius = newRadius;
context.lineWidth = radius * 2;
radSpan.innerHTML = radius;
}
var minRad = 1,
maxRad = 100,
defaultRad = 20,
interval = 5,
radSpan = document.getElementById('radval'),
decRad = document.getElementById('decrad'),
incRad = document.getElementById('incrad');
decRad.addEventListener('click', function () {
setRadius(radius - interval);
});
incRad.addEventListener('click', function () {
setRadius(radius + interval);
});
setRadius(defaultRad);
* {
box-sizing: border-box;
-moz-box-sizing: border-box;
font-family: sans-serif;
margin: 0;
user-select:none;
-webkit-user-select:none;
-moz-user-select:none;
-ms-user-select:none;
}
#toolbar {
width: 100%;
height: 50px;
padding: 10px;
position: fixed;
top: 0;
background-color: #2f2f2f;
color: white;
}
.radcontrol {
width: 30px;
height: 30px;
background-color: #4f4f4f;
display: inline-block;
text-align: center;
padding: 5px;
}
#rad {
float: left;
}
#colors {
}
.swatch {
width: 30px;
height: 30px;
border-radius: 15px;
box-shadow: inset 0px 1px 0px rgba(255, 255, 255, 0.5), 0px 2px 2px rgba(0, 0, 0, 0.5);
display: inline-block;
margin-left: 10px;
}
.swatch.active {
border: 2px solid white;
box-shadow: inset 0px 1px 2px rgba(0, 0, 0, 0.5);
}
#back {
width: 60px;
height: 5px;
padding: 5%;
background-color: white;
}
canvas {
cursor: crosshair;
display: block;
}
#tmp {
pointer-events: none;
display: block; position: absolute;left: 10px;top: 50px;
opacity: 0.5;
}
<div id="toolbar">
<div id="rad">Radius <span id="radval">10</span>
<div id="decrad" class="radcontrol">-</div>
<div id="incrad" class="radcontrol">+</div> <font color="white">BACK</font>
<font color="white">CLEAR</font>
</div>
<div id="colors">. Colour:
<input type="color" name="color1" id="color1" />
<br />
<br />
</div>
<canvas id="canvas">sorry, your browser does not support our canvas tag.</canvas>
<canvas id="tmp">sorry, your browser does not support our canvas tag.</canvas>
</div>
Look, I rewrote your code with jQuery and Fabric.
function getRandInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var canvas = new fabric.Canvas('canvas', {
isDrawingMode: true
});
var w = canvas.width;
var h = canvas.height;
$('#tri').click(function () {
var triangle = new fabric.Triangle({
width: getRandInt(10, w / 2),
height: getRandInt(10, h / 2),
fill: $('#color1').val(),
left: getRandInt(10, w / 2),
top: getRandInt(10, h / 2)
});
canvas.add(triangle);
});
$("#rect").click(function () {
var rect = new fabric.Rect({
width: getRandInt(10, w / 2),
height: getRandInt(10, h / 2),
fill: $('#color1').val(),
left: getRandInt(10, w / 2),
top: getRandInt(10, h / 2)
});
canvas.add(rect);
});
$("#circle").click(function () {
var circle = new fabric.Circle({
radius: getRandInt(10, w / 4),
fill: $('#color1').val(),
left: getRandInt(10, w / 2),
top: getRandInt(10, h / 2)
});
canvas.add(circle);
});
$('#radius').change(function () {
canvas.freeDrawingBrush.width = parseInt($(this).val(), 10) || 1;
});
$('#color1').change(function () {
canvas.freeDrawingBrush.color = $(this).val();
});
$('#edit').click(function () {
canvas.isDrawingMode = !canvas.isDrawingMode;
$("#draw").prop('disabled', false);
$(this).prop('disabled', true);
});
$('#draw').click(function () {
canvas.isDrawingMode = !canvas.isDrawingMode;
$("#edit").prop('disabled', false);
$(this).prop('disabled', true);
});
$('#c').click(function () {
canvas.clear();
});
Result JSFiddle!

Categories

Resources