kineticjs show image anchors on click - html

I have a kineticjs canvas with image upload and text input, both functions are working fine but I can't get the image resize anchors to show... I need to get the image resize anchors to show "onClick" of the image.
any help is much appreciated :)
thanks in advance.
here is the js
var stage = new Kinetic.Stage({
container: 'container',
width: 375,
height: 200
});
var layer = new Kinetic.Layer();
//image loader
var imageLoader = document.getElementById('imageLoader');
imageLoader.addEventListener('change', handleImage, false);
function handleImage(e){
var reader = new FileReader();
reader.onload = function(event){
var img = new Image();
img.onload = function(){
layer.add(new Kinetic.Image({
x: 100,
y: 50,
image: img,
width: 200,
height: 130,
draggable: true
}));
text.moveToTop();
stage.draw();
};
console.log(event);
img.src = event.target.result;
};
reader.readAsDataURL(e.target.files[0]);
}
// parameters
var resizerRadius = 3;
var rr = resizerRadius * resizerRadius;
// constant
var pi2 = Math.PI * 2;
function draw(img, withAnchors, withBorders) {
// clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw the image
var view = img.view;
ctx.drawImage(img, 0, 0, img.width, img.height, view.left, view.top, view.width, view.height);
// optionally draw the draggable anchors
if (withAnchors) {
drawDragAnchor(view.left, view.top);
drawDragAnchor(view.left + view.width, view.top);
drawDragAnchor(view.left + view.width, view.top + view.height);
drawDragAnchor(view.left, view.top + view.height);
}
// optionally draw the connecting anchor lines
if (withBorders) {
ctx.beginPath();
ctx.rect(view.left, view.top, view.width, view.height);
ctx.stroke();
}
drawText();
}
function drawDragAnchor(x, y) {
ctx.beginPath();
ctx.arc(x, y, resizerRadius, 0, pi2, false);
ctx.closePath();
ctx.fill();
}
function drawText(){
var x = 40,
y = 100;
ctx.font = "bold 20px sans-serif";
ctx.fillStyle = "black";
ctx.fillText($("#textBox").val(), x, y);
}
// -------------------------------------------
// - Hit Testing -
// -------------------------------------------
// return 0,1,2, or 3 if (x,y) hits the respective anchor
// of the given view.
// return -1 if no anchor hit.
function anchorHitTest(view, x, y) {
var dx, dy;
x -= view.left;
y -= view.top;
// top-left
dx = x;
dy = y;
if (dx * dx + dy * dy <= rr) return (0);
// top-right
dx = x - view.width;
dy = y;
if (dx * dx + dy * dy <= rr) return (1);
// bottom-right
dx = x - view.width;
dy = y - view.height;
if (dx * dx + dy * dy <= rr) return (2);
// bottom-left
dx = x;
dy = y - view.height;
if (dx * dx + dy * dy <= rr) return (3);
return (-1);
}
// return true if (x,y) lies within the view
function hitImage(view, x, y) {
x -= view.left;
y -= view.top;
return (x > 0 && x < view.width && y > 0 && y < view.height);
}
// -------------------------------------------
// - Mouse -
// -------------------------------------------
var mousePos = {
x: 0,
y: 0
};
var draggingImage = false;
var startX, startY;
var isDown = false;
var currentImg = null;
var draggingResizer;
function updateMousePos(e) {
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
updateMousePos = function (e) {
mousePos.x = parseInt(e.clientX - offsetX);
mousePos.y = parseInt(e.clientY - offsetY);
};
return updateMousePos(e);
}
function handleMouseDown(e) {
updateMousePos(e);
// here you could make a loop to see which image / anchor was clicked
draggingResizer = anchorHitTest(img.view, mousePos.x, mousePos.y);
draggingImage = draggingResizer < 0 && hitImage(img.view, mousePos.x, mousePos.y);
//
if (draggingResizer<0 && !draggingImage) return;
startX = mousePos.x;
startY = mousePos.y;
currentImg = img;
}
function handleMouseUp(e) {
if (!currentImg) return;
draggingResizer = -1;
draggingImage = false;
draw(currentImg, true, false);
currentImg = null;
}
function handleMouseOut(e) {
handleMouseUp(e);
}
function handleMouseMove(e) {
if (!currentImg) return;
updateMousePos(e);
var view = currentImg.view;
if (draggingResizer > -1) {
var oldView = {
left: view.left,
top: view.top,
width: view.width,
height: view.height
};
// resize the image
switch (draggingResizer) {
case 0:
cl('ttoo');
//top-left
view.left = mousePos.x;
view.top = mousePos.y;
view.width = oldView.left + oldView.width - mousePos.x;
view.height = oldView.top + oldView.height - mousePos.y;
break;
case 1:
//top-right
// view.left unchanged
view.top = mousePos.y;
view.width = mousePos.x - oldView.left;
view.height = oldView.top + oldView.height - mousePos.y;
break;
case 2:
//bottom-right
view.width = mousePos.x - oldView.left;
view.height = mousePos.y - oldView.top;
break;
case 3:
//bottom-left
view.left = mousePos.x;
view.width = oldView.left + oldView.width - mousePos.x;
view.height = mousePos.y - (oldView.top);
break;
}
if (view.width < 25) view.width = 25;
if (view.height < 25) view.height = 25;
// redraw the image with resizing anchors
draw(currentImg, true, true);
} else if (draggingImage) {
imageClick = false;
// move the image by the amount of the latest drag
var dx = mousePos.x - startX;
var dy = mousePos.y - startY;
view.left += dx;
view.top += dy;
// reset the startXY for next time
startX = mousePos.x;
startY = mousePos.y;
// redraw the image with border
draw(currentImg, false, true);
}
}
var text = new Kinetic.Text({
x: 20,
y: 30,
text: '',
fontSize: '30',
fontFamily: 'Calibri',
fill: 'black',
draggable: true
});
stage.add(layer);
layer.add(text);
document.getElementById("textBox").addEventListener("keyup", function () {
text.setText(this.value);
layer.draw();
}, true);
document.getElementById("textSize").addEventListener("change", function () {
var size = this.value;
text.fontSize(size);
layer.draw();
}, true);
document.getElementById("fontFamily").addEventListener("change", function () {
var font = this.value;
text.fontFamily(font);
layer.draw();
}, true);
document.getElementById("fontStyle").addEventListener("change", function () {
var style = this.value;
text.fontStyle(style);
layer.draw();
}, true);
document.getElementById("fill").addEventListener("change", function () {
var colour = this.value;
text.fill(colour);
layer.draw();
}, true);
$("#canvas").mousedown(function (e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function (e) {
handleMouseUp(e);
});
$("#canvas").mouseout(function (e) {
handleMouseOut(e);
});
// utility
function cl() {
console.log.apply(console, arguments);
}
can provide jsFiddle if needed :)

You're trying to mix KineticJS with html canvas drawing commands.
That combination doesn't work because KineticJS does its magic by taking over the canvas--leaving no ability to call native canvas commands like context.beginPath.
// these 2 don't play together
... new Kinetic.Image ...
... ctx.beginPath ...
Anyway, Here's the answer to your question (in case you choose KineticJS for your project)
Kinetic.Image can be asked to execute a function when the image is clicked like this:
var image=new Kinetic.Image({
x: 100,
y: 50,
image: img,
width: 200,
height: 130,
draggable: true
}));
image.on("click",function(){
// The image was clicked
// Show your anchors now
});
layer.add(image);
[ Addition: Example of Kinetic.Image resizing ]
I don't like the overhead and complexity of maintaining anchors to resize Kinetic.Images.
Here's an example that lets you drag on the right side of the image to scale it proportionally:
http://jsfiddle.net/m1erickson/p8bpC/
You could modify this code to add cosmetic resizing grabbers (the grabbers are not necessary, but if you prefer the "anchor" look, you can add them).

You can refer to this question, the answers are guided and constructive, and contain a jsfiddle with the exact same behavior that you need.
Kinetic JS - how do you hide all the anchors for a given group ID

Related

Three.js: car orbit controls code won't work

I'm an absolute beginner in coding in general. I was trying to adapt the code for controlling a car from this codepeninto my project structure.
Here is my code:
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import "./styles.css";
// TASK 2
//let timer = setInterval(myTimer, 1000); //isn't it supposed to show something?
//function myTimer(){
// let d = new Date();
// document.getElementById("demo").innerHTML = d.toLocaleTimeString();
//}
// TASK 3.1
//document.getElementById("app").innerHTML =`
//<h1>Hello Vanilla</h1>
//<div>
// We use the same configuration as Parcel to bundle this sandbox, you can find more
// info about Parcel
// here
//</div>`
// TASK 3.2
let scene, camera, renderer;
let geometry, material, cube;
let colour, intensity, light;
let ambientLight;
let orbit, controls;
let listener, sound, audioLoader;
let clock, delta, interval, elapsedTime, lastElapsedTime, deltaTime, tick;
let sceneHeight, sceneWidth;
let size, divisions;
let car, body, bonnet, wheels;
let leftPressed, rightPressed, upPressed, downPressed;
let startButton = document.getElementById("startButton");
startButton.addEventListener("click", init);
function init() {
//alert("We have initialised!");
let overlay = document.getElementById("overlay");
overlay.remove();
sceneWidth = window.innerWidth;
sceneHeight = window.innerHeight;
//create our clock and set interval at 30 fpx
clock = new THREE.Clock();
delta = 0;
interval = 1 / 30;
lastElapsedTime = 0;
//create the scene
scene = new THREE.Scene();
scene.background = new THREE.Color(0xdfdfdf);
//create fog
const fog = new THREE.Fog(0xc3ebcd, 15, 40);
scene.fog = fog;
//creating camera (fos,aspect,near,far)
camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.z = 5;
camera.position.y = 5;
//skybox https://www.youtube.com/watch?v=PPwR7h5SnOE
let skyboxLoader = new THREE.CubeTextureLoader();
let skyboxTexture = skyboxLoader.load([
"./assets/skybox/xpos.png",
"./assets/skybox/xneg.png",
"./assets/skybox/ypos.png",
"./assets/skybox/yneg.png",
"./assets/skybox/zpos.png",
"./assets/skybox/zneg.png"
]);
scene.background = skyboxTexture;
//plane (ground) https://www.youtube.com/watch?v=PPwR7h5SnOE
let plane = new THREE.Mesh(
new THREE.PlaneGeometry(100, 100, 1, 1),
new THREE.MeshStandardMaterial({ color: 0xc3ebcd })
);
plane.castShadow = false;
plane.receiveShadow = true;
plane.rotation.x = -Math.PI / 2;
scene.add(plane);
//specify and adding renderer
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
//create orbit controls to interact with mouse
orbit = new OrbitControls(camera, renderer.domElement);
orbit.maxPolarAngle = 80 * (Math.PI / 180);
orbit.minDistance = 3;
orbit.maxDistance = 50;
orbit.enableDamping = true;
//CAR https://codepen.io/johndownie/pen/abjbLzy
car = new THREE.Group();
body = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshStandardMaterial({
color: "blue",
roughness: 0.5
})
);
body.position.y = 0.2;
body.castShadow = true;
bonnet = new THREE.Mesh(
new THREE.BoxGeometry(1, 0.5, 0.5),
new THREE.MeshStandardMaterial({
color: "blue",
roughness: 0.5
})
);
bonnet.position.z = -0.75;
bonnet.position.y = -0.25 + 0.2;
bonnet.castShadow = true;
wheels = [
{
name: "wheel1",
rotation: {
x: 0,
y: 0,
z: Math.PI * 0.5
},
position: {
x: 0.5 + 0.3 * 0.5,
y: -0.2,
z: 0.2
}
},
{
name: "wheel2",
rotation: {
x: 0,
y: 0,
z: -Math.PI * 0.5
},
position: {
x: -(0.5 + 0.3 * 0.5),
y: -0.2,
z: 0.2
}
},
{
name: "wheel3",
rotation: {
x: 0,
y: 0,
z: -Math.PI * 0.5
},
position: {
x: -(0.5 + 0.3 * 0.5),
y: -0.2,
z: -0.7
}
},
{
name: "wheel4",
rotation: {
x: 0,
y: 0,
z: Math.PI * 0.5
},
position: {
x: 0.5 + 0.3 * 0.5,
y: -0.2,
z: -0.7
}
}
];
for (let i = 0; i < wheels.length; i++) {
const wheel = new THREE.Mesh(
new THREE.CylinderGeometry(0.3, 0.3, 0.3, 10),
new THREE.MeshStandardMaterial({
color: 0x000000,
roughness: 0.5
})
);
wheel.rotation.set(
wheels[i].rotation.x,
wheels[i].rotation.y,
wheels[i].rotation.z
);
wheel.position.set(
wheels[i].position.x,
wheels[i].position.y,
wheels[i].position.z
);
wheel.name = wheels[i].name;
wheel.castShadow = true;
car.add(wheel);
}
car.add(body);
car.add(bonnet);
car.position.set(0, 0.5, 0);
scene.add(car);
//KEYBOARD SETUP
// Set up the key codes for the arrow keys
const LEFT_ARROW = 37;
const UP_ARROW = 38;
const RIGHT_ARROW = 39;
const DOWN_ARROW = 40;
// Set up a flag to track which keys are currently being pressed
let leftPressed = false;
let upPressed = false;
let rightPressed = false;
let downPressed = false;
// Listen for keydown events
document.addEventListener("keydown", function (event) {
// Check which key was pressed
switch (event.keyCode) {
case "LEFT_ARROW":
leftPressed = true;
break;
case UP_ARROW:
upPressed = true;
break;
case RIGHT_ARROW:
rightPressed = true;
break;
case DOWN_ARROW:
downPressed = true;
break;
default:
break;
}
});
// Listen for keyup events
document.addEventListener("keyup", function (event) {
// Check which key was released
switch (event.keyCode) {
case LEFT_ARROW:
leftPressed = false;
break;
case UP_ARROW:
upPressed = false;
break;
case RIGHT_ARROW:
rightPressed = false;
break;
case DOWN_ARROW:
downPressed = false;
break;
default:
break;
}
});
//First Person Camera https://www.youtube.com/watch?v=oqKzxPMLWxo
//controls = new FirstPersonControls(camera, renderer.domElement);
//controls.movementSpeed = 5;
//controls.lookSpeed = 0.8;
//fpsCamera = new FirstPersonCamera(this.camera, this.objects);
// lighting
colour = 0xffffff;
intensity = 1;
light = new THREE.DirectionalLight(colour, intensity);
light.position.set(100, 100, 100);
light.target.position.set(0, 0, 0);
light.castShadow = true;
scene.add(light);
ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
// create a box to spin
//geometry = new THREE.BoxGeometry();
//material = new THREE.MeshNormalMaterial(); // Change this from normal to Phong in step 5
//cube = new THREE.Mesh(geometry, material);
//cube.position.set(0, 1, 0);
//cube.castShadow = true;
//cube.receiveShadow = true;
//scene.add(cube);
//SOUND (for single source and single listener)
listener = new THREE.AudioListener();
camera.add(listener);
sound = new THREE.PositionalAudio(listener);
audioLoader = new THREE.AudioLoader();
audioLoader.load("./sounds/CPC_Basic_Drone_Loop.mp3", function (buffer) {
sound.setBuffer(buffer);
sound.setRefDistance(5); //a double value representing the reference distance for reducing volume as the audio source moves further from the listener – i.e. the distance at which the volume reduction starts taking effect. This value is used by all distance models.
sound.setDirectionalCone(180, 230, 0.1);
sound.setLoop(true);
sound.setVolume(0.5);
sound.play();
});
//resize window
window.addEventListener("resize", onWindowResize, false);
//strech goal: add gridHelper
size = 20;
divisions = 20;
//let gridHelper = new THREE.GridHelper(size, divisions);
//scene.add(gridHelper);
play();
}
//stop animation
function stop() {
renderer.setAnimationLoop(null);
}
// simple render function
function render() {
//controls.update(clock.getDelta());
camera.position.z = car.position.z + 8;
camera.position.x = car.position.x + 8;
camera.lookAt(car.position);
renderer.render(scene, camera);
}
//start animation
function play() {
//callback — The function will be called every available frame. If null is passed it will stop any already ongoing animation
renderer.setAnimationLoop(() => {
update();
render();
});
}
//our update function
function update() {
//orbit.update();
//cube.rotation.x += 0.01;
//cube.rotation.y += 0.04;
//cube.rotation.z -= 0.01;
tick = () => {
elapsedTime = clock.getElapsedTime();
deltaTime = elapsedTime - lastElapsedTime;
lastElapsedTime = elapsedTime;
// Update the car's rotation based on which arrow keys are being pressed
if (leftPressed) {
car.rotation.y += Math.PI / 45; // Rotate the car 4 degree clockwise
}
if (rightPressed) {
car.rotation.y -= Math.PI / 45; // Rotate the car 4 degree counterclockwise
}
const vector = new THREE.Vector3(); // create once and reuse it!
// Get the car's forward direction vector
const forward = car.getWorldDirection(vector);
// Set up the speed at which the car will move
const CAR_SPEED = deltaTime * 20;
// Update the car's position based on its forward direction and speed
if (upPressed) {
car.position.x -= forward.x * CAR_SPEED;
car.position.y -= forward.y * CAR_SPEED;
car.position.z -= forward.z * CAR_SPEED;
car.getObjectByName("wheel1").rotation.x -= CAR_SPEED;
car.getObjectByName("wheel2").rotation.x -= CAR_SPEED;
car.getObjectByName("wheel3").rotation.x -= CAR_SPEED;
car.getObjectByName("wheel4").rotation.x -= CAR_SPEED;
}
if (downPressed) {
car.position.x += forward.x * CAR_SPEED;
car.position.y += forward.y * CAR_SPEED;
car.position.z += forward.z * CAR_SPEED;
car.getObjectByName("wheel1").rotation.x += CAR_SPEED;
car.getObjectByName("wheel2").rotation.x += CAR_SPEED;
car.getObjectByName("wheel3").rotation.x += CAR_SPEED;
car.getObjectByName("wheel4").rotation.x += CAR_SPEED;
}
// Update controls
// controls.update();
// Call tick again on the next frame
window.requestAnimationFrame(tick);
};
tick();
}
function onWindowResize() {
sceneHeight = window.innerHeight;
sceneWidth = window.innerWidth;
renderer.setSize(sceneWidth, sceneHeight);
camera.aspect = sceneWidth / sceneHeight;
// Always call updateProjectionMatrix on camera change
//camera.updateProjectionMatrix();
}
Any help is much appreciated!!
However, not sure if I put the loops in the right function (whether update or renderer function). The car won't move.

HTML5 canvas drawing on background scalling

i have problem i have background image and changing it scale and position with mousewheel and can drawing with mousedown and mousemove events. me example: http://jsfiddle.net/74MCQ/ Now see first drawing and second zoom we don't see drawing lines. I need make like a paint if drawing on me select position and if zoom i need see equal position with equal zoom scale.
You need a way to store the drawings of your user, either within another canvas, or by storing coordinates.
I suggest you store coordinates, below here's some code that will store the lines within an array, each line being an array of coordinates like : [x0, y0, x1, y1, x2, y2, ... ].
Edit : now i simplified the things, the coordinates are stored relative to the center of canvas.
See the fiddle, it is mostly working.
fiddle :
http://jsfiddle.net/gamealchemist/74MCQ/4/
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
var x = evt.clientX - rect.left;
var y = evt.clientY - rect.top;
var sx = (x-cw/2)/scale;
var sy = (y-ch/2)/scale;
return {
x: x,
y: y,
sx : sx,
sy:sy
};
}
/****** PAINT ******/
var isDrawing = false;
var color = "#000000";
var brushWidth = 10;
//var previousEvent = false;
ctx.strokeStyle = '#000000';
var currentLine = null;
var allLines = [];
$("#canvas").mousedown(function (e) {
var mousePos = getMousePos(canvas, e);
ctx.moveTo(mousePos.x, mousePos.y);
isDrawing = true;
if (currentLine) allLines.push(currentLine);
currentLine = [];
currentLine.push(mousePos.sx, mousePos.sy);
});
$("#canvas").mouseup(function () {
isDrawing = false;
if (currentLine) allLines.push(currentLine);
currentLine = null;
});
$("#canvas").mouseout(function () {
isDrawing = false;
if (currentLine) allLines.push(currentLine);
currentLine = null;
});
$("#canvas").mousemove(function (e) {
if (isDrawing === true) {
var mousePos = getMousePos(canvas, e);
currentLine.push(mousePos.sx, mousePos.sy);
//paint tools, effects
ctx.lineWidth = 10;
ctx.strokeStyle = color;
ctx.shadowBlur = 1;
ctx.shadowColor = 'rgb(0, 0, 0)';
ctx.lineTo(mousePos.x, mousePos.y);
ctx.stroke();
}
});
function drawStoredLines() {
var thisLine;
for (var i = 0; i < allLines.length; i++) {
thisLine = allLines[i];
drawLine(thisLine);
}
}
function drawLine(ptArray) {
if (ptArray.length <= 2) return;
ctx.beginPath();
ctx.moveTo(ptArray[0], ptArray[1]);
for (var p = 2; p < ptArray.length; p += 2) {
ctx.lineTo(ptArray[p], ptArray[p + 1]);
}
ctx.lineWidth = 10;
ctx.strokeStyle = color;
ctx.shadowBlur = 1;
ctx.shadowColor = 'rgb(0, 0, 0)';
ctx.stroke();
}
Notice that i couldn't resist reducing your 175 lines code to select the scale to a 25 lines one :-)
var zoomSteps = [0.1, 0.2, 0.4, 0.6, 0.8, 1.0, 1.5, 2.0, 3.0, 4.0];
var zoomIndex = zoomSteps.indexOf(1);
function doScroll(e) {
e = window.event || e;
var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
zoomIndex = zoomIndex + delta;
if (zoomIndex < 0) zoomIndex = 0;
if (zoomIndex >= zoomSteps.length) zoomIndex = zoomSteps.length - 1;
scale = zoomSteps[zoomIndex];
imageWidthZoomed = imageWidth * scale;
imageHeightZoomed = imageHeight * scale;
var mousePos = getMousePos(canvas, e);
draw(mousePos.x, mousePos.y, scale);
}

Ball movement path in canvas, and other ideas you may have?

I've created this animation for my project that had to use any form of physics.
I am a total beginner, too :) Anyway, this is my project now :
Bouncing Balls
You can setup gravity and force, then click play, and just drag and drop to shoot the balls. You can change the values and hit update too see an effect.
My question is, how can I create an effect that when I press ratio button (for example) I can see the path that ball makes? Is it complicated? As I was saying I am a beginner, so no complex code for me :)
Also, doyou have any ideas to make the project better? Any additional "physics" effects? Or maybe you know a website that shows tutorials for simile (please) effects made in HTML5/js so I can add additional effects to my project.
One possibility (as you're clearing the canvas each frame) would be to draw ball paths onto a secondary canvas, which would not be cleared each frame. Then, when you come to clear the first frame, render the second frame after clearing, and before rendering the balls.
The second canvas would of course have to be the same dimensions as the first, so that all of the ball points line up correctly. The second canvas should also have a z-index lower than the first, so that it is only shown when you specifically render it to the first canvas (i.e. when the radio button is checked).
To decrease any lag while the radio is not checked, you could skip drawing the ball paths to the second canvas, although I don't think you would see any great increase in performance.
On each frame update, you would mark the position of each ball with a pixel, or line (from the previous position to the current) on the second canvas.
Looking at your code, you seem pretty competent, so I've skipped writing an example as I think this would be good experience for you :)
Modified 'script.js' source demonstrating solution
window.onload = function(){
$("#canvas").hide();
var howManyPaths = 0;
var showPath=false;
// SLIDERS
var gravitySlider = document.getElementById('gravitySlider');
var gravityVal = document.getElementById('gravityValue');
gravitySlider.onchange = function(){
gravityVal.value = gravitySlider.value;
}
gravityVal.onkeyup = function(){
gravitySlider.value = gravityVal.value;
}
var forceSlider = document.getElementById('forceSlider');
var forceValue = document.getElementById('forceValue');
forceSlider.onchange = function(){
forceValue.value = forceSlider.value;
}
forceValue.onkeyup = function(){
forceSlider.value = forceValue.value;
}
// GLOBAL VARIABLES
var test = false;
var gravityCount = $("#gravity").val();
var forceCount = $("#rectangles").val();
// CSS :
var playCSS = document.getElementById("play");
var restartCSS = document.getElementById("restart");
var clickableCSS = document.getElementById("setup");
var clickableBG = document.getElementById("img");
//restartCSS.style.visibility="hidden";
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvas2 = document.getElementById("canvas2");
var ctx2 = canvas2.getContext("2d");
//var ctx;
var gravity = 9.86;
var forceFactor = 0.5;
var mouseDown = false;
var balls = new Array();
var mousePos = new Array();
// EVENT HANDLER
function onMouseDown(evt){
mouseDown = true;
mousePos['downX'] = evt.pageX;
mousePos['downY'] = evt.pageY;
}
function onMouseUp(evt){
mouseDown = false;
setup.style.visibility="visible";
if(test == true && !( mousePos['downX'] < 200 && mousePos['downY'] < 150) ){
restartCSS.style.visibility="visible";
forceFactor = forceCount;
balls.push(new ball(mousePos["downX"],
mousePos["downY"],
(evt.pageX - mousePos["downX"]) * forceFactor,
(evt.pageY - mousePos["downY"]) * forceFactor,
10 + (Math.random() * 10),
0.8,
randomColor()
));
}
ctx2.clearRect(0, 0, canvas2.width, canvas2.height);
}
function onMouseMove(evt){
mousePos['currentX'] = evt.pageX;
mousePos['currentY'] = evt.pageY;
}
function resizeWindow(evt){
//canvas.height = 960;
//canvas.width = 720;
canvas.height = $(window).height()-6;
canvas.width = $(window).width();
canvas2.height = $(window).height()-6;
canvas2.width = $(window).width();
}
$(document).mousedown(onMouseDown);
$(document).mouseup(onMouseUp);
$(document).mousemove(onMouseMove);
$(window).bind("resize", resizeWindow);
// GRAPHICS CODE
function circle(x, y, r, col){
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI*2, true);
ctx.closePath;
// fill
ctx.fillStyle = col;
ctx.fill();
// stroke
ctx.lineWidth = r * 0.1;
ctx.strokeStyle = "#000000";
ctx.stroke();
}
function circlePath(x, y)
{
ctx2.clearRect(0, 0, canvas2.width, canvas2.height);
ctx2.fillStyle = '#3f4043';
ctx2.fillRect(x, y, 5, 5);
ctx2.strokeStyle = "black";
ctx2.strokeRect(x, y, 5, 5);
}
function randomColor(){
var letter = "0123456789ABCDEF".split("");
var color = "#";
for(var i=0; i<6; i++){
color += letter[Math.round(Math.random()*15)];
}
return color;
}
function arrow(fromX, fromY, toX, toY, color){
// path
ctx.beginPath();
var headLen = 10;
var angle = Math.atan2(toY - fromY, toX - fromX);
ctx.moveTo(fromX, fromY);
ctx.lineTo(toX, toY);
ctx.lineTo(toX - headLen * Math.cos(angle - Math.PI/6), toY - headLen * Math.sin(angle - Math.PI/6));
ctx.moveTo(toX, toY);
ctx.lineTo(toX - headLen * Math.cos(angle + Math.PI/6), toY - headLen * Math.sin(angle + Math.PI/6));
// style
ctx.lineWith = 1;
ctx.strokeStyle = color;
ctx.lineCap = "butt";
ctx.stroke();
}
function drawBall(){
// Gravity
gravity = gravityCount;
this.speedY += gravity * 0.5; // v = a * t
this.x += this.speedX * 0.05; // s = v * t
this.y += this.speedY * 0.05;
// prawa ściana
if(this.x + this.r > canvas.width){
this.x = canvas.width - this.r;
this.speedX *= -1 * this.bounce;
}
// lewa ściana
if(this.x - this.r < 0){
this.x = this.r;
this.speedX *= -1 * this.bounce;
}
// dolna ściana
if(this.y + this.r > canvas.height){
this.y = canvas.height - this.r;
this.speedY *= -1 * this.bounce;
}
// górna ściana
if(this.y - this.r < 0){
this.y = this.r;
this.speedY *= -1 * this.bounce;
}
// zwalnianie na ziemi
if (this.speedX > 0.25){
this.speedX -= 0.25;
if (this.speedY > 0.25)
this.speedY -= 0.25;
}
if (this.speedX < -0.25){
this.speedX += 0.25;
//if (this.speedY < -0.25)
// this.speedY += 0.25;
}
circle(this.x, this.y, this.r, this.col);;
}
// OBJECTS
function ball(positionX, positionY, sX, sY, radius, b, color){
this.x = positionX;
this.y = positionY;
this.speedX = sX;
this.speedY = sY;
this.r = radius;
this.bounce = b;
this.col = color;
this.draw = drawBall;
}
//GAME LOOP
function gameLoop(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
//grab the context from your destination canvas
//if path drawing is enabled, first draw the path canvas to the display canvas
if (showPath) ctx.drawImage(canvas2,0,0);
if(mouseDown == true){
// ctx.clearRect(0, 0, canvas.width, canvas.height); /* !important !!!!!!!!!!!!!!! */
arrow(mousePos['downX'], mousePos['downY'], mousePos['currentX'], mousePos['currentY'], "red");
}
for(var i=0; i<balls.length; i++){
balls[i].draw();
if (i==balls.length-1) {
//draw path
ctx2.fillStyle = '#3f4043';
ctx2.fillRect(balls[i].x, balls[i].y, 5, 5);
ctx2.strokeStyle = "black";
ctx2.strokeRect(balls[i].x, balls[i].y, 5, 5);
}
}
ctx.fillStyle = "#000000";
ctx.font = "15px Arial";
ctx.fillText("Balls: " + balls.length + " " + gravityCount + " " + forceCount + " " + howManyPaths, 10, canvas.height -10);
}
// START THE GAME
function init(){
//$("#setup").hide();
$("#canvas").show();
$("#canvas2").hide();
ctx = $('canvas')[0].getContext("2d");
canvas.height = $(window).height()-6;
canvas.width = $(window).width();
//canvas.width = 960;
//canvas.height = 720;
canvas2.height = $(window).height()-6;
canvas2.width = $(window).width();
return setInterval(gameLoop, 10);
}
$("#play").click(function() {
test = true;
playCSS.style.visibility="hidden";
gravityCount = $("#gravitySlider").val();
forceCount = $("#forceSlider").val();
init();
});
$("#restart").click(function() {
window.location.href="index.html";
});
$("#refresh").click(function() {
gravityCount = $("#gravitySlider").val();
forceCount = $("#forceSlider").val();
});
$("#showPath").click(function() {
showPath=true;
});
$("#hidePath").click(function() {
showPath=false;
});
}

Kinetic JS - drawing arrowhead at start and end of a line using mouse

I am trying to add arrowhead to the start and end of lines that I am drawing using the mouse, here is my script for drawing the line:
document.getElementById('dLine').onclick = function() {
layer.on("mousedown", function () {
if (moving) {
moving = false;
layer.draw();
} else {
var mousePos = stage.getMousePosition();
x1 = mousePos.x;
y1 = mousePos.y;
line = new Kinetic.Line({
points: [0, 0, 50, 50],
stroke: "red"
});
layer.add(line);
line.getPoints()[0].x = mousePos.x;
line.getPoints()[0].y = mousePos.y;
line.getPoints()[1].x = mousePos.x;
line.getPoints()[1].y = mousePos.y;
moving = true;
layer.drawScene();
}
});
layer.on("mousemove", function () {
if (moving) {
var mousePos = stage.getMousePosition();
var x = mousePos.x;
var y = mousePos.y;
line.getPoints()[1].x = mousePos.x;
line.getPoints()[1].y = mousePos.y;
moving = true;
layer.drawScene();
}
});
layer.on("mouseup", function () {
moving = false;
var mousePos = stage.getMousePosition();
x2 = mousePos.x;
y2 = mousePos.y;
$("#distance").val(calculateDistance(x1, y1, x2, y2));
});
};
I would appreciate your suggestions.
You can use this function to draw an arrow:
function canvas_arrow(fromx, fromy, tox, toy){
var headlen = 20; // how long you want the head of the arrow to be, you could calculate this as a fraction of the distance between the points as well.
var angle = Math.atan2(toy-fromy,tox-fromx);
line = new Kinetic.Line({
points: [fromx, fromy, tox, toy, tox-headlen*Math.cos(angle-Math.PI/6),toy-headlen*Math.sin(angle-Math.PI/6),tox, toy, tox-headlen*Math.cos(angle+Math.PI/6),toy-headlen*Math.sin(angle+Math.PI/6)],
stroke: "red"
});
}
Edit: jsfiddle.net/cmcculloh/M56w4 - provided in the comments

Moving already Drawn shape on html5 canvas

I'm having trouble keeping one object on my canvas. The initially drawn box rendered it in the correct position, but it disappears when I drag it:
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
eraseAllButton = document.getElementById('eraseAllButton'),
strokeStyleSelect = document.getElementById('strokeStyleSelect'),
guidewireCheckbox = document.getElementById('guidewireCheckbox'),
drawingSurfaceImageData,
mousedown = {},
rubberbandRect = {},
dragging = false,
guidewires = guidewireCheckbox.checked,
w = 90, h = 90;
count = 0;
boxesXCo = 0;
boxesYCo = 0;
i = 0;
// Functions..........................................................
function drawGrid(color, stepx, stepy) {
context.save()
context.strokeStyle = color;
context.lineWidth = 0.5;
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
for (var i = stepx + 0.5; i < context.canvas.width; i += stepx) {
context.beginPath();
context.moveTo(i, 0);
context.lineTo(i, context.canvas.height);
context.stroke();
}
for (var i = stepy + 0.5; i < context.canvas.height; i += stepy) {
context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();
}
context.restore();
}
function windowToCanvas(x, y) {
var bbox = canvas.getBoundingClientRect();
return { x: x - bbox.left * (canvas.width / bbox.width),
y: y - bbox.top * (canvas.height / bbox.height) };
}
// Save and restore drawing surface...................................
function saveDrawingSurface() {
drawingSurfaceImageData = context.getImageData(0, 0,
canvas.width,
canvas.height);
}
function restoreDrawingSurface() {
context.putImageData(drawingSurfaceImageData, 0, 0);
}
function drawRubberbandShape(loc) {
context.beginPath();
context.moveTo(mousedown.x, mousedown.y);
//context.lineTo(loc.x, loc.y);
context.stroke();
}
function updateRubberband(loc) {
//updateRubberbandRectangle(loc);
context.restore();
drawRubberbandShape(loc);
}
// Guidewires.........................................................
function drawHorizontalLine (y) {
context.beginPath();
context.moveTo(0,y+0.5);
context.lineTo(context.canvas.width,y+0.5);
context.stroke();
}
function drawVerticalLine (x) {
context.beginPath();
context.moveTo(x+0.5,0);
context.lineTo(x+0.5,context.canvas.height);
context.stroke();
}
function drawGuidewires(x, y) {
context.save();
context.strokeStyle = 'rgba(0,0,230,0.4)';
context.lineWidth = 0.5;
drawVerticalLine(x);
drawHorizontalLine(y);
context.restore();
}
// Canvas event handlers..............................................
canvas.onmousedown = function (e) {
var loc = windowToCanvas(e.clientX, e.clientY);
e.preventDefault(); // prevent cursor change
context.restore();
saveDrawingSurface();
mousedown.x = loc.x;
mousedown.y = loc.y;
dragging = true;
if (i ==0)
i++;
else if(((mousedown.x<=(boxesXCo+w)&&(mousedown.x>=boxesXCo))&&
((mousedown.y<=(boxesYCo+h)&&(mousedown.y>=boxesYCo)))))
i--;
};
canvas.onmousemove = function (e) {
var loc;
if (dragging) {
e.preventDefault(); // prevent selections
loc = windowToCanvas(e.clientX, e.clientY);
restoreDrawingSurface();
//updateRubberband(loc);
if(guidewires) {
drawGuidewires(loc.x, loc.y);
}
}
if(((mousedown.x<=(boxesXCo+w)&&(mousedown.x>=boxesXCo))&&
((mousedown.y<=(boxesYCo+h)&&(mousedown.y>=boxesYCo))))
&& (dragging)&&(i == 1 )){
context.restore();
restoreDrawingSurface();
context.fillStyle = strokeStyleSelect.value;
context.fillRect(e.clientX,e.clientY,w,h);
};
//Trying to implement moving shapes but need to store values of drawn objs
};
canvas.onmouseup = function (e) {
loc = windowToCanvas(e.clientX, e.clientY);
restoreDrawingSurface();
updateRubberband(loc);
dragging = false;
if(i == 0);
else {
saveDrawingSurface();
restoreDrawingSurface();
context.fillRect(e.clientX,e.clientY, w, h);
boxesXCo = e.clientX;
boxesYCo = e.clientY;
context.restore();
i++;}
/*else if(i == 1)
{
context.restore();
}*/
//context.fillRect(mousedown.x,mousedown.y,w,h,"FF0982");
};
// Controls event handlers.......................................
eraseAllButton.onclick = function (e) {
context.clearRect(0, 0, canvas.width, canvas.height);
drawGrid('lightgray', 10, 10);
saveDrawingSurface();
count =0;
context.restore();
};
strokeStyleSelect.onchange = function (e) {
context.strokeStyle = strokeStyleSelect.value;
context.fillStyle = strokeStyleSelect.value;
};
guidewireCheckbox.onchange = function (e) {
guidewires = guidewireCheckbox.checked;
};
// Initialization................................................
context.strokeStyle = strokeStyleSelect.value;
context.fillStyle = strokeStyleSelect.value;
drawGrid('lightgray', 10, 10);
//context.fillRect(mousedown.x,mousedown.y,(mousedown.x+50),(mousedown.x+50),"FF0982");
//context.drawRect(mousedown.x-50,mousedown.y-50,mousedown.x+50,mousedown.y+50);
thanx again
Rather than drawing to canvas on each mouse movement, use window.requestFrameAnimation to draw constantly.
At a guess, I'd assume either the browser rendering is interfering or the coordinates are out but I can't run your code to make sure.
I've written some pseudo code that shows what I do for rendering things. You'll need to implement this for yourself, it won't run out of the box, it's just intended as a guide.
var Box = function() {
};
Box.prototype = {
x: 0,
y: 0,
draw: function (canvas) {
// draw the item on the canvas
}
};
var box = new Box();
window.requestAnimationFrame(function() {
box.draw(canvas);
window.requestAnimationFrame();
});
canvas.onmousemove = function(e) {
if (dragging) {
box.x = e.clientX;
box.y = e.clientY;
}
}