I'm trying to make a canvas which can be operated via the mouse (dragging, drawing, clicking...), which would seem to be a simple task. Currently I have it drawing a line from where the mouse was pressed to where ever it is now, until it is released. But all the old versions of the line continue to be drawn regardless of whether I clear the canvas. I've tried using beginPath/closePath and fill instead of stroke; both approaches caused the line to never appear. Is there some... "delimiter" of draw operations that I haven't been able to find?
The source may be viewed and tested here, and I've also included it below.
<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
</head>
<body>
<canvas id="test" width="640" height="480"></canvas>
<script type="text/javascript">
(function (){
// http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
function getMousePos(obj, evt){
// get canvas position
var top = 0;
var left = 0;
while (obj && obj.tagName != 'BODY') {
top += obj.offsetTop;
left += obj.offsetLeft;
obj = obj.offsetParent;
}
// return relative mouse position
var mouseX = evt.clientX - left + window.pageXOffset;
var mouseY = evt.clientY - top + window.pageYOffset;
return {
x: mouseX,
y: mouseY
};
}
var canvasElement = document.getElementById('test');
if(canvasElement.getContext){
var canvas = canvasElement.getContext('2d');
var start = null;
var end = null;
var drawing = false;
canvasElement.addEventListener('mousedown', function (event){
var mousePos = getMousePos(canvasElement, event);
start = mousePos;
end = mousePos;
drawing = true;
}, false);
canvasElement.addEventListener('mousemove', function (event){
if(drawing){
end = getMousePos(canvasElement, event);
}
}, false);
function release(event){
drawing = false;
}
canvasElement.addEventListener('mouseup', release, true);
var FPS = 30;
setInterval(function() {
canvas.clearRect(0, 0, canvasElement.width, canvasElement.height);
if(drawing && start != null){
canvas.moveTo(start.x, start.y);
canvas.lineTo(end.x, end.y);
canvas.stroke();
}
}, 1000/FPS);
}
})();
</script>
</body>
</html>
You need to create a path with beginPath and closePath, like so:
canvas.clearRect(0, 0, canvasElement.width, canvasElement.height);
if(drawing && start != null){
canvas.beginPath();
canvas.moveTo(start.x, start.y);
canvas.lineTo(end.x, end.y);
canvas.closePath();
canvas.stroke();
}
Otherwise you'll just keep adding lines to the existing path.
Related
I'm trying to implement a slider in a canvas using p5.js. If there are no HTML elements in the body of the webpage, then the canvas and the slider are on the top-left corner of the webpage.
However, when I change the position of the canvas, the slider does not stay inside the canvas. The position method sets the position of the slider ABSOLUTE with respect to the webpage.
How do I set the position of the slider inside the canvas?
This is the bare-minimum code to replicate the issue.
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>p5.js example</title>
<style> body {padding: 0; margin: 0;} </style>
<script src="../p5.min.js"></script>
<script src="../addons/p5.dom.min.js"></script>
<script src="../addons/p5.sound.min.js"></script>
<script src="sketch.js"></script>
</head>
<body>
<div>
<p><object width="150" height="150" vspace="100"></object>
This is some text. This is some text. This is some text.</p>
</div>
</body>
</html>
The sketch.js file is:
var slider;
function setup() {
slider = createSlider(0, 255, 100);
slider.position(10, 10);
slider.style('width', '80px');
}
function draw() {
var val = slider.value();
background(val);
}
p5.js' createSlider() function creates an <input /> range HTML element which is different from the <canvas/> element it uses to render the other methods.
You could use absolute positioning in tandem with z-index to have the canvas with a lower z-index and the slider with a higher z-index (on top of the canvas), both with the absolute positions you need.
If you really do want the slider rendered inside the canvas element you could roll your own slider class using the p5.js drawing functions and mouse/touch events, but it wouldn't be as CPU efficient as using an <input /> range HTML element.
Here is the Processing > Examples > Topics > GUI > Scrollbar example ported to p5.js:
/**
* Scrollbar.
*
* Move the scrollbars left and right to change the positions of the images.
*/
let slider;
function setup() {
createCanvas(640, 360);
noStroke();
slider = new HScrollbar(0, height/2-8, width, 16, 16);
}
function draw() {
background(255);
fill(0);
text("slider position: " + slider.getPos().toFixed(2),width/2,height/3);
slider.update();
slider.display();
}
class HScrollbar {
constructor(xp, yp, sw, sh, l) {
this.swidth = sw;
this.sheight = sh;
let widthtoheight = sw - sh;
this.ratio = sw / widthtoheight;
this.xpos = xp;
this.ypos = yp-this.sheight/2;
this.spos = this.xpos + this.swidth/2 - this.sheight/2;
this.newspos = this.spos;
this.sposMin = this.xpos;
this.sposMax = this.xpos + this.swidth - this.sheight;
this.loose = l;
this.over = false;
this.locked = false;
}
update() {
if (this.overEvent()) {
this.over = true;
} else {
this.over = false;
}
if (mouseIsPressed && this.over) {
this.locked = true;
}
if (!mouseIsPressed) {
this.locked = false;
}
if (this.locked) {
this.newspos = constrain(mouseX-this.sheight/2, this.sposMin, this.sposMax);
}
if (abs(this.newspos - this.spos) > 1) {
this.spos = this.spos + (this.newspos-this.spos)/this.loose;
}
}
overEvent() {
if (mouseX > this.xpos && mouseX < this.xpos+this.swidth &&
mouseY > this.ypos && mouseY < this.ypos+this.sheight) {
return true;
} else {
return false;
}
}
display() {
noStroke();
fill(204);
rect(this.xpos, this.ypos, this.swidth, this.sheight);
if (this.over || this.locked) {
fill(0, 0, 0);
} else {
fill(102, 102, 102);
}
rect(this.spos, this.ypos, this.sheight, this.sheight);
}
getPos() {
// Convert spos to be values between
// 0 and the total width of the scrollbar
return this.spos * this.ratio;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.min.js"></script>
Please, check this:
CSlider - Canvas Slider for p5.js with scale() support, mostly supported standard p5 slider calls:
https://editor.p5js.org/Comissar/sketches/IHUYuzjR
I want to give my users an easy way to visually trace a route on a map or a picture. The solution must let the users add control points that they can use to put bends into the route.
It should work with html5 canvas - I currently use the Konvajs library so a solution that uses this would be good.
In the interests of sharing & learning, if you can suggest solutions using other HTML5 canvas libraries that would be good to see too.
Note: This is not the original question posed. However it emerged over time that this was the actual requirement. The OP asked for means to find an arbitrary point part way along a line / curve in an HTML5 canvas so that a draggable control point could be added at that point to edit the line / curve. The accepted answer does not meet this need. However, an answer to this original question would involve serious collision-detection math and potentially use of bezier control points - in other words it would be a big ask whilst the accepted answer is a very approachable solution with consistent UX.
The original question can be seen in via the edit links below this question.
How about this idea. You click where you want the next point and the route line extends with new positioning handles along the line segments. If you need arrows you can extend the objects herein as you require. You can easily change colours, stroke width, circle opacity etc with attributes of the route class. The points are available in an array and in the standard Konva.js line points list. The JS is vanilla, no other libraries needed or used.
The Export button shows how to grab the (x,y) fixed point objects for export purposes.
Example video here, working code in below snippet.
// Set up the canvas / stage
var s1 = new Konva.Stage({container: 'container1', width: 600, height: 300});
// Add a layer for line
var lineLayer = new Konva.Layer({draggable: false});
s1.add(lineLayer);
// Add a layer for drag points
var pointLayer = new Konva.Layer({draggable: false});
s1.add(pointLayer);
// Add a rectangle to layer to catch events. Make it semi-transparent
var r = new Konva.Rect({x:0, y: 0, width: 600, height: 300, fill: 'black', opacity: 0.1})
pointLayer.add(r)
// Everything is ready so draw the canvas objects set up so far.
s1.draw()
// generic canvas end
// Class for the draggable point
// Params: route = the parent object, opts = position info, doPush = should we just make it or make it AND store it
var DragPoint = function(route, opts, doPush){
var route = route;
this.x = opts.x;
this.y = opts.y;
this.fixed = opts.fixed;
this.id = randId(); // random id.
if (doPush){ // in some cases we want to create the pt then insert it in the run of the array and not always at the end
route.pts.push(this);
}
// random id generator
function randId() {
return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(2, 10);
}
// mark the pt as fixed - important state, shown by filled point
this.makeFixed = function(){
this.fixed = true;
s1.find('#' + this.id)
.fill(route.fillColor);
}
this.kill = function(){
s1.find('#' + this.id)
.remove();
}
this.draw = function(){
// Add point & pt
var circleId = this.id;
var pt = new Konva.Circle({
id: circleId,
x: this.x,
y: this.y,
radius: route.pointRadius,
opacity: route.pointOpacity,
strokeWidth: 2,
stroke: route.strokeColor,
fill: 'transparent',
draggable: 'true'
})
pt.on('dragstart', function(){
route.drawState = 'dragging';
})
pt.on('dragmove', function(){
var pos = this.getPosition();
route.updatePt(this.id(), pos)
route.calc(this.id());
route.draw();
})
pt.on('dragend', function(){
route.drawState = 'drawing';
var pos = this.getPosition();
route.updatePt(this.getId(), pos);
route.splitPts(this.getId());
route.draw();
})
if (this.fixed){
this.makeFixed();
}
route.ptLayer.add(pt);
route.draw();
}
}
var Route = function() {
this.lineLayer = null;
this.ptLayer = null;
this.drawState = '';
this.fillColor = 'Gold';
this.strokeColor = 'Gold';
this.pointOpacity = 0.5;
this.pointRadius = 10;
this.color = 'LimeGreen';
this.width = 5;
this.pts = []; // array of dragging points.
this.startPt = null;
this.endPt = null;
// reset the points
this.reset = function(){
for (var i = 0; i < this.pts.length; i = i + 1){
this.pts[i].kill();
}
this.pts.length = 0;
this.draw();
}
// Add a point to the route.
this.addPt = function(pos, isFixed){
if (this.drawState === 'dragging'){ // do not add a new point because we were just dragging another
return null;
}
this.startPt = this.startPt || pos;
this.endPt = pos;
// create this new pt
var pt = new DragPoint(this, {x: this.endPt.x, y: this.endPt.y, fixed: isFixed}, true, "A");
pt.draw();
pt.makeFixed(); // always fixed for manual points
// if first point ignore the splitter process
if (this.pts.length > 0){
this.splitPts(pt.id, true);
}
this.startPt = this.endPt; // remember the last point
this.calc(); // calculate the line points from the array
this.draw(); // draw the line
}
// Position the points.
this.calc = function (draggingId){
draggingId = (typeof draggingId === 'undefined' ? '---' : draggingId); // when dragging an unfilled point we have to override its automatic positioning.
for (var i = 1; i < this.pts.length - 1; i = i + 1){
var d2 = this.pts[i];
if (!d2.fixed && d2.id !== draggingId){ // points that have been split are fixed, points that have not been split are repositioned mid way along their line segment.
var d1 = this.pts[i - 1];
var d3 = this.pts[i + 1];
var pos = this.getHalfwayPt(d1, d3);
d2.x = pos.x;
d2.y = pos.y;
}
s1.find('#' + d2.id).position({x: d2.x, y: d2.y}); // tell the shape where to go
}
}
// draw the line
this.draw = function (){
if (this.drawingLine){
this.drawingLine.remove();
}
this.drawingLine = this.newLine(); // initial line point
for (var i = 0; i < this.pts.length; i = i + 1){
this.drawingLine.points(this.drawingLine.points().concat([this.pts[i].x, this.pts[i].y]))
}
this.ptLayer.draw();
this.lineLayer.draw();
}
// When dragging we need to update the position of the point
this.updatePt = function(id, pos){
for (var i = 0; i < this.pts.length; i = i + 1){
if (this.pts[i].id === id){
this.pts[i].x = pos.x;
this.pts[i].y = pos.y;
break;
}
}
}
// Function to add and return a line object. We will extend this line to give the appearance of drawing.
this.newLine = function(){
var line = new Konva.Line({
stroke: this.color,
strokeWidth: this.width,
lineCap: 'round',
lineJoin: 'round',
tension : .1
});
this.lineLayer.add(line)
return line;
}
// make pts either side of the split
this.splitPts = function(id, force){
var idx = -1;
// find the pt in the array
for (var i = 0; i < this.pts.length; i = i + 1){
if (this.pts[i].id === id){
idx = i;
if (this.pts[i].fixed && !force){
return null; // we only split once.
}
//break;
}
}
// If idx is -1 we did not find the pt id !
if ( idx === -1){
return null
}
else if (idx === 0 ) {
return null
}
else { // pt not = 0 or max
// We are now going to insert a new pt either side of the one we just dragged
var d1 = this.pts[idx - 1]; // previous pt to the dragged pt
var d2 = this.pts[idx ]; // the pt pt
var d3 = this.pts[idx + 1]; // the next pt after the dragged pt
d2.makeFixed()// flag this pt as no longer splittable
// get point midway from prev pt and dragged pt
var pos = this.getHalfwayPt(d1, d2);
var pt = new DragPoint(this, {x: pos.x, y: pos.y, foxed: false}, false, "C");
pt.draw();
this.pts.splice(idx, 0, pt);
if (d3){
// get point midway from dragged pt to next
pos = this.getHalfwayPt(d2, d3);
var pt = new DragPoint(this, {x: pos.x, y: pos.y, foxed: false}, false, "D");
pt.draw();
this.pts.splice(idx + 2, 0, pt); // note idx + 2 !
}
}
}
// convert last point array entry to handy x,y object.
this.getPoint = function(pts){
return {x: pts[pts.length - 2], y: pts[pts.length - 1]};
}
this.getHalfwayPt = function(d1, d2){
var pos = {
x: d1.x + (d2.x - d1.x)/2,
y: d1.y + (d2.y - d1.y)/2
}
return pos;
}
this.exportPoints = function(){
var list = [], pt;
console.log('pts=' + this.pts.length)
for (var i = 0; i < this.pts.length; i = i + 1){
pt = this.pts[i]
if (pt.fixed){
console.log('push ' + i)
list.push({x: pt.x, y: pt.y});
}
}
return list;
}
}
var route = new Route();
route.lineLayer = lineLayer;
route.ptLayer = pointLayer;
route.fillColor = 'AliceBlue';
route.strokeColor = 'Red';
route.pointOpacity = 0.5;
route.pointRadius = 7;
route.color = '#2982E8'
// Listen for mouse up on the stage to know when to draw points
s1.on('mouseup touchend', function () {
route.addPt(s1.getPointerPosition(), true);
});
// jquery is used here simply as a quick means to make the buttons work.
// Controls for points export
$('#export').on('click', function(){
if ($(this).html() === "Hide"){
$(this).html('Export');
$('#points').hide();
}
else {
$(this).html('Hide');
$('#points')
.css('display', 'block')
.val(JSON.stringify(route.exportPoints()));
}
})
// reset button
$('#reset').on('click', function(){
route.reset();
})
p
{
padding: 4px;
}
#container1
{
background-image: url('https://i.stack.imgur.com/gADDJ.png');
}
#ctrl
{
position: absolute;
z-index: 10;
margin: 0px;
border: 1px solid red;
}
#points
{
width: 500px;
height: 100px;
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/konvajs/konva/1.6.5/konva.min.js"></script>
<p>Click to add a point, click to add another, drag a point to make a bend, etc.
</p>
<div id='ctrl'>
<button id='reset'>Reset</button>
<button id='export'>Export</button>
<textarea id='points'></textarea>
</div>
<div id='container1' style="display: inline-block; width: 300px, height: 200px; background-color: silver; overflow: hidden; position: relative;"></div>
<div id='img'></div>
I have n+1 hexshapes in a honeycomb grid. The objects are stacked close together. With this code:
// Get intersected objects, a.k.a objects "hit" by mouse, a.k.a objects that are mouse-overed
const intersects = raycaster.intersectObjects(hexObjects);
// If there is one (or more) intersections
let scaleTween = null;
if (intersects.length > 0) {
// If mouse is not currently over an object
// Set cursor to pointer so that the user can see that the object is clickable
document.body.style.cursor = 'pointer';
// Get the last intersected object, it's most likely that object we are currently hovering
const is = intersects.length > 0 ? intersects.length - 1 : 0;
// Is the object hovered over for the first time?
if (INTERSECTED === null) {
// Save current hovered object
INTERSECTED = intersects[is].object;
// HIGHLIGHT
// Save current color
INTERSECTED.currentHex = INTERSECTED.material.color.getHex();
// Set highlight color
INTERSECTED.material.color.setHex(COLOR_HIGHLIGHT);
// SCALE UP
// Try to stop the current tween, if any, in progress, so we can proceed with the next, if any, tween
try {
scaleTween.stop();
} catch (e) {}
// Create tween, save it so we can try to stop it, if needed
scaleTween = scale_tween(
INTERSECTED,
INTERSECTED.scale.clone(),
{
x: 1.5,
y: 1.5
},
100
);
scaleTween.start();
// SET Z-INDEX
INTERSECTED.position.z = 10;
} else {
// If the mouse is over an object
// Do we have a previous hovered item?
if (INTERSECTED !== null) {
// Revert color
INTERSECTED.material.color.setHex(INTERSECTED.currentHex);
// SCALE DOWN
// Try to stop the current tween, if any, in progress, so we can proceed with the next, if any, tween
try {
scaleTween.stop();
} catch (e) {}
// Create tween, save it so we can try to stop it, if needed
scaleTween = scale_tween(
INTERSECTED,
INTERSECTED.scale.clone(),
{
x: 1,
y: 1
},
100
);
scaleTween.start();
// REVERT Z-INDEX
INTERSECTED.position.z = 1;
}
// Save current intersected object
INTERSECTED = intersects[is].object;
// HIGHLIGHT
// Save current color
INTERSECTED.currentHex = INTERSECTED.material.color.getHex();
// Set highlight color
INTERSECTED.material.color.setHex(COLOR_HIGHLIGHT);
// SCALE UP
// Try to stop the current tween, if any, in progress, so we can proceed with the next, if any, tween
try {
scaleTween.stop();
} catch (e) {}
// Create tween, save it so we can try to stop it, if needed
scaleTween = scale_tween(
INTERSECTED,
INTERSECTED.scale.clone(),
{
x: 1.5,
y: 1.5
},
100
);
scaleTween.start();
// SET Z-INDEX
INTERSECTED.position.z = 10;
}
} else {
// If there are no intersections
// Reset cursor
document.body.style.cursor = 'default';
// Restore previous intersection object (if it exists) to its original color
if (INTERSECTED !== null) {
// REVERT COLOR
INTERSECTED.material.color.setHex(INTERSECTED.currentHex);
// SCALE DOWN
// Try to stop the current tween, if any, in progress, so we can proceed with the next, if any, tween
try {
scaleTween.stop();
} catch (e) {}
// Create tween, save it so we can try to stop it, if needed
scaleTween = scale_tween(
INTERSECTED,
INTERSECTED.scale.clone(),
{
x: 1,
y: 1
},
100
);
scaleTween.start();
// REVERT "Z-INDEX"
INTERSECTED.position.z = 1;
}
// Remove previous intersection object reference by setting current intersection object to "nothing"
INTERSECTED = null;
}
I've managed to highlight the object and scale it up with a tween quite nicely, but when I move the mouse out of the object onto the next object (the scaled object is scaled over the next object a bit), the highlight is gone, but the scale persists. How do I manage to scale the object down? And preferably with a tween?
A pen for this code can be found here: https://codepen.io/phun-ky/pen/erBZZy, the relevant part is at about line 1284 or search for INTERSECTED.
I wrote my own one. It's hell imperfect, but, at least, it scales up and down the hexagons:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 10);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x101010);
document.body.appendChild(renderer.domElement);
var hexes = [];
var colCount = 5;
var rowCount = 4;
var hexDiameter = 3;
var xStart = -(colCount) * hexDiameter * 0.5;
var rowSpace = Math.sqrt(3) * hexDiameter * 0.5;
var yStart = (rowCount - 1) * rowSpace * 0.5;
var hexGeom = new THREE.CylinderGeometry(hexDiameter * 0.5, hexDiameter * 0.5, 0.0625, 6, 1);
hexGeom.rotateX(Math.PI * 0.5);
for (let j = 0; j < rowCount; j++) {
for (let i = 0; i < colCount + (j % 2 === 0 ? 0 : 1); i++) {
let hex = new THREE.Mesh(hexGeom, new THREE.MeshBasicMaterial({
color: Math.random() * 0x7e7e7e + 0x7e7e7e,
wireframe: false
}));
hex.position.set(xStart + i * hexDiameter + (j % 2 === 0 ? 0.5 * hexDiameter : 0), yStart - j * rowSpace, 0);
hex.userData.scaleUp = function(h) {
if (h.userData.scaleDownTween) h.userData.scaleDownTween.stop();
let initScale = h.scale.clone();
let finalScale = new THREE.Vector3().setScalar(2);
h.userData.scaleUpTween = new TWEEN.Tween(initScale).to(finalScale, 500).onUpdate(function(obj) {
h.scale.copy(obj)
}).start();
}
hex.userData.scaleDown = function(h) {
if (h.userData.scaleUpTween) h.userData.scaleUpTween.stop();
let initScale = h.scale.clone();
let finalScale = new THREE.Vector3().setScalar(1);
h.userData.scaleUpTween = new TWEEN.Tween(initScale).to(finalScale, 500).onUpdate(function(obj) {
h.scale.copy(obj)
}).start();
}
scene.add(hex);
hexes.push(hex);
}
}
window.addEventListener("mousemove", onMouseMove, false);
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var intersects = [];
var intersected;
function onMouseMove(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
intersects = raycaster.intersectObjects(hexes);
if (intersects.length > 0) {
if (intersected != intersects[0].object) {
if (intersected) intersected.userData.scaleDown(intersected);
intersected = intersects[0].object;
intersected.userData.scaleUp(intersected);
}
} else {
if (intersected) intersected.userData.scaleDown(intersected);
intersected = null;
}
}
render();
function render() {
requestAnimationFrame(render);
TWEEN.update();
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.2.0/Tween.min.js"></script>
How can I use HTML5 canvas to simply connect two dots with one line using mouse? where I would click on the first dot and drag the mouse creating a line until it connects to the second dot.
I have been using x/y offset to follow the mouse but drawing a line is where I need help in.
Data array is the two dots
$scope.data = [
[192,27]
,[183,55]
];
function drawDot(event) {
if(dragging){
context.lineTo(event.offsetX, event.offsetY);
context.stroke();
context.beginPath();
context.arc(event.offsetX, event.offsetY,5, 0, Math.PI*2);
context.fill();
context.beginPath();
context.moveTo(event.offsetX, event.offsetY);
}
}
function engage(){
dragging = true;
drawDot(event);
}
function disengage(){
dragging = false;
context.beginPath();
}
function init(){
canvas.addEventListener("mousedown",engage);
canvas.addEventListener("mouseup",disengage);
canvas.addEventListener("mousemove",drawDot,false);
}
I am seeing a few things wrong here. Look at my example. I believe that is what you are looking for.
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d")
var startX = 0;
var startY = 0;
function drawDot(event) {
if(dragging){
context.clearRect(0,0,canvas.width, canvas.height)
context.beginPath();
context.moveTo(startX, startY);
context.lineTo(event.offsetX, event.offsetY);
context.arc(event.offsetX, event.offsetY,5, 0, Math.PI*2);
context.stroke();
context.closePath();
}
}
function engage(event){
dragging = true;
startX = event.offsetX;
startY = event.offsetY;
}
function disengage(){
dragging = false;
}
canvas.addEventListener("mousedown",engage);
canvas.addEventListener("mouseup",disengage);
canvas.addEventListener("mousemove",drawDot,false);
<canvas id="canvas" style="margin: 10px; background: blue"></canvas>
Hello I am new to jQuery and I have a problem!
I want to scroll to the top, in a page that is loaded via AJAX call.
This works (test):
$(document).on('click', '#top_icon', function() {
alert('ok');
});
But this is not working (this is what I want to achieve):
$(document).on('click', '#top_icon', function() {
$('html, body').animate({scrollTop: '0px'}, 800);
});
Try this,
$(document).on('click', '#top_icon', function() {
$('html, body').animate({'scrollTop': '0px'}, 800);
return false;
});
scrollTop is undefined in your case.
I am not sure about jQuery, but scrollTop is not a CSS property and therefor might not be part of the properties that can be animated.
But you can create a simple animation for this yourself:
var startValue = 0;
var endValue = 0;
var duration = 800;
var distance = 0;
var velocity = 0;
var step = 0;
var endTime = 0;
var animate = function() {
var elapsedTime = new Date().getTime() - step;
document.body.scrollTop += velocity * elapsedTime;
step = new Date().getTime();
if (step > endTime)
document.body.scrollTop = endValue;
else
setTimeout(animate, 15);
}
yourButton.onclick = function() {
startValue = document.body.scrollTop;
distance = endValue - startValue;
velocity = distance / duration;
step = new Date().getTime();
endTime = step + duration;
animate();
};
Here is a fiddle: http://jsfiddle.net/pXvQG/12/, animate by scrolling down and click the body.