Drawing tool selection on key press in Javascript - javascript

I am making a javascript canvas drawing program and I want the user to be able to choose between the pencil tool, circle tool and clearing screen on keypress.
In the following code the variable key_press holds the users selection. The whole program does not work when I don't assign anything to the variable, so I made the default value = pencil(). But now I cant use anything but pencil.
I post only relevant code here, but it is full in this jsfiddle
var canvas, context, tool, key_press;
// check for key press
window.addEventListener('keydown',function(event){
key_press= String.fromCharCode(event.keyCode);
},false);
function init () {
canvas = document.getElementById('canvas');
context = canvas.getContext('2d');
//check user selection
if (key_press === "1") {
tool = new Pencil();
} else if (key_press === "2") {
tool = new Circle();
} else if (key_press === "3") {
canvas.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
tool = new Pencil();
} else tool = new Pencil(); //this part is probably causing the problem, but clear screen (selection 3) does not work either so it could be something different.
//onmouse calls and end of init()
}
//basically just two functions after init for the tools
function Pencil () {
//...
}
function Circle() {
//...
}
//calling main function init()
init();
Obviously the way I handle user input is bad. Could you point me in the right direction as to what I am doing wrong?

Your distance calculation wasn't working because you left off a , 2 in the second Math.pow call.
Your jsfiddle wasn't working because the default on a new fiddle is to run in window.load, but you then added another load event listener that never fired.
I've changed the code to reflect these changes (and make the context.arc call use the distance rather than z) and it appears to work:
http://jsfiddle.net/rWV5h/1/

Related

Cursor as PNG image?

I am trying to make my cursor be a PNG image that I have already preloaded in an art game I am designing on P5.js.
I have tried so many things, but it still won't work!
Can someone please let me know where to put the cursor function as well as what to put inside the parentheses? Thanks so much!
function preload() {
uImg = loadImage('assets/ufo.png');
rImg = loadImage('assets/asteroid.png');
bImg3 = loadImage('assets/bimg3.jpg');
}
function setup() {
createCanvas(1200, 600);
mode = 3; //level 3 in game
noCursor();
}
// END OF SET UP
function draw() {
levelThree();
}
// END OF DRAW
function levelThree() {
clear();
if (mode == 3) {
lost = false;
score = 0;
background(bImg3);
cursor(uImg,mouseX,mouseY);
}
}
I think simply using image() instead of cursor() will do what you want. I don't know why, but I think that when using cursor() you can't input a p5.Image, you have to put a string of a URL to an image that exists on the internet.
Also, when using cursor(), the other two parameters should be between 0 and 31. They describe where the "active point" of the cursor is, relative to where the actual mouse point is.
You could just do something like this:
let img
function preload(){
img = loadImage('cursor.png')
}
function setup() {
createCanvas(400, 400);
imageMode(CENTER)
noCursor()
}
function draw() {
background(20);
image(img,mouseX,mouseY)
}
And you should put the option stuff in setup() so the imageMode() and fill() and idk rectMode()... in setup, though what ever you're going to draw multiple times in draw() and you should load images in preload, cause javascript doesn't reallly care if images are loaded in or not and callback functions are meh, preload is good in my opinion. I also don't think that you really need the assets in assets/image.png
And also why exactly do you have mouseX and mouseY in the cursor() at the end of your code snippet???
hope this is actually answering the right question...

HTML5 Canvas: Setting context on resize

I have a project using HTML5 Canvas (createjs) and I've had issues with spikes on text strokes, meaning I have to set the miterlimit of the 2d context. However, the parent (which I have no control over) scales the canvas when the window is resized, which obviously resets the canvas context.
Now, I want to avoid putting an onresize event inside the client - my first thought is just to use the createjs Ticker thus:
createjs.Ticker.addEventListener("tick", handleTick);
function handleTick(event) {
var ctx = canvas.getContext('2d');
ctx.miterLimit = 2;
}
Though this seems a little wasteful, is there a more efficient way of doing this, without using DOM events?
Your approach might work, but its definitely a hack, since you can't expect that context properties will be maintained, or that they won't be applied in the wrong place.
If you do want to patch the display list to update the context, you can use the "drawstart" event, which fires before the display list is drawn:
stage.on("drawstart", function(e) {
var ctx = stage.canvas.getContext("2d");
ctx.miterLimit = 2;
});
However if you want a better approach that is instance-specific, you can extend the Text class to append any context properties you want. Here is a quick example where miterLimit is stored and applied any time the text is drawn. In this example, you can create multiple instances and set different miter limits on them. Note that you might want to also support other properties such as lineJoin.
http://jsfiddle.net/cr4hmgqp/2/
(function() {
"use strict"
function MiterText(text, font, color, miterLimit) {
this.Text_constructor(text,font,color);
this.miterLimit = miterLimit;
};
var p = createjs.extend(MiterText, createjs.Text);
p.draw = function(ctx, ignoreCache) {
ctx.miterLimit = this.miterLimit;
if (this.Text_draw(ctx, ignoreCache)) { return true; }
return true;
};
p.clone = function() {
return this._cloneProps(new MiterText(this.text, this.font, this.color, this.miterLimit));
};
createjs.MiterText = createjs.promote(MiterText, "Text");
}());
Note that this issue should hopefully be fixed in the next version of EaselJS. Here is the tracked issue: https://github.com/CreateJS/EaselJS/issues/781
Cheers.

OL3 - How to know if drawing or interaction is started

In OpenLayer 3 I create a Draw interaction using the 'draw-feature' sample code they have on their website.
The only difference is that I supply my own condition function to the Draw constructor.
I would like to know if there is a way to determine within the condition function if the interaction/drawing has started?
Basically my goal is to change the behavior slightly so drawing a box is initiated with a CTRL-click rather than a click. But ending the drawing can be done with a simple click. So my approach would be something like this (in TypeScript)
var condition = (e: ol.MapBrowserEvent): boolean => {
return (myDraw.isStarted() ? true : e.originalEvent['ctrlKey']);
}
As far as I can see there's nothing like an isStarted() method in OL Draw class. If I had access to internal members I would resolve it by checking the length of myDraw.sketchCoords_ (haven't checked this but if 0 the drawing is not started yet). But I don't want to rely on private members, furthermore I'm using the minified version of OL where members names are transformed.
Try something like this:
var start_drawing = false;
function drawCondition(evt){
var ctrl = ol.events.condition.platformModifierKeyOnly(evt);
// this should be ol.events.condition.click
// but for some reason always returns false
var click = evt.type == 'pointerdown';
// to finish draw with click
if(start_drawing) return click;
// start drawing only with Ctrl + click
return ctrl && click;
}
// draw is a reference to ol.interaction.Draw
draw.on('drawstart', function(evt){
start_drawing = true;
});
draw.on('drawend', function(evt){
start_drawing = false;
});

Unresponsive charCode statements

I am currently watching a bunch of introductory videos about using the canvas tag in HTML5 to create simple 2d games.
As I was following the video code - precisely - there was an error somewhere along the way. I tried to draw a rectangle in the canvas that would respond to the navigation buttons and move accordingly.
Here is the main game code:
function game() {
update();
render();
}
function update() {
//This is the code that I think is causing an error
if(keys[38]) player.y--;
if(keys[40]) player.y++;
if(keys[37]) player.x--;
if(keys[39]) player.x++;
}
function render() {
context.fillRect(player.x, player.y, player.width, player.height);
}
setInterval(function(){
game();
}, 1000/30);
The site runs perfectly fine when I load it, but it doesn't respond to the user clicks. Thanks for any help in advance.
Below is the keys array that adds an indexed value every-time a the navigation keys are pressed:
var keys = [];
window.addEventListener('keydown', function(e){
keys[e.keycode] = true;
}, false);
window.addEventListener('keyup', function(e){
delete keys[e.keycode]
}, false);
It seems like you're using the .keycode property, all lower case, in your event handlers. That property doesn't exist. Instead, try using the .keyCode property, with a capital C.
Using a nonexistent property returns undefined, so that would always execute keys[undefined] = true and keys[undefined] = false.
It doesnt respond to mouse interactions because you just assigned key codes. i assume you can control the rectangle with the arrow keys?
which framework are you using?

How to stop a function from returning unless a key press is made

I'm attempting to create a simple program that sequentially displays a number of letters where each letter is presented alone (see the figure below). I'm also attempting to make the program work in such a way that the user needs to press a key on the keyboard before the next letter is presented.
I'm trying to do this by encapsulating each letter presentation within a single, almost self-contained function (singleTrial). My problem is is that I can't figure-out how to stop the singleTrial function from returning unless a key press is made (see the waitForResponse function). In this case, when the function returns, the next function call to SingleTrial is executed, making it so that only the second letter is displayed (because the first letter gets presented and then cleared in almost an instant). What am I doing wrong here? How can I make it so that the singleTrial function does not return unless a key press is made?
My ultimate goal is to make it so that I can iterate though a letter list, presenting each letter sequentially:
letterList.forEach(function(stim) {
singleTrial(stim);
});
Thanks in advance!
Here is my code:
var responseMade;
function onResponse() {
responseMade = true;
}
function singleTrial(stim, context, canvas) {
responseMade = false;
context.clearRect(0, 0, canvas.width, canvas.height);
window.removeEventListener('keydown', onResponse, false);
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillText(stim, 100, 10);
window.addEventListener('keydown', onResponse, false);
function waitForResponse() {
if (responseMade == false) {
setInterval(waitForResponse, 1000);
}
}
waitForResponse();
}
function main() {
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d');
singleTrial("A", context, canvas);
singleTrial("B", context, canvas);
}
main()
</script>
I can't figure-out how to stop the singleTrial function from returning unless a key press is made
You can't (currently; ES6's "generators" will offer a way to do it, but it still wouldn't be the best way here). Instead, what you do is hook up an event handler for when a key is pressed, and generate the next letter when that event occurs. This is a key concept in web (and other) programming: Rather than your program working in some set loop, you wait for and respond to events that occur.
For instance, remove waitForResponse from singleTrial, and change main:
function main() {
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
nextLetter = "A".charCodeAt(0);
document.addEventListener("keydown", function() {
singleTrial(String.fromCharCode(nextLetter), context, canvas);
++nextLetter;
}, false);
}
(You'll need to handle the addEventListener / attachEvent thing if you need to support old IE. From the canvas, I'm thinking you don't.)

Categories

Resources