HTML5 Canvas How To Fill A Mouse Drawn Triangle - html5-canvas

I am trying to fill a triangle shape on a HTML5 canvas drawn by dragging the mouse.
I have similar effect for circles, rectangles working.
The code showing both the working drawCircle and not working drawTriangle functions is below. The outline of the triangle gets drawn but it is not filled. I have tried loving the context.stroke line to various places in the sequence of there is no effect.
<style>
#divContainer {
width: 100%;
height: 80%;
background: #ddd;
}
#divContentArea {
left: 0px;
top: 0px;
right: 0px;
bottom: 0px;
}
.canvas {
cursor: crosshair;
position:relative;
left:0px;
top:0px;
}
</style>
<div>
Click the button to select the shape type then click and drag mouse on the canvas below.
<BR>
<button type="button" onClick='shapetype="circle";'>Draw Circle</button>
<button type="button" onClick='shapetype="triangle";'>Draw Triangle</button>
<BR>
</div>
<div id="divContainer">
<div id="divContentArea">
<canvas id="canvas" class='canvas'>
Sorry, your browser does not support a canvas object.
</canvas>
</div>
</div>
<script>
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var canrect = canvas.getBoundingClientRect();
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var lastPoint;
var startPoint;
var isDrawing = false;
var shapetype = 'triangle';
canvas.onmousedown = function(e) {
isDrawing = true;
if ( shapetype == 'circle' ) {
canvas.removeEventListener("mousemove", drawTriangle, false);
canvas.addEventListener("mousemove", drawCircle, false);
} else {
canvas.removeEventListener("mousemove", drawCircle, false);
canvas.addEventListener("mousemove", drawTriangle, false);
}
lastPoint = { x: e.offsetX, y: e.offsetY };
startPoint = lastPoint;
};
function drawTriangle(e) {
// This doesn't work - triangle is not filled
e.preventDefault();
e.stopPropagation();
if (!isDrawing) return;
mx = e.offsetX;
my = e.offsetY;
// clear the canvas
context.clearRect(0, 0, canvas.width, canvas.height);
// calculate the rectangle width/height based
// on starting vs current mouse position
var twidth = Math.abs(mx - startPoint.x) ;
var theight = Math.abs(my - startPoint.y) ;
// draw a new rect from the start position
// to the current mouse position
context.beginPath();
context.lineWidth = 3;
context.lineJoin = context.lineCap = 'round';
context.setLineDash([0, 0]);
context.globalAlpha = 1.0;
if ( mx >= startPoint.x ) {
context.moveTo(startPoint.x, startPoint.y );
context.lineTo(mx, my);
context.moveTo(mx-(2*twidth), my );
context.lineTo(mx, my);
context.moveTo(startPoint.x, startPoint.y );
context.lineTo(mx-(2*twidth), my );
} else {
context.moveTo(startPoint.x, startPoint.y );
context.lineTo(mx, my);
context.moveTo(mx+(2*twidth), my );
context.lineTo(mx, my);
context.moveTo(startPoint.x, startPoint.y );
context.lineTo(mx+(2*twidth), my );
}
context.closePath();
context.strokeStyle = 'red';
context.stroke();
context.fillStyle = 'rgba(25,50,75,0.5)';
context.fill();
}
function drawCircle(e) {
// This works
e.preventDefault();
e.stopPropagation();
if (!isDrawing) return;
mx = e.offsetX;
my = e.offsetY;
// clear the canvas
context.clearRect(0, 0, canvas.width, canvas.height);
// calculate the rectangle width/height based
// on starting vs current mouse position
var cradius = Math.abs(mx - startPoint.x) ;
// draw a new rect from the start position
// to the current mouse position
context.beginPath();
context.lineWidth = 3;
context.lineJoin = context.lineCap = 'round';
context.setLineDash([0, 0]);
context.globalAlpha = 1.0;
context.strokeStyle = 'red';
context.arc(startPoint.x, startPoint.y, cradius, 0, 2 * Math.PI, false);
context.fillStyle = 'rgba(25,50,75,0.5)';
context.fill();
context.stroke();
}
canvas.onmouseup = function() {
isDrawing = false;
};
canvas.onmouseleave = function() {
isDrawing = false;
};
</script>

function drawTriangle(e) {
e.preventDefault();
e.stopPropagation();
if (!isDrawing) return;
// clear the canvas
context.clearRect(0, 0, canvas.width, canvas.height);
// draw a new rect from the start position
// to the current mouse position
context.strokeStyle = 'red';
context.fillStyle = 'rgba(25,50,75,0.5)';
context.lineWidth = 3;
context.lineJoin = context.lineCap = 'round';
context.setLineDash([0, 0]);
context.globalAlpha = 1.0;
context.beginPath();
context.moveTo(startPoint.x, startPoint.y);
context.lineTo(e.offsetX, e.offsetY);
context.lineTo(startPoint.x * 2 - e.offsetX, e.offsetY);
context.closePath();
context.stroke();
context.fill();
}

The CanvasRenderingContext2D's fill() method fills a path with a given color. To be able to fill such a path, it must contain at least three points - which is fulfilled in your case.
The problem is the way you're creating the path:
context.moveTo(startPoint.x, startPoint.y );
context.lineTo(mx, my);
context.moveTo(mx-(2*twidth), my );
context.lineTo(mx, my);
context.moveTo(startPoint.x, startPoint.y );
context.lineTo(mx-(2*twidth), my );
By calling moveTo() again, you're essentially starting a new path - thus you have just three single lines hence nothing to fill.
Try making the path in one go:
context.moveTo(startPoint.x, startPoint.y );
context.lineTo(mx, my);
context.lineTo(mx-(2*twidth), my );
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var canrect = canvas.getBoundingClientRect();
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var lastPoint;
var startPoint;
var isDrawing = false;
var shapetype = 'triangle';
canvas.onmousedown = function(e) {
isDrawing = true;
if (shapetype == 'circle') {
canvas.removeEventListener("mousemove", drawTriangle, false);
canvas.addEventListener("mousemove", drawCircle, false);
} else {
canvas.removeEventListener("mousemove", drawCircle, false);
canvas.addEventListener("mousemove", drawTriangle, false);
}
lastPoint = {
x: e.offsetX,
y: e.offsetY
};
startPoint = lastPoint;
};
function drawTriangle(e) {
// This doesn't work - triangle is not filled
e.preventDefault();
e.stopPropagation();
if (!isDrawing) return;
mx = e.offsetX;
my = e.offsetY;
// clear the canvas
context.clearRect(0, 0, canvas.width, canvas.height);
// calculate the rectangle width/height based
// on starting vs current mouse position
var twidth = Math.abs(mx - startPoint.x);
var theight = Math.abs(my - startPoint.y);
// draw a new rect from the start position
// to the current mouse position
context.beginPath();
context.lineWidth = 3;
context.lineJoin = context.lineCap = 'round';
context.setLineDash([0, 0]);
context.globalAlpha = 1.0;
if (mx >= startPoint.x) {
context.moveTo(startPoint.x, startPoint.y);
context.lineTo(mx, my);
context.lineTo(mx - (2 * twidth), my);
} else {
context.moveTo(startPoint.x, startPoint.y);
context.lineTo(mx, my);
context.lineTo(mx + (2 * twidth), my);
}
context.closePath();
context.strokeStyle = 'red';
context.stroke();
context.fillStyle = 'rgba(25,50,75,0.5)';
context.fill();
}
function drawCircle(e) {
// This works
e.preventDefault();
e.stopPropagation();
if (!isDrawing) return;
mx = e.offsetX;
my = e.offsetY;
// clear the canvas
context.clearRect(0, 0, canvas.width, canvas.height);
// calculate the rectangle width/height based
// on starting vs current mouse position
var cradius = Math.abs(mx - startPoint.x);
// draw a new rect from the start position
// to the current mouse position
context.beginPath();
context.lineWidth = 3;
context.lineJoin = context.lineCap = 'round';
context.setLineDash([0, 0]);
context.globalAlpha = 1.0;
context.strokeStyle = 'red';
context.arc(startPoint.x, startPoint.y, cradius, 0, 2 * Math.PI, false);
context.fillStyle = 'rgba(25,50,75,0.5)';
context.fill();
context.stroke();
}
canvas.onmouseup = function() {
isDrawing = false;
};
canvas.onmouseleave = function() {
isDrawing = false;
};
#divContainer {
width: 100%;
height: 80%;
background: #ddd;
}
#divContentArea {
left: 0px;
top: 0px;
right: 0px;
bottom: 0px;
}
.canvas {
cursor: crosshair;
position: relative;
left: 0px;
top: 0px;
}
<div>
Click the button to select the shape type then click and drag mouse on the canvas below.
<BR>
<button type="button" onClick='shapetype="circle";'>Draw Circle</button>
<button type="button" onClick='shapetype="triangle";'>Draw Triangle</button>
<BR>
</div>
<div id="divContainer">
<div id="divContentArea">
<canvas id="canvas" class='canvas'>
Sorry, your browser does not support a canvas object.
</canvas>
</div>
</div>

Related

Mix WebGL and CSS3D renderers when using percentage

When mixing WebGL and CSS3D renderers, the CSS3D layer gets shifted when resizing the page. It took me a while before realizing I was using percentages to set the WebGL canvas and it seems to be the source of the problem. The 2 elements are perfectly aligned when the computed size (from percentage calculation) is a whole number, and are shifted when the computed size introduces decimals.
Here is a record of what happens:
I could simply get rid of the percentages and use whole numbers instead but I wonder if there is a better solution to this problem?
I'm not seeing any shifting. Maybe I just don't know how to repo the issue. Can you post a repo?
html, body {
margin: 0;
height: 100%;
}
#css3d {
width: 100%;
height: 100%;
overflow: hidden;
}
#webgl, #blocker {
width: 100%;
height: 100%;
display: block;
position: absolute;
left: 0;
top: 0;
}
<div id="css3d"></div>
<canvas id="webgl"></canvas>
<div id="blocker"></div>
<script type="module">
import * as THREE from 'https://cdn.jsdelivr.net/npm/three#0.120.0/build/three.module.js';
import {
TrackballControls
} from 'https://cdn.jsdelivr.net/npm/three#0.120.0/examples/jsm/controls/TrackballControls.js';
import {
CSS3DRenderer,
CSS3DObject
} from 'https://cdn.jsdelivr.net/npm/three#0.120.0/examples/jsm/renderers/CSS3DRenderer.js';
function Element(url, x, y, z, ry) {
const div = document.createElement('div');
div.style.width = '480px';
div.style.height = '360px';
div.style.backgroundColor = '#000';
const iframe = document.createElement('iframe');
iframe.style.width = '480px';
iframe.style.height = '360px';
iframe.style.border = '0px';
iframe.src = url;
div.appendChild(iframe);
const object = new CSS3DObject(div);
object.position.set(x, y, z);
object.rotation.y = ry;
return object;
}
const css3DContainer = document.querySelector('#css3d');
const css3DRenderer = new CSS3DRenderer();
css3DContainer.appendChild(css3DRenderer.domElement);
const webglCanvas = document.querySelector('#webgl')
const webglRenderer = new THREE.WebGLRenderer({
canvas: webglCanvas,
alpha: true,
});
const camera = new THREE.PerspectiveCamera(50, 2, 1, 5000);
camera.position.set(500, 350, 750);
const scene = new THREE.Scene();
const plane = new THREE.PlaneGeometry(480, 360);
const group = new THREE.Group();
function addElementAndPlane(color, url, x, y, z, ry) {
group.add(new Element(url, x, y, z, ry));
const material = new THREE.MeshBasicMaterial({
color,
transparent: true,
opacity: 0.5,
});
const mesh = new THREE.Mesh(plane, material);
mesh.position.set(x, y, z);
mesh.rotation.y = ry;
group.add(mesh);
}
[
['red', 'https://twgljs.org/examples/tiny.html', 0, 0, 240, 0],
['green', 'https://twgljs.org/examples/2d-lines.html', 240, 0, 0, Math.PI / 2],
['blue', 'https://twgljs.org/examples/kaleidoscope.html', 0, 0, -240, Math.PI],
['yellow', 'https://twgljs.org/examples/twgl-cube.html', -240, 0, 0, -Math.PI / 2],
].forEach(args => addElementAndPlane(...args));
scene.add(group);
const controls = new TrackballControls(camera, webglCanvas);
controls.rotateSpeed = 4;
window.addEventListener('resize', onWindowResize, false);
onWindowResize();
// Block iframe events when dragging camera
const blocker = document.querySelector('#blocker');
blocker.style.display = 'none';
controls.addEventListener('start', function() {
blocker.style.display = '';
});
controls.addEventListener('end', function() {
blocker.style.display = 'none';
});
function onWindowResize() {
const width = webglCanvas.clientWidth;
const height = webglCanvas.clientHeight;
if (webglCanvas.width !== width || webglCanvas.height !== height) {
webglRenderer.setSize(width, height, false);
css3DRenderer.setSize(width, height, false);
camera.aspect = width / height;
camera.updateProjectionMatrix();
}
}
function animate() {
controls.update();
css3DRenderer.render(scene, camera);
webglRenderer.render(scene, camera);
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
</script>

Loading image in Canvas with mouse follow

I am struggling to make an image appear in a Canvas animated card. I can get text and drawn images to show up, but I can't seem to load the image and still have the ball follow the mouse. Why is that? I'm sure it's something super easy but I keep trying different things and am getting no where!
<script>
var canvas = document.querySelector("#myCanvas");
var context = canvas.getContext("2d");
var canvasPos = getPosition(canvas);
var mouseX = 525;
var mouseY = 325;
canvas.addEventListener("mousemove", setMousePosition, false);
function setMousePosition(e) {
mouseX = e.clientX - canvasPos.x;
mouseY = e.clientY - canvasPos.y;
}
function getPosition(el) {
var xPosition = 0;
var yPosition = 0;
while (el) {
xPosition += (el.offsetLeft - el.scrollLeft + el.clientLeft);
yPosition += (el.offsetTop - el.scrollTop + el.clientTop);
el = el.offsetParent;
}
return {
x: xPosition,
y: yPosition
};
}
function loadTeacher() {
var myImage = new Image();
myImage.src = 'images/teacher.jpg';
myImage.addEventListener("load", loadImage, false);
function loadImage(e) {
context.drawImage(myImage, 0, 75, 500, 350);
}
} loadTeacher();
function update() {
context.clearRect(0, 0, canvas.width, canvas.height);
//write text
context.font = "bold 12pt Helvetica, Ariel, sans-serif";
context.textAlign = "center";
context.fillStyle = "black";
context.fillText("This teacher needs an apple now! Drag the apple to her mouth.", 250, 50);
//draw circle
context.beginPath();
context.arc(mouseX, mouseY, 15, 0, 2 * Math.PI, true);
context.fillStyle = "red";
context.fill();
requestAnimationFrame(update);
}
update();
</script>

Threejs Tooltip

this could be a duplicate, but I have not found anything as yet.
I am trying to create tooltip for on mouse hover. (perspective camera)
Tooltip issue:
https://jsfiddle.net/thehui87/d12fLr0b/14/
threejs r76
function onDocumentMouseMove( event )
{
// update sprite position
// sprite1.position.set( event.clientX, event.clientY, 1 );
// update the mouse variable
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
var vector = new THREE.Vector3( mouse.x, mouse.y, 0 );
vector.unproject(camera);
var dir = vector.sub( camera.position ).normalize();
var distance = - camera.position.z / dir.z;
var pos = camera.position.clone().add( dir.multiplyScalar( distance ) );
sprite1.position.copy(pos);
}
But once i orbit the camera the tooltip moves away.
References for tooltip.
http://stemkoski.github.io/Three.js/Mouse-Tooltip.html
Three.js - Object follow mouse position
If anyone could kindly point me to the right answer on stackoverflow or provide an alternate solution.
Thanks
Well working tooltip is not only correctly placed text label. It has some of show and hide intelligence.
It should:
not appear immediately, but once mouse becomes stationary over some object,
not disappear immediately, rather it should fade away after mouse left the object area,
it should neither follow the mouse, nor stay where it was, if user moves the mouse around the object area not leaving it.
All of that is included in my solution: http://jsfiddle.net/mmalex/ycnh0wze/
<div id="tooltip"></div> must be initially added to HTML. The recommended CSS you find below. Crucial to have it position: fixed;, anything else is a matter of taste.
#tooltip {
position: fixed;
left: 0;
top: 0;
min-width: 100px;
text-align: center;
padding: 5px 12px;
font-family: monospace;
background: #a0c020;
display: none;
opacity: 0;
border: 1px solid black;
box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5);
transition: opacity 0.25s linear;
border-radius: 3px;
}
var scene = new THREE.Scene();
var raycaster = new THREE.Raycaster();
//create some camera
camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = 5;
camera.position.y = 5;
camera.position.z = 5;
camera.lookAt(0, 0, 0);
var controls = new THREE.OrbitControls(camera);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(new THREE.Color(0x595959));
document.body.appendChild(renderer.domElement);
// white spotlight shining from the side, casting a shadow
var spotLight = new THREE.SpotLight(0xffffff, 2.5, 25, Math.PI / 6);
spotLight.position.set(4, 10, 7);
scene.add(spotLight);
// collect objects for raycasting,
// for better performance don't raytrace all scene
var tooltipEnabledObjects = [];
var colors = new RayysWebColors();
for (let k = 0; k < 12; k++) {
var size = 0.5;
var geometry = new THREE.BoxGeometry(size, 0.2, size);
var randomColor = colors.pickRandom();
var material = new THREE.MeshPhongMaterial({
color: randomColor.hex,
transparent: true,
opacity: 0.75
});
var cube = new THREE.Mesh(geometry, material);
cube.userData.tooltipText = randomColor.name;
cube.applyMatrix(new THREE.Matrix4().makeTranslation(-3 + 6 * Math.random(), 0, -3 + 0.5 * k));
scene.add(cube);
tooltipEnabledObjects.push(cube);
}
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
};
// this will be 2D coordinates of the current mouse position, [0,0] is middle of the screen.
var mouse = new THREE.Vector2();
var latestMouseProjection; // this is the latest projection of the mouse on object (i.e. intersection with ray)
var hoveredObj; // this objects is hovered at the moment
// tooltip will not appear immediately. If object was hovered shortly,
// - the timer will be canceled and tooltip will not appear at all.
var tooltipDisplayTimeout;
// This will move tooltip to the current mouse position and show it by timer.
function showTooltip() {
var divElement = $("#tooltip");
if (divElement && latestMouseProjection) {
divElement.css({
display: "block",
opacity: 0.0
});
var canvasHalfWidth = renderer.domElement.offsetWidth / 2;
var canvasHalfHeight = renderer.domElement.offsetHeight / 2;
var tooltipPosition = latestMouseProjection.clone().project(camera);
tooltipPosition.x = (tooltipPosition.x * canvasHalfWidth) + canvasHalfWidth + renderer.domElement.offsetLeft;
tooltipPosition.y = -(tooltipPosition.y * canvasHalfHeight) + canvasHalfHeight + renderer.domElement.offsetTop;
var tootipWidth = divElement[0].offsetWidth;
var tootipHeight = divElement[0].offsetHeight;
divElement.css({
left: `${tooltipPosition.x - tootipWidth/2}px`,
top: `${tooltipPosition.y - tootipHeight - 5}px`
});
// var position = new THREE.Vector3();
// var quaternion = new THREE.Quaternion();
// var scale = new THREE.Vector3();
// hoveredObj.matrix.decompose(position, quaternion, scale);
divElement.text(hoveredObj.userData.tooltipText);
setTimeout(function() {
divElement.css({
opacity: 1.0
});
}, 25);
}
}
// This will immediately hide tooltip.
function hideTooltip() {
var divElement = $("#tooltip");
if (divElement) {
divElement.css({
display: "none"
});
}
}
// Following two functions will convert mouse coordinates
// from screen to three.js system (where [0,0] is in the middle of the screen)
function updateMouseCoords(event, coordsObj) {
coordsObj.x = ((event.clientX - renderer.domElement.offsetLeft + 0.5) / window.innerWidth) * 2 - 1;
coordsObj.y = -((event.clientY - renderer.domElement.offsetTop + 0.5) / window.innerHeight) * 2 + 1;
}
function handleManipulationUpdate() {
raycaster.setFromCamera(mouse, camera); {
var intersects = raycaster.intersectObjects(tooltipEnabledObjects);
if (intersects.length > 0) {
latestMouseProjection = intersects[0].point;
hoveredObj = intersects[0].object;
}
}
if (tooltipDisplayTimeout || !latestMouseProjection) {
clearTimeout(tooltipDisplayTimeout);
tooltipDisplayTimeout = undefined;
hideTooltip();
}
if (!tooltipDisplayTimeout && latestMouseProjection) {
tooltipDisplayTimeout = setTimeout(function() {
tooltipDisplayTimeout = undefined;
showTooltip();
}, 330);
}
}
function onMouseMove(event) {
updateMouseCoords(event, mouse);
latestMouseProjection = undefined;
hoveredObj = undefined;
handleManipulationUpdate();
}
window.addEventListener('mousemove', onMouseMove, false);
animate();
Replace:
var vector = new THREE.Vector3( mouse.x, mouse.y, 0 );
by:
var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );

Can't Detect Mouseover on This KineticJS Shape?

I have a KineticJS shape that draws a bezier curve that is wider on one end. It draws correctly, but I can't yet detect a 'mouseover' event on it. I have created a small JSFiddle demo of the anomaly, at:
http://jsfiddle.net/VikR0001/nZYxL/6/
How can I detect 'mouseover' events on this shape?
Thanks very much in advance to all for any info!
var mainLayer;
//bezier curve code:
//http://stackoverflow.com/questions/8325680/how-to-draw-a-bezier-curve-with-variable-thickness-on-an-html-canvas
//draw a bezier curve that gets larger as it flows
//adapted for use with KineticJS
function drawBezierCurve() {
var centerLeft = new Object();
centerLeft.x = 100;
centerLeft.y = 400;
var centerRight = new Object();
centerRight.x = 400;
centerRight.y = 100;
var thicknessLeft = 1;
var thicknessRight = 50;
var color = "#000";
var context = mainLayer.getContext();
var leftUpper = {
x: centerLeft.x,
y: centerLeft.y - thicknessLeft / 2
};
var leftLower = {
x: centerLeft.x,
y: leftUpper.y + thicknessLeft
};
var rightUpper = {
x: centerRight.x,
y: centerRight.y - thicknessRight / 2
};
var rightLower = {
x: centerRight.x,
y: rightUpper.y + thicknessRight
};
var center = (centerRight.x + centerLeft.x) / 2;
var cp1Upper = {
x: center,
y: leftUpper.y
};
var cp2Upper = {
x: center,
y: rightUpper.y
};
var cp1Lower = {
x: center,
y: rightLower.y
};
var cp2Lower = {
x: center,
y: leftLower.y
};
var bezierCurve = new Kinetic.Shape({
drawFunc: function (canvas) {
var context = mainLayer.getContext();
context.fillStyle = color;
context.beginPath();
context.moveTo(leftUpper.x, leftUpper.y);
context.bezierCurveTo(cp1Upper.x, cp1Upper.y, cp2Upper.x, cp2Upper.y, rightUpper.x, rightUpper.y);
context.lineTo(rightLower.x, rightLower.y);
context.bezierCurveTo(cp1Lower.x, cp1Lower.y, cp2Lower.x, cp2Lower.y, leftLower.x, leftLower.y);
context.lineTo(leftUpper.x, leftUpper.y);
context.fill();
canvas.stroke(this);
},
fill: color,
stroke: color,
strokeWidth: 1
});
bezierCurve.on('mouseover', function (evt) {
document.body.style.cursor = "pointer";
$("#debug").html("MOUSEOVER DETECTED."); //<==NEVER CALLED
});
bezierCurve.on('mouseout', function (evt) {
document.body.style.cursor = "default";
$("#debug").html("MOUSEOUT DETECTED."); //NEVER CALLED
});
bezierCurve.setAttrs({
'leftUpper': leftUpper,
'leftLower': leftLower,
'rightUpper': rightUpper,
'rightLower': rightLower,
'cp1Upper': cp1Upper,
'cp2Upper': cp2Upper,
'cp1Lower': cp1Lower,
'cp2Lower': cp2Lower
});
mainLayer.add(bezierCurve);
mainLayer.draw();
$("#debug").html("bezier curve has been drawn onscreen.");
}
$(document).ready(function () {
var stage = new Kinetic.Stage({
container: 'canvasContainer',
width: 500,
height: 500
});
mainLayer = new Kinetic.Layer('main');
stage.add(mainLayer);
mainLayer.draw();
drawBezierCurve();
});
Can you define it as an SVG element, and just give that an onmouseover?
Fixed it! Changes are shown at the jsFiddle link in the original post.
//FIXED!
//OLD VERSION: DOES NOT WORK
// var bezierCurve = new Kinetic.Shape({
// drawFunc: function (canvas) {
// var context = mainLayer.getContext();
// context.fillStyle = color;
// context.beginPath();
// context.moveTo(leftUpper.x, leftUpper.y);
// context.bezierCurveTo(cp1Upper.x, cp1Upper.y, cp2Upper.x, cp2Upper.y, rightUpper.x, rightUpper.y);
// context.lineTo(rightLower.x, rightLower.y);
// context.bezierCurveTo(cp1Lower.x, cp1Lower.y, cp2Lower.x, cp2Lower.y, leftLower.x, leftLower.y);
// context.lineTo(leftUpper.x, leftUpper.y);
// context.closePath();
// context.fill();
// canvas.stroke(this);
// },
// fill: color,
// stroke: color,
// strokeWidth: 1
// });
//NEW VERSION: WORKS!
var bezierCurve = new Kinetic.Shape({
drawFunc: function (canvas) {
var context = canvas.getContext('2d');
context.beginPath();
context.moveTo(leftUpper.x, leftUpper.y);
context.bezierCurveTo(cp1Upper.x,cp1Upper.y, cp2Upper.x,cp2Upper.y, rightUpper.x,rightUpper.y);
context.lineTo(rightLower.x, rightLower.y);
context.bezierCurveTo(cp1Lower.x,cp1Lower.y, cp2Lower.x,cp2Lower.y, leftLower.x,leftLower.y);
context.lineTo(leftUpper.x, leftUpper.y);
context.fill();
canvas.stroke(this);
},
fill: color,
stroke: color,
strokeWidth: 3
});

Capturing the mouse coordinates on every step of a jQuery animation

I'm trying to get the mouse coordinates during a jQuery animation, I'm doing this because I'm working on an interactive plug-in which moves the background image inside a div from covercss property to 100% of it's scale when the user go over the element.
I'm near to completing the plug-in but the animation is buggy because it work on the last position of the mouse fired by mousemove event of jQuery.
Does exists some way to avoid the problem?
This is my situation:
$(settings.selector).hover(function (e) {
$(this).bind('mousemove', setFollowMouse);
}, function () {
$(this).unbind('mousemove', setFollowMouse);
zoomOut();
});
var setFollowMouse = function (e) {
var o = {offsetLeft:this.offsetLeft, offsetTop:this.offsetTop};
if (!settings.bg.zooming_in && settings.bg.current_scale != 100) {
settings.bg.zooming_in = true;
zoomIn(e, o);
} else {
followMouse(e, o);
}
}
var zoomIn = function (e, o) {
$({scale:settings.bg.min_perc}).animate ({
scale:100
},{
easing:settings.zoom_in.easing,
duration:settings.zoom_in.duration,
step:function () {
settings.bg.current_scale = this.scale;
followMouse(e, o);
},
complete:function () {
settings.bg.current_scale = 100;
settings.bg.zooming_in = false;
followMouse(e, o);
}
});
}
var followMouse = function (e, o) {
var m_x = e.pageX - o.offsetLeft;
var m_y = e.pageY - o.offsetTop;
settings.bg.perc_pos_x = ((m_x * 100) / (a_w - bg_w)) + '%';
settings.bg.perc_pos_y = ((m_y * 100) / (a_h - bg_h)) + '%';
var bg_w = getScalePercent(settings.bg.width, settings.bg.current_scale);
var a_w = settings.container.width;
var bg_h = getScalePercent(settings.bg.height, settings.bg.current_scale);
var a_h = settings.container.height;
var bpx = - (bg_w - a_w) * m_x / a_w;
var bpy = - (bg_h - a_h) * m_y / a_h;
$(settings.selector).css({
backgroundPosition:bpx + 'px ' + bpy + 'px'
,backgroundSize:bg_w + 'px ' + bg_h + 'px'
});
}
As you see, I use animation to calculate the progressive scaling of the background-image, and trying to calculating it with the follow mouse method, but if I sto moving the mouse, the animation works with the last mousemove event.pageX and Y mouse position.
I've done this because I have problems with make animation method fluid if I trying to rewrite it continuously by with the mouse.
Should I follow some different way to avoid the bug?
forgive my dodgy math; but this should help!
<html>
<head>
<script type="text/javascript" charset="utf-8">
window.onload = function () {
var img = new Image();
img.src = 'http://wallpapers.free-review.net/wallpapers/23/Autumn_Theme_-_Windows_7_Backgrounds.jpg';
var canvas = document.getElementById("canvas1");
canvas.width = img.width;
canvas.height = img.height;
canvas.addEventListener('mousemove', onMouseMove, false);
var ctx = canvas.getContext("2d");
var scale = 0.9;
var scaledwidth = canvas.width * scale;
var scaledheight = canvas.height * scale;
var scaledcenterX = scaledwidth /2;
var scaledcenterY = scaledheight /2;
var animloop = setInterval(function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, scaledwidth, scaledheight, canvas.width - scaledcenterX, canvas.height - scaledcenterY, 0, 0, canvas.width, canvas.height);
}, .01);
function onMouseMove(e) {
mouseX = e.clientX - canvas.offsetLeft;
mouseY = e.clientY - canvas.offsetTop;
scale = mouseX/1000;
scaledwidth = canvas.width * scale;
scaledheight = canvas.height * scale;
}
};
</script>
<style>
body {
background: #001;
background-size: cover;
overflow: hidden;
}
#canvas1 {
position: absolute;
top: 0;
left: 0;
padding: 0;
margin: 0;
height: 100% auto;
}
</style>
</head>
<body>
<canvas id="canvas1"></canvas>
</body>
</html>
I've just solved the problem with this simple edit to my code:
var setFollowMouse = function (e) {
settings.mouse.x = e.pageX - this.offsetLeft;
settings.mouse.y = e.pageY - this.offsetTop;
if (!settings.bg.zooming_in && settings.bg.current_scale != 100) {
settings.bg.zooming_in = true;
zoomIn();
} else {
followMouse();
}
}
the old one:
var setFollowMouse = function (e) {
var o = {offsetLeft:this.offsetLeft, offsetTop:this.offsetTop};
if (!settings.bg.zooming_in && settings.bg.current_scale != 100) {
settings.bg.zooming_in = true;
zoomIn(e, o);
} else {
followMouse(e, o);
}
}
this has removed the buggy behavior.

Resources