I am trying to make my own chess analysis board to use when teaching chess. I currently have the board, pieces that I can drag and drop, as well as a method for clearing the board and setting up different board positions. I can also click on squares to highlight them.
I want to be able to draw arrows from one square to another to show lines of attack and influence but have no idea how to accomplish this. My board is made up of <div> tags. A short example is below (pseudo-code and actual code for brevity).
// a couple of CSS styles to define the width, height, and color of the squares
CSS Style Class "dark square"
CSS Style Class "light square"
//my board is made up of <div> tags
<div id="board">
<div id="a1" class="lightsquare"></div>
<div id="a2" class="darksquare"></div>
<div id="a3" class="lightsquare"></div>
//second rank
<div id="b1" class="darksquare"></div>
<div id="b2" class="lightsquare"></div>
<div id="b3" class="darksquare"></div>
//third rank
<div id="c1" class="lightsquare"></div>
<div id="c2" class="darksquare"></div>
<div id="c3" class="lightsquare"></div>
</div>
I can place pieces on the board, move them around, take other pieces, clear the board, set up unique positions, and highlight individual squares just fine, but would also like to be able to have the user click, drag, and draw arrows live on the board while still being able to manipulate the pieces on the board.
I looked at using the tag but based on my reading and research, it doesn't seem like the <canvas> tag was designed to do what I am looking for.
Does anyone have any ideas on how to do this in JavaScript? I have not learned to use JQuery yet, and would prefer to avoid using JQuery as I don't want to have to download an extra file or necessarily be on the internet to use this program.
So after a month of tinkering I have finally found a solution. As much effort as I put into using < div > tags and images to solve this problem, I could never get the arrow to position itself correctly when rotated. I therefore went back to trying out the < canvas > tag and I did finally find a solution that works.
function drawArrow(fromx, fromy, tox, toy){
//variables to be used when creating the arrow
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var headlen = 10;
var angle = Math.atan2(toy-fromy,tox-fromx);
//starting path of the arrow from the start square to the end square and drawing the stroke
ctx.beginPath();
ctx.moveTo(fromx, fromy);
ctx.lineTo(tox, toy);
ctx.strokeStyle = "#cc0000";
ctx.lineWidth = 22;
ctx.stroke();
//starting a new path from the head of the arrow to one of the sides of the point
ctx.beginPath();
ctx.moveTo(tox, toy);
ctx.lineTo(tox-headlen*Math.cos(angle-Math.PI/7),toy-headlen*Math.sin(angle-Math.PI/7));
//path from the side point of the arrow, to the other side point
ctx.lineTo(tox-headlen*Math.cos(angle+Math.PI/7),toy-headlen*Math.sin(angle+Math.PI/7));
//path from the side point back to the tip of the arrow, and then again to the opposite side point
ctx.lineTo(tox, toy);
ctx.lineTo(tox-headlen*Math.cos(angle-Math.PI/7),toy-headlen*Math.sin(angle-Math.PI/7));
//draws the paths created above
ctx.strokeStyle = "#cc0000";
ctx.lineWidth = 22;
ctx.stroke();
ctx.fillStyle = "#cc0000";
ctx.fill();
}
This code will get its start and end coordinates based on the coordinates of the squares at the mouse down and mouse up events. It will then use those coordinates to determine how the arrow should be drawn with the proper rotation.
If your asking how to approach this (fun) problem, I would go about it like this.
Make your arrow with 2 pngs: 2 divs with background images (body
and point of the arrow) inside one container div.
Once you have the code to properly display the arrow, make sure
you know how to append it to the DOM using javascript.
Now try to make the arrow longer and shorter with javascript (by
changing the size of the div containing the body of the arrow)
Once you can do this, it's time for math. Use javascript to
calculate the coordinates of the DIV that is clicked first when
making an arrow, and the DIV that is clicked second. When you have
these coordinates, calculate (using Pythagoras) the length of the
arrow you need, and the amound of rotation you need (this is the
tricky part, but I have done it before so it can certainly be done
if you know some basic math). You are essentially creating triangles on the board.
With the coordinates, length and rotation, you can now place your
arrow on the playing board, adjust the length and the rotation, to
display it just the way you need it. And remember you can also turn the
arrow for say 350 degrees to get to -10 degrees.
This is by no means easy but a lot of fun if you like math, and considering chess, I guess you do.
By the way, this problem can certainly be solved with plain JS but using jQuery would make it easier en less work. You can also use jQuery offline by downloading the library.
To activate and disable pointerEvents I used this code.
//checks to see if the shift key was pressed
function disableImage(ev){
if(ev.shiftKey == 1){
var canvas = document.getElementById("arrowCanvas");
canvas.style.pointerEvents = "all";
}
}
function enableImage(){
var canvas = document.getElementById("arrowCanvas");
canvas.style.pointerEvents = "none";
}
Related
So I have been having this problem with HTML5 canvas and Bootstrap. Esentially, I inserted a canvas inside a Bootstrap template (put it in an element with the class of "jumbotron"). And I want to be able to draw inside that canvas using my mouse. But, my mouse position and the editable-canvas area seem off. I took a snap-shot (hope I uploaded it correctly), the canvas is the pale-yellow thing with the purple border and the actual mouse position is the arrow I drew with blue, the blue dot is where the page sees the mouse position and begins drawing the line. Also, it won`t let me use the whole canvas area, I can only draw in the green square I outlined in the photo...
HTML code:
<div class="jumbotron">
<canvas id="draw" width="800" height="800"></canvas>
</div>
JS code to activate the drawing:
function draw(e) {
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();
[lastX, lastY] = [e.offsetX, e.offsetY];
}
I also have to add that if I get the canvas into a new HTML (without Bootstrap), the code works perfectly (dot/line is following the mouse cursor fine). Also, if I delete the class "jumbotron", the mouse Position will be read correctly. I tried looking into the styles for "jumbotron", digged it up, tried using BoundingRect and others, but I could not figure this one out.
I am new here, so take me slow :) Many thanks in advance!
This happens because mouse position is relative to window. You must make some math to calculate coordinates relative to canvas. Some code for understanding
rect = canvas.getBoundingClientRect()
x = e.offsetX - rect.x
y = e.offsetY - rect.y
Then use x, y to draw something on canvas.
Also you can check my example where I draw with mouse without some additional calculations.
https://codepen.io/Profesor08/pen/aYJWRZ
This application is made with Easeljs, to work in HTML5 canvas.
I want to be able to draw different kinds of arrows on the board. I tried inserting arrows as images and then making them draggable and resizable, but that made these images pretty ugly.
To illustrate:
Field to draw on
Arrows to draw on the field
The functionality should be as follows:
Click on the button
Draw a line
At mouseup event: convert line into corresponding arrow
Arrow should be draggable and resizable
How would I get this result?
You can fairly easily draw arrows using the Graphics API. I spent about 20 mins making this demo:
http://jsfiddle.net/lannymcnie/ukjb1g2g/2/
http://jsfiddle.net/lannymcnie/ukjb1g2g/3/
Code:
var w = startX - endX;
var h = startY - endY;
var lineLength = Math.sqrt(w*w+h*h);
arrow.graphics.clear().setStrokeStyle(3).beginStroke("#000").moveTo(0,0);
// Logic to draw to the end. This is just a straight line
arrow.lineTo(lineLength-arrowHeadSize, 0);
arrow.graphics.beginFill("#000");
arrow.graphics.drawPolyStar(lineLength, 0, arrowHeadSize, 3);
// Rotate
arrow.rotation = Math.atan2(h, w) * 180/Math.PI;
Drawing it straight and rotating it is the easiest way to add effects to the line. The demo I posted draws a sort of sine-wave like one of your examples. There is some more magic in there to make it the right length, etc.
Alright, so I have a good deal of experience with HTML and CSS, and some experience with Javascript (I can write basic functions and have coded in similar languages).
I'm looking to start some visual projects and am specifically interested in getting into particle systems. I have an idea for something similar to Codecademy's name generator here (https://www.codecademy.com/courses/animate-your-name/0/1) where particles are mapped to a word and move if hovered over. It seems as though alphabet.js is what's really behind Codecademy's demo however I can't understand exactly how they mapped the particles to a word, etc.
I've done some basic tutorials just creating rudimentary particles in a canvas but I'm not sure a canvas is the best way to go - demos that utilize one of the many libraries available (such as http://soulwire.github.io/sketch.js/examples/particles.html) don't use a canvas.
So my question is - what is the best way for a beginner/intermediate in Javascript to start with particle systems? Specifically to accomplish the Codecademy name effect or similar? Should I try to use canvas or which library would be best to start with and how would you recommend starting?
The code for this project is achievable for your intermediate JS programmer status.
How the CodeAcademy project works ...
Start by building each letter out of circles and saving each circle's centerpoint in an array. The alphabet.js script holds that array of circle centerpoints.
On mousemove events, test which circles are within a specified radius of the mouse position. Then animate each of those discovered circles radially outward from the mouse position using simple trigonometry.
When the mouse moves again, test which circles are no longer within the specified radius of the current mouse position. Then animate each of those "outside" circles back towards their original positions.
You can also use native html5 canvas without any libraries...
Another approach allowing any text to be "dissolved" and reassembled
Start by drawing the text on the canvas. BTW, this approach will "dissolve" any drawing, not just text.
Use context.getImageData to fetch the opacity value of every pixel on the canvas. Determine which pixels on the canvas contain parts of the text. You can tell if a pixel is part of the text because it will be opaque rather than transparent.
Now do the same procedure that CodeAcademy did with their circles -- but use your pixels:
On mousemove events, test which pixels are within a specified radius of the mouse position. Then animate each of those discovered pixels radially outward from the mouse position using simple trigonometry.
When the mouse moves again, test which pixels are no longer within the specified radius of the current mouse position. Then animate each of those "outside" pixels back towards their original positions.
[Addition: mousemove event to test if circles are within mouse distance]
Note: You probably want to keep an animation frame running that moves circles closer or further from their original positions based on a flag (isInside) for each circle.
function handleMouseMove(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// calc the current mouse position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// test each circle to see if it's inside or outside
// radius of 40px to current mouse position
// circles[] is an array of circle objects shaped like this
// {x:,y:,r:,originalX:,originalY:,isInside:}
var radius=40;
for(var i=0;i<circles.length;i++){
var c=circles[i];
var dx=c.x-mouseX;
var dy=c.y-mouseY;
if(dx*dx+dy*dy<radius*radius){
c.isInside=true;
// move c.x & c.y away from its originalX & originalY
}else{
c.isInside=false;
// if the circle is not already back at it's originalX, originalY
// then move c.x & c.y back towards its originalX, originalY
}
}
}
I am working on web app in which i have to display PDF file using PDF.JS and there are few area where i have to draw a rectangle and user can click on that which take him to details page. Till now i am able to display pdf and while looking at pdf js i found canvas.js in which all text is draw on canvas using
showText: function CanvasGraphics_showText(glyphs) {} function now i am keeping track of all text those text where i have to draw a rectangle but i am facing some problem to accomplish it. showText function calls many times which creating multiple rectangles. I have done following changes in function
if(glyphs.length ==10){
// common case
var bValue=false;
glyphs.forEach(function(value, index, ar){
var str =['d', 'e', 't', 'a','i','l','='];
if(str.indexOf(value.fontChar)>=0){
bValue=true;
}
});
if(bValue){
ctx.beginPath();
ctx.rect(scaledX, 50, 200, 100);
ctx.fillStyle = 'yellow';
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = 'black';
ctx.stroke();
ctx.font = '20pt Calibri';
// textAlign aligns text horizontally relative to placement
ctx.textAlign = 'center';
// textBaseline aligns text vertically relative to font
// style
ctx.textBaseline = 'middle';
ctx.fillStyle = 'blue';
ctx.fillText("Click", 120, 100);
}
}
glyphs is array of objects and i am searching for values define in str.
Can any one please point me into right direction ?
Thanks in Advance.
It's not really possible to do this directly. Canvas is, fundamentally, a bitmap-based graphics engine: the only things it remembers from call to call are the values of the pixels inside it. You can draw text, but once you've done that, the canvas doesn't know that it's text anymore. That's why you can't search for it inside the image.
The quickest and easiest way around this is to keep track of the text somewhere else. #ZachSaucier's comment mentions this possibility. I see that you're concerned about performance, but the alternative would be to implement some kind of OCR algorithm to extract the text from the bitmap. There's no standard way to do that, so you'd have to implement OCR yourself, and it would be much slower than storing the text in a variable.
Another option would be to use SVG instead of Canvas. SVG isn't bitmap-based, so when you put text into an SVG image, the engine can remember that it's text, and you could search within that. However, drawing things in SVG is very different from drawing them in Canvas, so unless you're already using a library that can work with either one, you would have to rewrite your drawing code. That might not be feasible for what you're trying to do.
I am having trouble finding a good method to limit my mouse to be only able to click on a pre existing line in canvas (stroke width of 3)
What I need to know
how to limit mouse so can only click on pre- existing line, add a dot on click
line is drawn with this function
function createLine(startX:Float, startY:Float, endX:Float, endY:Float)
{
surface.beginPath();
surface.moveTo(startX, startY);
surface.lineTo(endX, endY);
surface.closePath();
surface.strokeStyle = '#ffffff';
surface.lineWidth = 2;
surface.stroke();
}
I am working in haxe, but solution in JS is fine
Thanks in advance.
The only way is for you to keep track of what you have drawn and do the collision/mouse over detection on your own.
If you need your canvas to be highly interactive, you should probably be looking at SVG. http://raphaeljs.com/ is a great library for drawing which will use canvas or SVG, whichever is available.