Can we assign class to shapes in canvas in html5 - javascript

Can we assign a class to shapes in canvas?
I am trying to build a path using lines and want to give a collection of lines a class so as to change their properties specifically.
My code is somewhat like:
ctx.beginPath();
ctx.moveTo(200,450);
ctx.lineTo(200,400);
ctx.lineTo(400,400);
ctx.lineTo(400,450);
ctx.stroke();
I want to assign to a class to all these lines specifically.How is it done?
Any suggestions ?

Canvas is a bitmap board in which you can draw on with no way to track shapes
However...
You can always use this clicking function to interact with your square manually:
var canvas = ...
var ctx = ...
canvas.addEventListener("mousedown", getPosition, false)
function getPosition(event) {
x = event.x;
y = event.y;
x -= canvas.offsetLeft;
y -= canvas.offsetTop;
// Now put code to describe specifically where to click
if (x < 400 && x > 200 && y < 450 && y > 400) {
// Now if you click on your square, you can write code here to interact
}
}
You are also always able to make an array of the squares coordinates and keep track of it that way.
I hope this helped :)

Related

Rendering lots of sprites with hexagon shape from image using pixijs

I'm trying to create a hexagonal map with the list of terrain types.
At the moment I have the map that is drawn from the sprites that uses as a base texture the graphics with the shape of a hexagon.
I need to put a different images on them, but can't find a solution how to do it.
Here's the demo of what I have: https://codepen.io/cuddlemeister/pen/rPvwZw
I've tryied to do it in this way:
const texture = PIXI.Texture.fromImage(img);
const s = new PIXI.Sprite(texture);
s.mask = graphics;
But I get only one hexagon that mask being applyied to. And if I put graphics in a loop, I get performance issues.
Maybe I should just cut the images to get hexagons and simply draw sprites made from these images?
Here's what I want to achieve: http://i.imgur.com/xXLTK.jpg
Basically, I need to replace that white hexagons with some textures. How can I get this?
how about that:
https://jsfiddle.net/vxt5eqk4/
for each tile you use a clipmask
var scale = 8;
for (y = 0; y < 10; y++) {
for (x = 0; x < 10; x++) {
var offsetx = (y%2)*5 + x*10 - 6;
var offsety = y * 9 -3;
ctx.save();
ctx.beginPath();
ctx.moveTo(scale*(offsetx+5),scale*(offsety));
ctx.lineTo(scale*(offsetx+10),scale*(offsety+3));
ctx.lineTo(scale*(offsetx+10),scale*(offsety+9));
ctx.lineTo(scale*(offsetx+5),scale*(offsety+12));
ctx.lineTo(scale*offsetx,scale*(offsety+9));
ctx.lineTo(scale*offsetx,scale*(offsety+3));
ctx.closePath();
ctx.clip();
if((y%2 !== 0 || x%2 !== 0) && (y%2 === 0 || x%2 === 0)){
ctx.drawImage(img, scale*offsetx, scale*offsety, 10*scale, 12*scale);
}else{
ctx.drawImage(img2, scale*offsetx, scale*offsety, 10*scale, 12*scale);
}
ctx.restore();
}
a 10x12 grid seemed fine to me to draw a hexagon
the fiddle just shows a basic method to draw hexagonal tiles, the if part should be replaced by getting the proper image for the tile in the tilemap, should you use one

how to make objects inside canvas clickable for popups?

i am making a webgl application i want to know is there any way of making objects(3D models made using blender) inside canvas clickable. So that when i click on them a pop up comes containing data.
I know (and have used) two major approaches.
The first one is to allocate a separate framebuffer and render interactive object to it with different colours. Then, upon a mouse event, you read a pixel corresponding to mouse position and find an object corresponding to the colour just read. For exapmle, it may look somewhat like this.
Textured and shaded scene:
Rendered for hit testing:
This approach is interesting due to it's simplicity. But it has some performance challenges and major ones among them are rendering the scene twice and reading pixel data back (its slow and synchronous). The first one was easy: just keep a dirty flag for the framebuffer and redraw it only upon a event and only if the flag is set (then of course reset it). The second one I've tackled by reading and caching from the framebuffer big chunks of pixels:
getPixel: function (x, y) {
var screenSize = this._screen.getCssSize();
x = x * HIT_TEST_BUFFER_SIZE[0] / screenSize[0] | 0;
y = y * HIT_TEST_BUFFER_SIZE[1] / screenSize[1] | 0;
var rx = x >> PIXEL_CACHE_BUCKET_IDX_SHIFT,
ry = y >> PIXEL_CACHE_BUCKET_IDX_SHIFT,
pixelCache = this._pixelCache,
bucket = pixelCache[[rx, ry]];
if (!bucket) {
this._framebuffer.bind();
bucket = pixelCache[[rx, ry]] = new Uint8Array(
4 * PIXEL_CACHE_BUCKET_SIZE[0] * PIXEL_CACHE_BUCKET_SIZE[1]
);
var gl = this._gl;
gl.readPixels(
rx << PIXEL_CACHE_BUCKET_IDX_SHIFT,
ry << PIXEL_CACHE_BUCKET_IDX_SHIFT,
PIXEL_CACHE_BUCKET_SIZE[0],
PIXEL_CACHE_BUCKET_SIZE[1],
gl.RGBA,
gl.UNSIGNED_BYTE,
bucket
);
this._framebuffer.unbind();
}
var bucketOffset = 4 * (
(y - ry * PIXEL_CACHE_BUCKET_SIZE[1]) * PIXEL_CACHE_BUCKET_SIZE[0] +
x - rx * PIXEL_CACHE_BUCKET_SIZE[0]
);
return bucket.subarray(bucketOffset, bucketOffset + 3);
}
The second major approach would be casting a ray to the scene. You take mouse position, construct a ray with it and cast it from a camera position into a scene to find which object it intersects with. That object would be the one mouse cursor pointing to. There is actually a decent implementation of that approach in Three.js, you can use it or take it as a reference to implement your own algorithm. The main challenge with that approach would be algorithmic complexity of searching an object the ray intersects with. It can be tackled with spacial indices built upon you scene.
Canvas is a simple graphics API. It draws pixels very well and nothing more. There are ways to 'fake' event handlers via mouse positions, but that takes more work. Basically you will register the location of mouse click, than match that up with the position of your 3D models to see if you have a match. You will not be able to attach event handlers directly to the 3d blender objects in canvas. In Scalable Vector Graphics (SVG) that would work fine. Just not in canvas.
function handleMouseDown(e) {
// tell the browser we'll handle this event
e.preventDefault();
e.stopPropagation();
// save the mouse position
// in case this becomes a drag operation
lastX = parseInt(e.clientX - offsetX);
lastY = parseInt(e.clientY - offsetY);
// hit all existing FrameControlPt of your blender objects
var hit = -1;
for (var i = 0; i < FrameControlPt.length; i++) {
var location = FrameControlPt[i];
var dx = lastX - location.x;
var dy = lastY - location.y;
if (dx * dx + dy * dy < stdRadius * stdRadius) {
hit = i;
}
}
// hit all existing buttons in the canvas
for (var i = 0; i < btn.length; i++) {
if ((lastX < (btn[i].x + btn[i].width)) &&
(lastX > btn[i].x) &&
(lastY < (btn[i].y + btn[i].height)) &&
(lastY > btn[i].y)) {
console.log("Button #" + (i + 1) + " has been clicked!!");
// execute button function
btn[i].action(); // execute a custom function
}
}
// if hit then set the isDown flag to start a drag
if (hit < 0) {
drawAll();
} else {
draggingCircle = FrameControlPt[hit];
isDown = true;
}
}
Obviously you'd have to handleMouseUp(event).. in this example, I was allowing the users to drag and drop elements within the canvas. You'd have to adjust your events to match your intended usage.
Code extract from this sample.

drag and drop is not working properly processing.js

What I am trying to do is to make the white square to move around the canvas when the mouse is pressed with the mouse locations but it is not working. I know that I am missing something and ask you to help me. Here is my code:
Object o;
int[][] back =new int[3][3];
int pad = 10, bs=100; //len=pad*(back.length+1)+bs*back.length; za dinamichno resaizvane na ekrana
boolean drag = false;
void setup() {
size(400, 400);
noStroke();
o = new Object();
}
void draw() {
rectt(0, 0, width, height, color(100));
for (int row=0; row<back.length; row++)
for (int coll=0; coll<back[row].length; coll++) {
float x = pad+(pad+bs)*coll;
float y = pad+(pad+bs)*row;
rectt(x, y, bs, bs, color(150));
if (mouseX >=x && mouseX<=x+width/x*coll+bs
&& mouseY>=y && mouseY<=y+height/y*row+bs) {
rectt(x, y, bs, bs, color(255, 0, 0));
}
}
o.show();
//o.over();
}
void rectt(float x, float y, float w, float h, color c) {
fill(c);
rect(x, y, w, h);
}
void mousePressed() {
o.drag();
}
and the class is here:
class Object {
float size = 50;
float x;
float y;
// boolean d = false;
Object() {
x = width -60;
y = height -60;
}
void show() {
fill(255);
rect(x, y, size, size);
}
void drag() {
if ( mouseX >= x && mouseX <= x+size && mouseY <= y+size && mouseY >= y && mousePressed ) {
x = mouseX;
y = mouseY;
}
}
}
In the future, please tell us exactly what your code does, and exactly what you mean when you say it isn't working.
But let's run through your code and figure out what's going on.
First off, it's a pretty bad idea to name your class Object. It probably won't actually hurt anything, especially using Processing.js, but better safe than sorry. So I'm going to rename it to Rectangle.
After that, your main problem comes from the fact that you have two sets of x and y coordinates. The first come from your loop:
float x = pad+(pad+bs)*coll;
float y = pad+(pad+bs)*row;
You use this first set of coordinates to draw your rectangles. But then you have a second set of coordinates inside your Rectangle class:
x = width -60;
y = height -60;
You use this second set in your dragging logic, but then you never use them for drawing your rectangles. More generally, you never seem to use the show() function at all. Where do you expect that rectangle to show up?
Also, you only ever instantiate one Rectangle instance. The rectangles you're drawing in the for loop don't have anything to do with the Rectangle that you've created.
So to fix your problems, you need to do a few things.
Step 1: Create one instance of Rectangle for each rectangle you want to draw to the screen. In other words, you need to create an ArrayList that holds 9 Rectangle instances, not one.
Put this at the top of your sketch:
ArrayList<Rectangle> rectangles = new ArrayList<Rectangle>();
You never use your back variable, so you can get rid of it.
Put this inside your setup() function:
for (int row=0; row<back.length; row++) {
for (int coll=0; coll<back[row].length; coll++) {
float x = pad+(pad+bs)*coll;
float y = pad+(pad+bs)*row;
Rectangle rectangle = new Rectangle(x, y);
rectangles.add(rectangle);
}
}
This code loops through the coordinates and creates an instance of Rectangle at that position, and then adds it to the ArrayList. You'll also have to add the parameters to the Rectangle constructor.
Step 2: You can then shorten your draw() function to simply loop over the Rectangle instances in the ArrayList and draw them:
void draw() {
background(100);
for (Rectangle r : rectangles) {
r.show();
}
}
Step 3: Modify your show() function to include your logic for coloring the Rectangle based on the mouse position:
void show() {
if (mouseX >=x && mouseX<=x+size && mouseY>=y && mouseY<=y+size) {
//mouse is inside this Rectangle
rectt(x, y, size, size, color(255, 0, 0));
} else {
rectt(x, y, size, size, color(150));
}
}
See how each Rectangle knows how to draw itself based on its position and whether the mouse is inside it. All of our logic is inside this class instead of being split into two places.
Step 4: You can then add the dragging logic inside that if statement. If the cursor is inside the Rectangle and the mouse is being pressed, then you know the user is dragging that Rectangle:
//mouse is inside this Rectangle
if (mousePressed) {
x = mouseX - size/2;
y = mouseY - size/2;
}
Please note that I did this in regular Processing, not Processing.js, so you might have to make a few small adjustments like using mouseIsPressed instead of mousePressed. But the basic steps are the same: you need to move your logic inside your Rectangle class, and then you need to use the variables inside that class to draw each rectangle.
If you get stuck on a specific step then please post another question with your updated code and a description of exactly what you expect your code to do, what it does instead, and how those two things are different. Good luck.
You can find the answered in here: https://processing.org/examples/mousefunctions.html
But I will remember you that you can't use mouse event in the Object.
mouse-click-on-object

Skew a line on canvas using JavaScript

I am drawing lines on a canvas. The user can select a particular line and be able to skew that line. By skew, I mean they can drag one end point of the line to a desired point on the same x-axis. How can I do this using JavaScript and HTML5 canvas?
The general way to draw a line is this:
ctx.moveTo(line.startX, line.startY);
ctx.lineTo(line.endX, line.endY);
ctx.stroke();
and then you can add EventListeners and check to see if the mouse is near the line...
window.addEventListener("mousemove", function(e)
{
mouse.x = e.layerX || e.offsetX;
mouse.y = e.layerY || e.offsetY;
// check to see if the mouse is near the line(s) here...
// you can change to x/y and start/end
// example:
if (mouse.x <= line.startX + 5 || mouse.x >= line.startX - 5)
{
// mouse is within 5px of first x
}
});

HTML5 canvas character jump

I try to make an animation of character by reading this tutorial:
http://mrbool.com/html5-canvas-moving-a-character-with-sprites/26239 .
It's quite ease to make the character go left ('go right' is already done). But how to make the character jump (with animation)?
I was thinking about something like this:
case 38:
if (y + dy > HEIGHT){
y += dy
}
break;
...but it just move character up (without animation). Can someone help me? Some code example will be useful.
You get the jumping behavior like this (using the same code on the tutorial)
JSFiddle
var canvas;// the canvas element which will draw on
var ctx;// the "context" of the canvas that will be used (2D or 3D)
var dx = 50;// the rate of change (speed) horizontal object
var x = 30;// horizontal position of the object (with initial value)
var y = 150;// vertical position of the object (with initial value)
var limit = 10; //jump limit
var jump_y = y;
var WIDTH = 1000;// width of the rectangular area
var HEIGHT = 340;// height of the rectangular area
var tile1 = new Image ();// Image to be loaded and drawn on canvas
var posicao = 0;// display the current position of the character
var NUM_POSICOES = 6;// Number of images that make up the movement
var goingDown = false;
var jumping;
function KeyDown(evt){
switch (evt.keyCode) {
case 39: /* Arrow to the right */
if (x + dx < WIDTH){
x += dx;
posicao++;
if(posicao == NUM_POSICOES)
posicao = 1;
Update();
}
break;
case 38:
jumping = setInterval(Jump, 100);
}
}
function Draw() {
ctx.font="20px Georgia";
ctx.beginPath();
ctx.fillStyle = "red";
ctx.beginPath();
ctx.rect(x, y, 10, 10);
ctx.closePath();
ctx.fill();
console.log(posicao);
}
function LimparTela() {
ctx.fillStyle = "rgb(233,233,233)";
ctx.beginPath();
ctx.rect(0, 0, WIDTH, HEIGHT);
ctx.closePath();
ctx.fill();
}
function Update() {
LimparTela();
Draw();
}
var Jump = function(){
if(y > limit && !goingDown){
y-=10;
console.log('jumping: ' + y);
} else{
goingDown = true;
y +=10;
if(y > jump_y){
clearInterval(jumping);
goingDown = false;
}
}
}
function Start() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
return setInterval(Update, 100);
}
window.addEventListener('keydown', KeyDown);
Start();
There's no one right answer to this question, and unless you find a game-design library, there's no simple one, either. Your problem is that you're moving the character instantaneously in response to input, but a jump requires movement over time. You'll have to either find a moving sprites library - I don't have one in particular to recommend, but I'm sure Google has several - or set up something yourself that runs every so many milliseconds and updates the character's position and some sort of velocity variable.
Edit: Looking at that tutorial, the simplest solution that comes to mind is to put your animation code inside of Update(), like so:
function Update() {
LimparTela();
Animate();
Draw();
}
Inside of Animate(), you should keep track of the character's height and vertical momentum. If the momentum is positive, increase the y position a little, otherwise decrease it a little. Either way, reduce momentum a bit. Add something to keep the character from going through the floor, and have the up key set the character's momentum to be positive if he's on the floor.
Note that this is an incredibly bare-bones solution, but for a basic tutorial it'll do the job.

Categories