I have a Sharepoint page in which i want to show a hierarchical diagram with boxes.According to my requirement those boxes should work as links to other sharepoint pages in the same site.
Since sharepoint's default designer tools doesn't support designing such diagrams, I created a page with html5 canvas and the element i wanted inside that.
Inside the canvas i created few boxes and lines to connect them.And i added texts inside the boxes.Then i used a mouse listener to check whether the mouse pointer hovers over a box and if so changed the pointer icon and the link to be redirected to.
I added the canvas tag inside the sharepoint page by "Edit Source" and i added the javascript part using 'Embed Code'
Now the code works perfectly in IE and Firefox.
In chrome although the boxes,lines and text are drawn according to the coordinates i gave in the code but But when i hover the mouse over them it gives different coordinates for mouse listener in different browser sizes.So the mouse pointer doesn't change at correct locations ie: over the boxes.
This doesn't happen in firefox or IE. They changes the mouse pointer when it comes over the boxes and links to the pages perfectly.
Why does it change when i use chrome?
And why does it only affect to the mouse listener coordinates.
This is the code i used.(I have removed the repetitive parts which draws other boxes)
Same in jsfiddle
<canvas id="myCanvas" height="500" width="960" style="border: 1px solid;"><img src="" alt=""/> </canvas>
<script>
var canvas = document.getElementById("myCanvas");
var ctx;
var rNBDX = 50; var rNBDY = 150;
var rectWidth = 200;
var rectHeight = 100;
var cornerRadius = 20;
var linkNBD="https://google.com";
var textNBD1 ="Google";
var linkHeight=20;
var linkNum = 0;
function draw(){
canvas = document.getElementById("myCanvas");
if(canvas.getContext){
ctx=canvas.getContext("2d");
//Drawing Lines
ctx.lineWidth = 3;
ctx.strokeStyle = '#000000';
ctx.moveTo(380, 100);
ctx.lineTo(380, 125);
ctx.stroke();
//Drawing Rectangles
ctx.fillStyle="#0b61d0";
ctx.strokeStyle="#0b61d0";
ctx.lineJoin = "round";
ctx.lineWidth = cornerRadius;
ctx.strokeRect(rNBDX+(cornerRadius/2), rNBDY+(cornerRadius/2), rectWidth-cornerRadius, rectHeight-cornerRadius);
ctx.fillRect(rNBDX+(cornerRadius/2), rNBDY+(cornerRadius/2), rectWidth-cornerRadius, rectHeight-cornerRadius);
//Drawing the Texts
ctx.font='24px Segoe UI Light';
ctx.fillStyle = "#FFFFFF";
ctx.fillText(textNBD1,(rNBDX+rectWidth/2)-(ctx.measureText(textNBD1).width)/2,rNBDY+rectHeight/2);
//Add mouse listeners
canvas.addEventListener("mousemove", on_mousemove, false);
canvas.addEventListener("click", on_click, false);
}
}
function on_mousemove (ev) {
var x, y;
if (ev.layerX || ev.layerX == 0) {
x = ev.layerX;
y = ev.layerY;
}
x-=canvas.offsetLeft;
y-=canvas.offsetTop;
if(x>=rNBDX && x <= (rNBDX + rectWidth) && y>=rNBDY && y<= (rNBDY+rectHeight)){
document.body.style.cursor = "pointer";
linkNum=1;
}
else{
document.body.style.cursor = "";
}
}
function on_click(e) {
switch (linkNum)
{
case 1:
window.location = linkNBD;
break;
}
}
draw();
</script>
Try adjusting the mouse coordinates like this:
function on_mousemove (ev) {
var x, y,
rect = canvas.getBoundingClientRect();
x = ev.clientX - rect.left + 1;
y = ev.clientY - rect.top + 1;
...
You will have to add (as in the example) the width of the left/top border though as getBoundingClientRect does not include those (you can calculate this dynamically using getComputedStyle and getPropertyValue of that for the borders).
Related
I have a bunch of canvas elements in my html file like so:
<canvas id="one"></canvas>
<canvas id="two"></canvas>
I'm using the arrow keys to move an object around #one, but I want to have that object "appear" in #two when it hits a point on #one, e.g. x=150 and y=55.
I tried using the jQuery focus() method when that coordinate was triggered, but the object stayed in #one. Any suggestions?
To make a canvas element focus-able, and therefor able to capture key-strokes, you simply add a tabIndex attribute to the element:
Now you can TAB between the elements and bind event-listeners to the canvas element directly.
Inside the handler you simply draw to the canvas you want based on whatever criteria you require.
Example
var canvases = document.querySelectorAll("canvas"),
i = 0;
while(canvas = canvases[i++]) {
canvas.width = 200;
canvas.tabIndex = 0;
canvas.addEventListener("keyup", process);
}
function process(e) {
var ctx = this.getContext("2d");
ctx.clearRect(0, 0, 200, 150);
ctx.fillText("KEY HERE: " + e.keyCode, 10, 10);
}
canvas {border:1px solid #999;margin:0 2px 2px 0; display:inline-block}
<canvas></canvas>
<canvas></canvas>
<canvas></canvas>
<canvas></canvas>
<canvas></canvas>
<canvas></canvas>
Rather than changing focus when that coordinate is hit, I think you need to change the <canvas> element (and associated context) you're drawing to, e.g.:
var theCanvas = document.getElementById("one");
var context = theCanvas.getContext("2d");
... your canvas drawing code here ...
if (posX < 150 && posY < 55) {
//clear the top canvas
context.clearRect(0, 0, theCanvas.width, theCanvas.height);
// switch to the second canvas
theCanvas = document.getElementById("two");
context = theCanvas.getContext("2d");
}
Here's a fiddle that borrows code from rectangleworld.com. Drag the circle into the upper left corner of the top canvas, and it should appear in the lower canvas.
JSFiddle
There is no such thing as focus on a canvas for this purpose.
Your both canvases need to listen for keypresses, while your code needs to decide what to draw on which canvas.
var canvas1 = document.getElementById("one");
var context1 = canvas1.getContext("2d");
var canvas2 = document.getElementById("two");
var context2 = canvas2.getContext("2d");
canvas1.width = canvas1.height = canvas2.width = canvas2.height = 50;
var obj = {x: 5, y: 5, w: 5};
function draw() {
canvas1.width = canvas2.width = canvas2.width;
context1.beginPath();
context1.rect(obj.x, obj.y, obj.w, obj.w);
context1.fillStyle = 'green';
context1.fill();
context2.beginPath();
context2.rect(obj.x - canvas1.width, obj.y, obj.w, obj.w);
context2.fillStyle = 'blue';
context2.fill();
}
window.addEventListener('keydown', function() {
if(++obj.x > canvas1.width + canvas2.width) obj.x = 5;
draw();
});
draw();
canvas {border: 1px solid black; margin: 10px;}
<canvas id="one"></canvas>
<canvas id="two"></canvas>
<p>Click inside this window to get focus and then <br>press any key to move the object to the right</p>
Of course, this can be optimized not to redraw both canvases on each tick, but you get the idea.
I have three arrys:
clickX = [],
clickY = [],
clickDrag = [];
this is what happens when you click down:
$('#canvasCursor').mousedown(function (e) {
console.log('down');
mouseX = e.pageX - this.offsetLeft;
mouseY = e.pageY - this.offsetTop;
paint = true;
addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
redraw();
});
here it adds the clicks to the array and draws.:
function redraw() {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); // Clears the canvas
ctx.strokeStyle = "green";
ctx.lineJoin = "round";
ctx.lineWidth = brushSize*2;
for (var i = 0; i < clickX.length; i++) {
ctx.beginPath();
if (clickDrag[i] && i) {
ctx.moveTo(clickX[i - 1], clickY[i - 1]);
} else {
ctx.moveTo(clickX[i] - 1, clickY[i]);
}
ctx.lineTo(clickX[i], clickY[i]);
ctx.closePath();
ctx.stroke();
}
}
I am trying to get rid of the array way of doing it now because when I change the var brushSize dynamically using a slider it redraws the entire picture in the new size not the size they had at the time. I don't know how to save the size of any specific object in the array and then paint them seperate.
I don't mind if I cant implement the undo function that this way gives me as long as I can fix the change of brush size. Here you can see what I am rambling on about! http://www.taffatech.com/Paint.html
-also it seems slower and im guessing its because its drawing from an array
Do not store painting to array
It slows down drawing critically. Just draw the latest line without clearing canvas. That way lineWeight changes does not affect to before drawings. So remove ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); and for loop. You also might want to change context styles (lineWidth etc.) only when changes occur, not every time you run redraw() function.
Undo support
Making different canvas for every mouse down session and drawing them together you can easily make undo feature. By pressing undo it simply splices latest canvas out of canvases array. Google to learn more about drawing to temporary canvas.
EDIT: Sorry, fixed some typos
Edit 2: And again. It's a bit difficult to test.
There's no reason to redraw each of the points each time. You could modify your listener to do this:
var prevMouseX=null,prevMouseY=null;
$('#canvasCursor').mousedown(function (e) {
paint = true;
console.log('down');
//get current mouse coords
mouseX = e.pageX - this.offsetLeft;
mouseY = e.pageY - this.offsetTop;
if (prevMouseX==null) {
//store these coordinates for next time if they haven't been defined yet
prevMouseX = mouseX;
prevMouseY = mouseY;
}
});
$('#canvasCursor').mousemove(function (e) {
//get current mouse coords
mouseX = e.pageX - this.offsetLeft;
mouseY = e.pageY - this.offsetTop;
if (prevMouseX==null) {
//store these coordinates for next time if they haven't been defined yet
prevMouseX = mouseX;
prevMouseY = mouseY;
}
if (paint) {drawline(mouseX,mouseY,prevMouseX,prevMouseY);}
//store these coordinates for next time
prevMouseX = mouseX;
prevMouseY = mouseY;
});
Where the function drawLine is defined as:
function drawline(x1,y1,x2,y2) {
ctx.strokeStyle = "green";
ctx.lineJoin = "round";
ctx.lineWidth = brushSize*2;
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.closePath();
ctx.stroke();
}
Here’s how to use canvas to draw like Paint
If you want an undo feature, your best option is to record all line segments drawn by the user.
This is done with a point array that contains all points (polylines) drawn by the user.
To track the brush size and brush color, you need to include this info in your array also.
So each element of the the array will have this info about each line segment:
x: the ending x coordinate of this line segment
y: the ending y coordinate
size: the brush size (lineWidth)
color: the brush color (strokeStyle)
mode: “begin” indicates the beginning of a new line, “end” indicates the end of this line.
How does it work?
When the user is drag-drawing a line segment, each mousemove event is extending the current segment with context.lineTo and context.stroke.
When the user selects a new BrushSize or BrushColor, context.beginPath starts context.beginPath.
When the user holds down the Undo button, the last point in the last line segment is popped off the point array. Then all the surviving line segments are redrawn. The undo button fires every 1/10th of a second when held down.
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/AEYYq/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<!--[if lt IE 9]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var lastX;
var lastY;
var mouseX;
var mouseY;
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var isMouseDown=false;
var brushSize=20;
var brushColor="#ff0000";
var points=[];
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
ctx.beginPath();
if(ctx.lineWidth!=brushSize){ctx.lineWidth=brushSize;}
if(ctx.strokeStyle!=brushColor){ctx.strokeStyle=brushColor;}
ctx.moveTo(mouseX,mouseY);
points.push({x:mouseX,y:mouseY,size:brushSize,color:brushColor,mode:"begin"});
lastX=mouseX;
lastY=mouseY;
isMouseDown=true;
}
function handleMouseUp(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mouseup stuff here
isMouseDown=false;
points.push({x:mouseX,y:mouseY,size:brushSize,color:brushColor,mode:"end"});
}
function handleMouseMove(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here
if(isMouseDown){
ctx.lineTo(mouseX,mouseY);
ctx.stroke();
lastX=mouseX;
lastY=mouseY;
// command pattern stuff
points.push({x:mouseX,y:mouseY,size:brushSize,color:brushColor,mode:"draw"});
}
}
function redrawAll(){
if(points.length==0){return;}
ctx.clearRect(0,0,canvas.width,canvas.height);
for(var i=0;i<points.length;i++){
var pt=points[i];
var begin=false;
if(ctx.lineWidth!=pt.size){
ctx.lineWidth=pt.size;
begin=true;
}
if(ctx.strokeStyle!=pt.color){
ctx.strokeStyle=pt.color;
begin=true;
}
if(pt.mode=="begin" || begin){
ctx.beginPath();
ctx.moveTo(pt.x,pt.y);
}
ctx.lineTo(pt.x,pt.y);
if(pt.mode=="end" || (i==points.length-1)){
ctx.stroke();
}
}
ctx.stroke();
}
function undoLast(){
points.pop();
redrawAll();
}
ctx.lineJoin = "round";
ctx.fillStyle=brushColor;
ctx.lineWidth=brushSize;
$("#brush5").click(function(){ brushSize=5; });
$("#brush10").click(function(){ brushSize=10; });
// Important! Brush colors must be defined in 6-digit hex format only
$("#brushRed").click(function(){ brushColor="#ff0000"; });
$("#brushBlue").click(function(){ brushColor="#0000ff"; });
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
// hold down the undo button to erase the last line segment
var interval;
$("#undo").mousedown(function() {
interval = setInterval(undoLast, 100);
}).mouseup(function() {
clearInterval(interval);
});
}); // end $(function(){});
</script>
</head>
<body>
<p>Drag to draw. Use buttons to change lineWidth/color</p>
<canvas id="canvas" width=300 height=300></canvas><br>
<button id="undo">Hold this button down to Undo</button><br><br>
<button id="brush5">5px Brush</button>
<button id="brush10">10px Brush</button>
<button id="brushRed">Red Brush</button>
<button id="brushBlue">Blue Brush</button>
</body>
</html>
I took this question and used it to create a full featured "coloring book" solution, which I posted on Github. https://github.com/collinph/jl-coloringbook
It handles all of the mouse issues + undo and other things that we were discussing + a lot of sizing issues that could come up. It does store the coordinates in an array and is not slow as some suggested it would be-- not in Chrome or Safari anyway.
I have a webpage with an HTML5 canvas which I'm using to display a number of images as well as four 'description boxes' on the canvas.
The intention is that users will be able to drag and drop the images to their matching description boxes, however, I'm having a bit of trouble getting the dragging and dropping working.
The function I've written to add the drag and drop functionality is based on the tutorial I found at this page: http://simonsarris.com/blog/510-making-html5-canvas-useful
Obviously, I altered the code slightly, as I don't want to do everything suggested in the tutorial, and because I'm drawing images (not shapes) to the canvas. However, when viewing my page in the browser although all of the images are displayed on the canvas, the drag and drop functionality has not been added along with the new JavaScript file I've written based on that tutorial.
I'm not getting any errors in the Firebug console, and the page is displaying exactly as it was before I added the new JS function.
Can anyone spot what I'm missing?
My HTML is:
<!DOCTYPE html>
<html>
<head>
<script src = "kinetic.js" type = "text/javascript"></script>
<title>Home</title>
<script src = "drawLevelOneElements.js" type = "text/javascript"></script>
<script src = "layers&analytics.js" type = "text/javascript"></script>
<script src = "startGameDrawGameElementsDrawStartButton.js" type = "text/javascript"></script>
<script src = "interaction.js" type = "text/javascript"></script>
<script src = "dragAndDrop.js" type = "text/javascript"></script>
</head>
<body onLoad="startGame()">
<section hidden>
<img id="StartButton" src="StartButton.png" alt="Start Button" width="179" height="180" href="javascript:drawLevelOneElements();"/>
</section>
<h1>Home</h1>
<p>The purpose of this website is to teach users the basic principles of running a business by playing the game below. <br /><br /></p>
<canvas id="gameCanvas" width="1000" height="500" style="border:1px solid">
Your browser does not support the canvas element.
</canvas>
<br /><br />
<p>Use this paragraph to enter text that provides the user with instructions for how to play the game. <br />
Update the instructions so that they're appropriate to whatever level the user is currently playing.</p>
<script src = "layers&analytics.js" type = "text/javascript"></script>
<script src = "startGameDrawGameElementsDrawStartButton.js" type = "text/javascript"></script>
<script src = "variables&preloadingImages.js" type = "text/javascript"></script>
<script src = "drawLevelOneElements.js" type = "text/javascript"></script>
<script src = "interaction.js" type = "text/javascript"></script>-->
<script src = "variables&preloadingImages.js" type = "text/javascript"></script>
</body>
All of the script tags at the bottom of the page (except the last one) are actually commented out in my file, I just had to remove the comment to get it to display in a code block on here.
The javaScript I've added for the drag and drop functionality is:
function canvasState(myGameCanvas){
var bounding_box = myGameCanvas.getBoundingClientRect();
var mouseX = (mouse_event.clientX-bounding_box.left) * (myGameCanvas.width/bouding_box.width);
var mouseY = (mouse_event.clientY-bounding_box.top) * (myGameCanvas.height/bounding_box.height);
var pixels = context.getImageData(mouseX, mouseY, 1, 1);
this.valid = false; /*When set to true, the canvas will redraw everything */
this.allImagesArray; /*This is the array holding all of the images to be drawn */
this.dragging = false; /*Keep track of when the current selected object is being dragged */
this.selection = null;
this.dragOffX = 0; /*See mousedown and mousemove events for explanation */
this.dragOffY = 0;
this.interval = 30; /*This variable will be used to determine how often the draw method is called. */
/*Save a reference to the canvasState so that I'm still using this particular canvasState. */
var myState = this;
/*This stops double clicking on the canvas selecting text on the canvas */
myGameCanvas.addEventListener('selectstart', function(e) {e.preventDefault(); return false; }, false);
/*Up, down and move are for dragging */
myGameCanvas.addEventListener('mousedown', function(e){
var mouse = myState.getMouse(e);
var mX = mouse.x;
var mY = mouse.y;
var allImages = myState.allImagesArray;
var NoOfImages = allImages.length;
for (var i = 1-1; i >= 0; i--){
if(allImages[i].contains(mX, mY)){
var mySelection = allImages[i];
/*Keep track of where in the object was clicked, so that it can be
moved smoothly (see mousemove) */
myState.dragOffX = mX - mySelection.x;
myState.dragOffY = mY - mySelection.y;
myState.dragging = true;
myState.selection = mySelection;
myState.valid = false;
return;
}
}
/*If the code hasn't returned, it means that nothing has been selected.
If there was an object selected, then deselect it. */
if (myState.selection){
myState.selection = null;
myState.valid = false; /*Need to clear the old selection border */
}
}, true);
/*This event checks to see if the dragging flag has been set to true. If it has, it gets the
current mouse position and moves the selected object to that position, remembering the offset
where it was selected. If the dragging flag is false, the event does nothing. */
myGameCanvas.addEventListener('mousemove', function(e){
if(myState.dragging){
var mouse = myState.getMouse(e);
/*I don't want to drag the object by its top left corner, I want to drag from where the
object was clicked. That's why I saved the offset and use it here. */
myState.selection.x = mouse.x - myState.dragOffX;
myState.selection.y = mouse.y - myState.dragOffY;
myState.valid = false; /*Something's dragging, so I must redraw */
}
}, true);
/*All the mouseup event has to do is update the canvas state so that it is no longer dragging.
So, once the mouse button is lifted, the mousemove event should be back to doing nothing. */
myGameCanvas.addEventListener('mouseup', function(e){
myState.dragging = false;
}, true);
setInterval(function(){ myState.draw(); }, myState.interval);
canvasState.prototype.draw = function(){
/*If the state is invalid,redraw and validate. */
if (!this.valid){
var context = this.context;
var images = this.images;
this.clear();
/*Redraw the game elements here */
drawLevelOneElements();
}
}
}
Code for dragAndDrop.js:
function canvasState(myGameCanvas){
var bounding_box = myGameCanvas.getBoundingClientRect();
var mouseX = (mouse_event.clientX-bounding_box.left) * (myGameCanvas.width/bouding_box.width);
var mouseY = (mouse_event.clientY-bounding_box.top) * (myGameCanvas.height/bounding_box.height);
var pixels = context.getImageData(mouseX, mouseY, 1, 1);
this.valid = false; /*When set to true, the canvas will redraw everything */
this.allImagesArray; /*This is the array holding all of the images to be drawn */
this.dragging = false; /*Keep track of when the current selected object is being dragged */
this.selection = null;
this.dragOffX = 0; /*See mousedown and mousemove events for explanation */
this.dragOffY = 0;
this.interval = 30; /*This variable will be used to determine how often the draw method is called. */
/*Save a reference to the canvasState so that I'm still using this particular canvasState. */
var myState = this;
/*This stops double clicking on the canvas selecting text on the canvas */
myGameCanvas.addEventListener('selectstart', function(e) {e.preventDefault(); return false; }, false);
console.log("Event Listener 'selectstart' added to canvas.");
/*Up, down and move are for dragging */
myGameCanvas.addEventListener('mousedown', function(e){
console.log("Event Listener 'mousedown' added to canvas");
var mouse = myState.getMouse(e);
var mX = mouse.x;
var mY = mouse.y;
var allImages = myState.allImagesArray;
var NoOfImages = allImages.length;
for (var i = 1-1; i >= 0; i--){
if(allImages[i].contains(mX, mY)){
var mySelection = allImages[i];
/*Keep track of where in the object was clicked, so that it can be
moved smoothly (see mousemove) */
myState.dragOffX = mX - mySelection.x;
myState.dragOffY = mY - mySelection.y;
myState.dragging = true;
myState.selection = mySelection;
myState.valid = false;
return;
}
}
/*If the code hasn't returned, it means that nothing has been selected.
If there was an object selected, then deselect it. */
if (myState.selection){
myState.selection = null;
myState.valid = false; /*Need to clear the old selection border */
}
}, true);
/*This event checks to see if the dragging flag has been set to true. If it has, it gets the
current mouse position and moves the selected object to that position, remembering the offset
where it was selected. If the dragging flag is false, the event does nothing. */
myGameCanvas.addEventListener('mousemove', function(e){
console.log("Event listener 'mousemove' added to canvas.");
if(myState.dragging){
var mouse = myState.getMouse(e);
/*I don't want to drag the object by its top left corner, I want to drag from where the
object was clicked. That's why I saved the offset and use it here. */
myState.selection.x = mouse.x - myState.dragOffX;
myState.selection.y = mouse.y - myState.dragOffY;
myState.valid = false; /*Something's dragging, so I must redraw */
}
}, true);
/*All the mouseup event has to do is update the canvas state so that it is no longer dragging.
So, once the mouse button is lifted, the mousemove event should be back to doing nothing. */
myGameCanvas.addEventListener('mouseup', function(e){
console.log("Event listener 'mouseup' added to canvas.");
myState.dragging = false;
}, true);
setInterval(function(){ myState.draw(); }, myState.interval);
canvasState.prototype.draw = function(){
/*If the state is invalid,redraw and validate. */
if (!this.valid){
var context = this.context;
var images = this.images;
this.clear();
/*Redraw the game elements here */
drawLevelOneElements();
}
}
}
Code for drawLevelOneElements.js: (this now includes the call to canvasState(); )
function drawLevelOneElements(){
/*First, clear the canvas */
context.clearRect(0, 0, myGameCanvas.width, myGameCanvas.height);
/*This line clears all of the elements that were previously drawn on the canvas. */
/*Then redraw the game elements */
drawGameElements();
/*Call the function to enable drag and drop */
canvasState(document.getElementById('gameCanvas'));
/*Create the four description areas, and place them near the bottom of the canvas */
/*Create boxes with rounded corners for the description areas */
CanvasRenderingContext2D.prototype.drawDescriptionArea = function(x, y, width, height, radius, stroke){
if(typeof stroke == "undefined" ){
stroke = true;
}
if(typeof radius === "undefined"){
radius = 5;
}
this.beginPath();
this.moveTo(x + radius, y);
this.lineTo(x + width - radius, y);
this.quadraticCurveTo(x + width, y, x + width, y + radius);
this.lineTo(x + width, y + height - radius);
this.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
this.lineTo(x + radius, y + height);
this.quadraticCurveTo(x, y + height, x, y + height - radius);
this.lineTo(x, y + radius);
this.quadraticCurveTo(x, y, x + radius, y);
this.closePath();
if(stroke){
context.stroke();
}
}
context.drawDescriptionArea(70, 400, 120, 70);
context.font = '25pt Calibri';
context.strokeText('Asset', 90, 440);
context.drawDescriptionArea(300, 400, 120, 70);
context.strokeText('Liability', 310, 440);
context.drawDescriptionArea(540, 400, 120, 70);
context.strokeText('Income', 550, 440);
context.drawDescriptionArea(750, 400, 180, 70);
context.strokeText('Expenditure', 760, 440);
/*Now draw the images to the canvas */
/*First, create variables for the x & y coordinates of the image that will be drawn.
the x & y coordinates should hold random numbers, so that the images will be
drawn in random locations on the canvas.*/
var imageX = Math.floor(Math.random()*100);
var imageY = Math.floor(Math.random()*100);
/*Create a 'table' of positions that the images will be drawn to */
var imagePositionsX = [20, 80, 140, 200, 260, 320, 380, 440, 500, 560];
var imagePositionsY = [20, 60, 100, 140, 180, 220, 260, 300, 340, 380];
/*Draw all images from assetsImageArray */
/*Use a while loop to loop through the array, get each item and draw it. */
var arrayIteration = 0;
console.log('All Images Array length: ' + allImagesArray.length); /*Display the length of the array in the console, to check it's holding the correct number of images. */
while(arrayIteration < allImagesArray.length){
var randomPositionX = Math.floor(Math.random()*10);
var randomPositionY = Math.floor(Math.random()*10);
context.drawImage(allImagesArray[arrayIteration], imageX, imageY, 50, 50);
console.log(arrayIteration); /*Display the current array position that's being drawn */
arrayIteration = arrayIteration+1;
/*Now try changing the values of imageX & imageY so that the next image is drawn to a
different location*/
imageX = imagePositionsX[randomPositionX]; /* imageX+(Math.floor(Math.random()*100)); */
imageY = imagePositionsY[randomPositionY]; /* imageY+(Math.floor(Math.random()*100)); */
}
}
In conclusion to the comments, I can answer you this: Somewhere within your code, you have to call the canvasState() function, it's not enough just to define it. Where you must call it largely depends on when you need it's functionality. By example, if you want to set up the drag and drop functionality when the page loads, you have an event handler for the body's load event:
<body onLoad="startGame()">
Somewhere in the startGame() function's code, you would call canvasState(). If you you want it when StartButton is pressed, you should call it from within the drawLevelOneElements() function. Since you were following a tutorial, the order in which things happen might matter, so there might be a particular place where you need to call your function.
One more advice. Because you seem to be learning, start with the basics and work your way up with a deep understanding of what you learned up to that point, don't just follow random tutorials.
I am trying to draw over a canvas by clicking and dragging the mouse. My problem is that, apart from the fact that the line has a very poor quality (I want a more pronounced border) it only respects the mouse position when this is at 0,0. As I move the mouse to the lower corner, the line increments its distance from it as much as when I am in the middle of the canvas, the line is already out of it.
I have my code at: http://jsfiddle.net/ajTkP/12/
I will also post it here:
var MDown = false;
var Color = 'blue';
var Canvas = document.getElementById('canvas');
var Context = Canvas.getContext('2d');
Canvas.onselectstart = function() { return false; };
Canvas.unselectable = "on";
Canvas.style.MozUserSelect = "none";
Canvas.onmousedown = function(e) {
MDown = true;
Context.strokeStyle = Color;
Context.lineWidth = 3;
Context.lineCap = 'round';
Context.beginPath();
Context.moveTo(e.pageX - Position(Canvas).left, e.pageY - 5);
}
Canvas.onmouseup = function() { MDown = false; };
Canvas.onmousemove = function(e) {
if (MDown) {
Context.lineTo(e.pageX - Position(Canvas).left, e.pageY - 5);
Context.stroke();
}
}
function Position(el) {
var position = {left: 0, top: 0};
if (el) {
if (!isNaN(el.offsetLeft) && !isNaN(el.offsetTop)) {
position.left += el.offsetLeft;
position.top += el.offsetTop;
}
}
return position;
}
Thanks for your help!
You need to set an explicit width and height on the canvas. The default dimensions of a canvas are a width of 300 and a height of 150 (see the spec here). By setting the width and height via CSS you are just stretching the canvas.
Either do:
<canvas id="canvas" width="300" height="200"></canvas>
or set the width/height via JavaScript:
canvas.width = 300;
canvas.height = 200;
See the updated jsfiddle: http://jsfiddle.net/ajTkP/13/
It looks like jimr beat me to the punch about the canvas height and width.
The poor quality of the line though is due to how you're drawing the line. You'll notice that you're calling stroke() on every onmousemove event. Keep in mind that it's keeping track of the path of the line from when you beginPath() to when you closePath(), so you're basically stroking the same line multiple times (every time your mouse moves). This is what's giving you the aliased (blocky-looking) lines, instead of the smooth anti-aliased lines you're expecting.
I am trying to build a floorplan model in Canvas. Currently I have a grid image in my canvas and have the ability for users to draw lines by clicking and dragging their mouse. But, this doesn't guarantee straight lines.
Is there anyway I can provide input fields in the html page for users to input the beginning and ending x and y coordinates of the lines, and have it updated in my canvas code? I'm a beginner when it comes to JS/AJAX, so any remedial help is appreciated :)
Right now, this is the section that dictates how the lines get drawn:
$(document).ready(function() {
var canvas = document.getElementById('canvas');
var context = canvas.getContext("2d");
if(canvas.getContext) {
$('#canvas').mousedown(function (evt) {
var offset = $('#canvas').offset();
context.beginPath();
context.moveTo(20, 20);
});
$(document).mousemove(function(evt) {
var offset = $('#canvas').offset();
context.lineTo(evt.pageX - offset.left, evt.pageY - offset.top);
context.stroke();
}).mouseup(function() {
$(document).unbind('mousemove');
$(document).unbind('mouseup');
});
$('#clearcanvas').click(function () {
context.clearRect(0, 0, 600, 580);
});
}
});
I suspect it involves modifying following code:
context.lineTo(evt.pageX - offset.left, evt.pageY - offset.top);
Very simply you could use 4 input fields and take the value of each when a button is pressed
button.addEventListener('click', function() {
ctx.beginPath();
ctx.moveTo(x1.value, y1.value);
ctx.lineTo(x2.value, y2.value);
ctx.stroke();
}, false);
http://jsfiddle.net/TeGGx/