Canvas request animation out of frame on slider input to javascript variable
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
I have a canvas element. It draws some lines, based on art vanishing points.
I'm trying to draw a house (for now its just a box) from a single vanishing point. The size of the box is dictated by a delta
variable. If I change the value manually, it does this:
I wanted to have a slider that changes the delta
variable. But I get some really weird effects. Namely lines are drawn out of frame to the right. I dumped console.log statements everywhere but I still cannot find the problem (how does one even debug canvas issues?)
var canvas = document.querySelector("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.width = 1600;
canvas.height = 800;
var ct = canvas.getContext("2d");
// TODO
// 1. Make a center point
// 2. Draw lines jutting from center
// 3. Draw a line parallel to canvas bottom
// 4. Draw an adjoining item upward
// x, y
// right, down
// Nomenclature
// x0a
// coordinate type, vanishingPt#, endPtName
// Vanishing point 0
var x0 = 400;
var y0 = 400;
// Vanishing point end 0a
var x0a = 0;
var y0a = 2 * y0;
// Vanishing point end 0b
var x0b = 2 * x0;
var y0b = 2 * y0;
// Define delta
var delta = 700;
function init() {
console.log(delta, "delta");
console.log(x0b, "x0b");
console.log(y0b, "y0b");
console.log(x0, "x0");
console.log(y0, "y0");
// First Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0a, y0a);
ct.strokeStyle = 'red';
ct.stroke();
// Second Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0b, x0b);
ct.strokeStyle = 'green';
ct.stroke();
// House based on second Line
ct.beginPath();
ct.moveTo(x0b, y0b); // starting point
ct.lineTo(x0b + delta, y0b); // right x+100
ct.lineTo(x0b + delta, y0b - delta); // up y-100
ct.lineTo(x0b, y0b - delta); // left x-100
ct.lineTo(x0b, y0b); // down y+100
ct.lineTo(x0b, y0b - delta); // back up y-100
//calculate
ct.lineTo(x0, y0);
ct.lineTo(x0b + delta, y0b - delta);
ct.strokeStyle = 'blue';
ct.stroke();
}
init();
var slider = document.getElementById("myRange");
slider.oninput = function () {
delta = this.value;
requestAnimationFrame(init()); // redraw everything
}
body {
background-color: lightgray;
display: flex;
justify-content: center;
align-items: center;
}
.slideContainer {
position: fixed;
right: 30px;
top: 30px;
background-color: lightblue;
z-index: 20;
}
canvas {
border: 1px dotted red;
padding: 80px;
background-color: lightgray;
transform: scale(0.5);
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="wrapper">
<div class="slideContainer">
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
</div>
<canvas id="canvas"></canvas>
</div>
<script src="script.js"></script>
</body>
</html>
javascript html css canvas html5-canvas
add a comment |
I have a canvas element. It draws some lines, based on art vanishing points.
I'm trying to draw a house (for now its just a box) from a single vanishing point. The size of the box is dictated by a delta
variable. If I change the value manually, it does this:
I wanted to have a slider that changes the delta
variable. But I get some really weird effects. Namely lines are drawn out of frame to the right. I dumped console.log statements everywhere but I still cannot find the problem (how does one even debug canvas issues?)
var canvas = document.querySelector("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.width = 1600;
canvas.height = 800;
var ct = canvas.getContext("2d");
// TODO
// 1. Make a center point
// 2. Draw lines jutting from center
// 3. Draw a line parallel to canvas bottom
// 4. Draw an adjoining item upward
// x, y
// right, down
// Nomenclature
// x0a
// coordinate type, vanishingPt#, endPtName
// Vanishing point 0
var x0 = 400;
var y0 = 400;
// Vanishing point end 0a
var x0a = 0;
var y0a = 2 * y0;
// Vanishing point end 0b
var x0b = 2 * x0;
var y0b = 2 * y0;
// Define delta
var delta = 700;
function init() {
console.log(delta, "delta");
console.log(x0b, "x0b");
console.log(y0b, "y0b");
console.log(x0, "x0");
console.log(y0, "y0");
// First Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0a, y0a);
ct.strokeStyle = 'red';
ct.stroke();
// Second Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0b, x0b);
ct.strokeStyle = 'green';
ct.stroke();
// House based on second Line
ct.beginPath();
ct.moveTo(x0b, y0b); // starting point
ct.lineTo(x0b + delta, y0b); // right x+100
ct.lineTo(x0b + delta, y0b - delta); // up y-100
ct.lineTo(x0b, y0b - delta); // left x-100
ct.lineTo(x0b, y0b); // down y+100
ct.lineTo(x0b, y0b - delta); // back up y-100
//calculate
ct.lineTo(x0, y0);
ct.lineTo(x0b + delta, y0b - delta);
ct.strokeStyle = 'blue';
ct.stroke();
}
init();
var slider = document.getElementById("myRange");
slider.oninput = function () {
delta = this.value;
requestAnimationFrame(init()); // redraw everything
}
body {
background-color: lightgray;
display: flex;
justify-content: center;
align-items: center;
}
.slideContainer {
position: fixed;
right: 30px;
top: 30px;
background-color: lightblue;
z-index: 20;
}
canvas {
border: 1px dotted red;
padding: 80px;
background-color: lightgray;
transform: scale(0.5);
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="wrapper">
<div class="slideContainer">
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
</div>
<canvas id="canvas"></canvas>
</div>
<script src="script.js"></script>
</body>
</html>
javascript html css canvas html5-canvas
add a comment |
I have a canvas element. It draws some lines, based on art vanishing points.
I'm trying to draw a house (for now its just a box) from a single vanishing point. The size of the box is dictated by a delta
variable. If I change the value manually, it does this:
I wanted to have a slider that changes the delta
variable. But I get some really weird effects. Namely lines are drawn out of frame to the right. I dumped console.log statements everywhere but I still cannot find the problem (how does one even debug canvas issues?)
var canvas = document.querySelector("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.width = 1600;
canvas.height = 800;
var ct = canvas.getContext("2d");
// TODO
// 1. Make a center point
// 2. Draw lines jutting from center
// 3. Draw a line parallel to canvas bottom
// 4. Draw an adjoining item upward
// x, y
// right, down
// Nomenclature
// x0a
// coordinate type, vanishingPt#, endPtName
// Vanishing point 0
var x0 = 400;
var y0 = 400;
// Vanishing point end 0a
var x0a = 0;
var y0a = 2 * y0;
// Vanishing point end 0b
var x0b = 2 * x0;
var y0b = 2 * y0;
// Define delta
var delta = 700;
function init() {
console.log(delta, "delta");
console.log(x0b, "x0b");
console.log(y0b, "y0b");
console.log(x0, "x0");
console.log(y0, "y0");
// First Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0a, y0a);
ct.strokeStyle = 'red';
ct.stroke();
// Second Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0b, x0b);
ct.strokeStyle = 'green';
ct.stroke();
// House based on second Line
ct.beginPath();
ct.moveTo(x0b, y0b); // starting point
ct.lineTo(x0b + delta, y0b); // right x+100
ct.lineTo(x0b + delta, y0b - delta); // up y-100
ct.lineTo(x0b, y0b - delta); // left x-100
ct.lineTo(x0b, y0b); // down y+100
ct.lineTo(x0b, y0b - delta); // back up y-100
//calculate
ct.lineTo(x0, y0);
ct.lineTo(x0b + delta, y0b - delta);
ct.strokeStyle = 'blue';
ct.stroke();
}
init();
var slider = document.getElementById("myRange");
slider.oninput = function () {
delta = this.value;
requestAnimationFrame(init()); // redraw everything
}
body {
background-color: lightgray;
display: flex;
justify-content: center;
align-items: center;
}
.slideContainer {
position: fixed;
right: 30px;
top: 30px;
background-color: lightblue;
z-index: 20;
}
canvas {
border: 1px dotted red;
padding: 80px;
background-color: lightgray;
transform: scale(0.5);
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="wrapper">
<div class="slideContainer">
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
</div>
<canvas id="canvas"></canvas>
</div>
<script src="script.js"></script>
</body>
</html>
javascript html css canvas html5-canvas
I have a canvas element. It draws some lines, based on art vanishing points.
I'm trying to draw a house (for now its just a box) from a single vanishing point. The size of the box is dictated by a delta
variable. If I change the value manually, it does this:
I wanted to have a slider that changes the delta
variable. But I get some really weird effects. Namely lines are drawn out of frame to the right. I dumped console.log statements everywhere but I still cannot find the problem (how does one even debug canvas issues?)
var canvas = document.querySelector("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.width = 1600;
canvas.height = 800;
var ct = canvas.getContext("2d");
// TODO
// 1. Make a center point
// 2. Draw lines jutting from center
// 3. Draw a line parallel to canvas bottom
// 4. Draw an adjoining item upward
// x, y
// right, down
// Nomenclature
// x0a
// coordinate type, vanishingPt#, endPtName
// Vanishing point 0
var x0 = 400;
var y0 = 400;
// Vanishing point end 0a
var x0a = 0;
var y0a = 2 * y0;
// Vanishing point end 0b
var x0b = 2 * x0;
var y0b = 2 * y0;
// Define delta
var delta = 700;
function init() {
console.log(delta, "delta");
console.log(x0b, "x0b");
console.log(y0b, "y0b");
console.log(x0, "x0");
console.log(y0, "y0");
// First Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0a, y0a);
ct.strokeStyle = 'red';
ct.stroke();
// Second Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0b, x0b);
ct.strokeStyle = 'green';
ct.stroke();
// House based on second Line
ct.beginPath();
ct.moveTo(x0b, y0b); // starting point
ct.lineTo(x0b + delta, y0b); // right x+100
ct.lineTo(x0b + delta, y0b - delta); // up y-100
ct.lineTo(x0b, y0b - delta); // left x-100
ct.lineTo(x0b, y0b); // down y+100
ct.lineTo(x0b, y0b - delta); // back up y-100
//calculate
ct.lineTo(x0, y0);
ct.lineTo(x0b + delta, y0b - delta);
ct.strokeStyle = 'blue';
ct.stroke();
}
init();
var slider = document.getElementById("myRange");
slider.oninput = function () {
delta = this.value;
requestAnimationFrame(init()); // redraw everything
}
body {
background-color: lightgray;
display: flex;
justify-content: center;
align-items: center;
}
.slideContainer {
position: fixed;
right: 30px;
top: 30px;
background-color: lightblue;
z-index: 20;
}
canvas {
border: 1px dotted red;
padding: 80px;
background-color: lightgray;
transform: scale(0.5);
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="wrapper">
<div class="slideContainer">
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
</div>
<canvas id="canvas"></canvas>
</div>
<script src="script.js"></script>
</body>
</html>
var canvas = document.querySelector("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.width = 1600;
canvas.height = 800;
var ct = canvas.getContext("2d");
// TODO
// 1. Make a center point
// 2. Draw lines jutting from center
// 3. Draw a line parallel to canvas bottom
// 4. Draw an adjoining item upward
// x, y
// right, down
// Nomenclature
// x0a
// coordinate type, vanishingPt#, endPtName
// Vanishing point 0
var x0 = 400;
var y0 = 400;
// Vanishing point end 0a
var x0a = 0;
var y0a = 2 * y0;
// Vanishing point end 0b
var x0b = 2 * x0;
var y0b = 2 * y0;
// Define delta
var delta = 700;
function init() {
console.log(delta, "delta");
console.log(x0b, "x0b");
console.log(y0b, "y0b");
console.log(x0, "x0");
console.log(y0, "y0");
// First Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0a, y0a);
ct.strokeStyle = 'red';
ct.stroke();
// Second Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0b, x0b);
ct.strokeStyle = 'green';
ct.stroke();
// House based on second Line
ct.beginPath();
ct.moveTo(x0b, y0b); // starting point
ct.lineTo(x0b + delta, y0b); // right x+100
ct.lineTo(x0b + delta, y0b - delta); // up y-100
ct.lineTo(x0b, y0b - delta); // left x-100
ct.lineTo(x0b, y0b); // down y+100
ct.lineTo(x0b, y0b - delta); // back up y-100
//calculate
ct.lineTo(x0, y0);
ct.lineTo(x0b + delta, y0b - delta);
ct.strokeStyle = 'blue';
ct.stroke();
}
init();
var slider = document.getElementById("myRange");
slider.oninput = function () {
delta = this.value;
requestAnimationFrame(init()); // redraw everything
}
body {
background-color: lightgray;
display: flex;
justify-content: center;
align-items: center;
}
.slideContainer {
position: fixed;
right: 30px;
top: 30px;
background-color: lightblue;
z-index: 20;
}
canvas {
border: 1px dotted red;
padding: 80px;
background-color: lightgray;
transform: scale(0.5);
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="wrapper">
<div class="slideContainer">
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
</div>
<canvas id="canvas"></canvas>
</div>
<script src="script.js"></script>
</body>
</html>
var canvas = document.querySelector("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.width = 1600;
canvas.height = 800;
var ct = canvas.getContext("2d");
// TODO
// 1. Make a center point
// 2. Draw lines jutting from center
// 3. Draw a line parallel to canvas bottom
// 4. Draw an adjoining item upward
// x, y
// right, down
// Nomenclature
// x0a
// coordinate type, vanishingPt#, endPtName
// Vanishing point 0
var x0 = 400;
var y0 = 400;
// Vanishing point end 0a
var x0a = 0;
var y0a = 2 * y0;
// Vanishing point end 0b
var x0b = 2 * x0;
var y0b = 2 * y0;
// Define delta
var delta = 700;
function init() {
console.log(delta, "delta");
console.log(x0b, "x0b");
console.log(y0b, "y0b");
console.log(x0, "x0");
console.log(y0, "y0");
// First Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0a, y0a);
ct.strokeStyle = 'red';
ct.stroke();
// Second Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0b, x0b);
ct.strokeStyle = 'green';
ct.stroke();
// House based on second Line
ct.beginPath();
ct.moveTo(x0b, y0b); // starting point
ct.lineTo(x0b + delta, y0b); // right x+100
ct.lineTo(x0b + delta, y0b - delta); // up y-100
ct.lineTo(x0b, y0b - delta); // left x-100
ct.lineTo(x0b, y0b); // down y+100
ct.lineTo(x0b, y0b - delta); // back up y-100
//calculate
ct.lineTo(x0, y0);
ct.lineTo(x0b + delta, y0b - delta);
ct.strokeStyle = 'blue';
ct.stroke();
}
init();
var slider = document.getElementById("myRange");
slider.oninput = function () {
delta = this.value;
requestAnimationFrame(init()); // redraw everything
}
body {
background-color: lightgray;
display: flex;
justify-content: center;
align-items: center;
}
.slideContainer {
position: fixed;
right: 30px;
top: 30px;
background-color: lightblue;
z-index: 20;
}
canvas {
border: 1px dotted red;
padding: 80px;
background-color: lightgray;
transform: scale(0.5);
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="wrapper">
<div class="slideContainer">
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
</div>
<canvas id="canvas"></canvas>
</div>
<script src="script.js"></script>
</body>
</html>
javascript html css canvas html5-canvas
javascript html css canvas html5-canvas
asked Nov 25 '18 at 3:28
Vincent TangVincent Tang
84121431
84121431
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
Decouple render from input events
Your question as been answered but your question has some bad practice parts that need to be pointed out or they get copied.
oninput
is a mouse move driven event.
Never call a render function or requestAnimationFrame
from any events that are the result of mouse move events. Mouse move events on many devices can fire at rates much higher than the display rate (as much as 1000 times a second). The display can only display 1 frame every 60th second, drawing more will not be seen and can chew through the client's batteries.
If you call requestAnimationFrame
from within a mouse driven input event you end up queuing many renders for the next display refresh, and as requestAnimationFrame
tries to balance the load, it may queue renders for the next frame, thus the latest update can be up to 2 display frames late. Most frames will never be seen and you still chew up power.
Use a semaphore and a standard render loop that monitors the semaphore and redraws only when needed, and only once per frame. (see example)
Don`t scale down the canvas.
Unless you are transforming the canvas as part of an animation dont scale it down via the CSS rule transform: scale(0.5);
(or any other scaling method) Rendering performance is all about pixels per second, if you half the size of the displayed canvas that means you need to render 4 times as many pixels, and use 4 times as much memory.
You can do the scaling via the canvas 2D API and will save the clients battery life, and increase performance, doing so.
Example
I have totally re-written the code, hopefully it will help. The two main points, Updates, and Scale are commented. Added code to use points rather than x,y coords as I am lazy.
requestAnimationFrame(update); // start anim loop
const ctx = canvas.getContext("2d");
const width = 1600; // The ideal resolution
const height = 800; // used to scale content
canvas.width = innerWidth;
canvas.height = innerHeight;
//Scales 2D context to always show the ideal resolution area
const scaleToFit = () => { // sets canvas scale to fit content
var scale = Math.min(canvas.width / width, canvas.height / height);
ctx.setTransform(scale, 0, 0, scale, 0, 0);
}
var redraw = true; // when true scene is redrawn ready for the next display refresh
// Working with points is easier
const point = (x = 0, y = 0) => ({x, y});
const pointCpy = (p, x = 0, y = 0) => ({x: p.x + x, y: p.y + y});
const scalePoint = (origin, point, scale) => {
point.x = (point.x - origin.x) * scale + origin.x;
point.y = (point.y - origin.y) * scale + origin.y;
};
const p1 = point(400,400);
const pA = point(p1.x, p1.y * 2);
const pB = point(p1.x * 2, p1.y * 2);
var delta = 50;
// the slider input event should not directly trigger a render
slider.addEventListener("input",(e) => {
delta = Number(e.target.value);
redraw = true; // use a semaphore to indicate content needs to redraw.
});
function update() { // this is the render loop it only draws when redraw is true
if (redraw) { // monitor semaphore
redraw = false; // clear semaphore
ctx.setTransform(1,0,0,1,0,0); // resets transform
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
scaleToFit();
draw();
}
requestAnimationFrame(update);
}
// this was your function init()
function draw() {
drawLine(p1, pA, "red");
drawLine(p1, pB, "green");
drawVBox(pB, delta, p1, "blue");
}
function drawVBox(p, size, vp, col, width) { // p is bottom left vp is vanish point
ctx.strokeStyle = col;
ctx.lineWidth = width;
const p0 = pointCpy(p); // get corners
const p1 = pointCpy(p, size);
const p2 = pointCpy(p, size, -size);
const p3 = pointCpy(p, 0, -size);
drawPoly(col, width, p0, p1, p2, p3)
ctx.beginPath(); // draw vanish lines
pathLine(p0, vp);
pathLine(p1, vp);
pathLine(p2, vp);
pathLine(p3, vp);
ctx.stroke();
const scale = 1 - size / (800 * 2);
scalePoint(vp, p0, scale);
scalePoint(vp, p1, scale);
scalePoint(vp, p2, scale);
scalePoint(vp, p3, scale);
drawPoly(col, width, p0, p1, p2, p3);
}
// Use function to do common tasks and save your self a lot of typing
function drawLine(p1, p2, col, width = 1) {
ctx.strokeStyle = col;
ctx.lineWidth = width;
ctx.beginPath();
ctx.lineTo(p1.x, p1.y); // First point after beginPath can be lineTo
ctx.lineTo(p2.x, p2.y);
ctx.stroke();
}
function drawPoly(col,width, ...points) {
ctx.strokeStyle = col;
ctx.lineWidth = width;
ctx.beginPath();
for(const p of points){
ctx.lineTo(p.x, p.y); // First point after beginPath can be lineTo
}
ctx.closePath(); // draw closing line
ctx.stroke();
}
function pathLine(p1, p2) {
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
}
canvas {
position : absolute;
top: 0px;
left: 0px;
background-color: lightgray;
z-index: -20;
}
<canvas id="canvas"></canvas>
<input type="range" min="1" max="800" value="50" id="slider">
<code id="info"></code>
wow thanks so much for the codereview :). I'm still a beginner at using<canvas>
so this was very helpful
– Vincent Tang
Nov 26 '18 at 0:05
That will obviously depend on the type of application, but for the ones that only do draw in response to user events, keeping an rAF loop active is probably not the best direction either ;-) You might want to throttle your event handlers instead, so that your tab can actually be free of computation when not interacting with it. Here is an old and basic implementation of a rAF based throttler
– Kaiido
Nov 26 '18 at 15:05
@Kaiido frames are call as soon as possible after the display refresh, How do you stop renders in the time after the frame and before the next display refresh? Even the most basic renderctx.clearRect(0,0,1,1)
takes 2000 time longer thanif(redraw){ ...}
ifredraw
isfalse
Your throttle on average lets through 1 extra render per frame (rounding down and on slow machine) when moving the mouse, so in one second of move events your throttle generates unneeded renders consuming the equivalent of half an hour idle frame calls or 1 render = 33 seconds of rAF non renders
– Blindman67
Nov 26 '18 at 17:19
@Blindman67 I think you forgot rAF itself in your calculations ;-) even if internal code, it is far from being a noop. And I don't see where you see the extra render, throttling causes one lost render on average (we are always on the late frame)
– Kaiido
Nov 26 '18 at 22:30
@Your throttle lets extra rAF calls in the time between rAF exit, and the next display refresh, which could be as long as 15+ms. Seq.. Display refresh, then mouse event requests frame, Frame gets called immediately after event exits and clears the active flag and exits, Then another mouse event fires, and requests another frame, that gets called after event exits. thats two renders in less than 16ms. How do you stop renders in the time after the frame and before the next display refresh?
– Blindman67
Nov 26 '18 at 23:01
|
show 12 more comments
After fixing the Syntax Error of calling requestAnimationFrame(init())
instead of requestAnimationFrame(init)
, note the ()
, all that remains is to coerce your HTMLInput's value
to a Number so you don't end up doing "800" + 150
which results in "800150"
.
myRange.oninput = function() {
console.log(this.value + 150);
}
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
var canvas = document.querySelector("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.width = 1600;
canvas.height = 800;
var ct = canvas.getContext("2d");
// TODO
// 1. Make a center point
// 2. Draw lines jutting from center
// 3. Draw a line parallel to canvas bottom
// 4. Draw an adjoining item upward
// x, y
// right, down
// Nomenclature
// x0a
// coordinate type, vanishingPt#, endPtName
// Vanishing point 0
var x0 = 400;
var y0 = 400;
// Vanishing point end 0a
var x0a = 0;
var y0a = 2 * y0;
// Vanishing point end 0b
var x0b = 2 * x0;
var y0b = 2 * y0;
// Define delta
var delta = 700;
function init() {
console.log(delta, "delta");
console.log(x0b, "x0b");
console.log(y0b, "y0b");
console.log(x0, "x0");
console.log(y0, "y0");
// First Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0a, y0a);
ct.strokeStyle = 'red';
ct.stroke();
// Second Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0b, x0b);
ct.strokeStyle = 'green';
ct.stroke();
// House based on second Line
ct.beginPath();
ct.moveTo(x0b, y0b); // starting point
ct.lineTo(x0b + delta, y0b); // right x+100
ct.lineTo(x0b + delta, y0b - delta); // up y-100
ct.lineTo(x0b, y0b - delta); // left x-100
ct.lineTo(x0b, y0b); // down y+100
ct.lineTo(x0b, y0b - delta); // back up y-100
//calculate
ct.lineTo(x0, y0);
ct.lineTo(x0b + delta, y0b - delta);
ct.strokeStyle = 'blue';
ct.stroke();
}
init();
var slider = document.getElementById("myRange");
slider.oninput = function () {
// coerce to Number
delta = +this.value;
requestAnimationFrame(init); // redraw everything
}
body {
background-color: lightgray;
display: flex;
justify-content: center;
align-items: center;
}
.slideContainer {
position: fixed;
right: 30px;
top: 30px;
background-color: lightblue;
z-index: 20;
}
canvas {
border: 1px dotted red;
padding: 80px;
background-color: lightgray;
transform: scale(0.5);
}
<div class="wrapper">
<div class="slideContainer">
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
</div>
<canvas id="canvas"></canvas>
</div>
ah I see now.this.value
from the slider is a string. Thanks for the help :)
– Vincent Tang
Nov 25 '18 at 5:27
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53464401%2fcanvas-request-animation-out-of-frame-on-slider-input-to-javascript-variable%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Decouple render from input events
Your question as been answered but your question has some bad practice parts that need to be pointed out or they get copied.
oninput
is a mouse move driven event.
Never call a render function or requestAnimationFrame
from any events that are the result of mouse move events. Mouse move events on many devices can fire at rates much higher than the display rate (as much as 1000 times a second). The display can only display 1 frame every 60th second, drawing more will not be seen and can chew through the client's batteries.
If you call requestAnimationFrame
from within a mouse driven input event you end up queuing many renders for the next display refresh, and as requestAnimationFrame
tries to balance the load, it may queue renders for the next frame, thus the latest update can be up to 2 display frames late. Most frames will never be seen and you still chew up power.
Use a semaphore and a standard render loop that monitors the semaphore and redraws only when needed, and only once per frame. (see example)
Don`t scale down the canvas.
Unless you are transforming the canvas as part of an animation dont scale it down via the CSS rule transform: scale(0.5);
(or any other scaling method) Rendering performance is all about pixels per second, if you half the size of the displayed canvas that means you need to render 4 times as many pixels, and use 4 times as much memory.
You can do the scaling via the canvas 2D API and will save the clients battery life, and increase performance, doing so.
Example
I have totally re-written the code, hopefully it will help. The two main points, Updates, and Scale are commented. Added code to use points rather than x,y coords as I am lazy.
requestAnimationFrame(update); // start anim loop
const ctx = canvas.getContext("2d");
const width = 1600; // The ideal resolution
const height = 800; // used to scale content
canvas.width = innerWidth;
canvas.height = innerHeight;
//Scales 2D context to always show the ideal resolution area
const scaleToFit = () => { // sets canvas scale to fit content
var scale = Math.min(canvas.width / width, canvas.height / height);
ctx.setTransform(scale, 0, 0, scale, 0, 0);
}
var redraw = true; // when true scene is redrawn ready for the next display refresh
// Working with points is easier
const point = (x = 0, y = 0) => ({x, y});
const pointCpy = (p, x = 0, y = 0) => ({x: p.x + x, y: p.y + y});
const scalePoint = (origin, point, scale) => {
point.x = (point.x - origin.x) * scale + origin.x;
point.y = (point.y - origin.y) * scale + origin.y;
};
const p1 = point(400,400);
const pA = point(p1.x, p1.y * 2);
const pB = point(p1.x * 2, p1.y * 2);
var delta = 50;
// the slider input event should not directly trigger a render
slider.addEventListener("input",(e) => {
delta = Number(e.target.value);
redraw = true; // use a semaphore to indicate content needs to redraw.
});
function update() { // this is the render loop it only draws when redraw is true
if (redraw) { // monitor semaphore
redraw = false; // clear semaphore
ctx.setTransform(1,0,0,1,0,0); // resets transform
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
scaleToFit();
draw();
}
requestAnimationFrame(update);
}
// this was your function init()
function draw() {
drawLine(p1, pA, "red");
drawLine(p1, pB, "green");
drawVBox(pB, delta, p1, "blue");
}
function drawVBox(p, size, vp, col, width) { // p is bottom left vp is vanish point
ctx.strokeStyle = col;
ctx.lineWidth = width;
const p0 = pointCpy(p); // get corners
const p1 = pointCpy(p, size);
const p2 = pointCpy(p, size, -size);
const p3 = pointCpy(p, 0, -size);
drawPoly(col, width, p0, p1, p2, p3)
ctx.beginPath(); // draw vanish lines
pathLine(p0, vp);
pathLine(p1, vp);
pathLine(p2, vp);
pathLine(p3, vp);
ctx.stroke();
const scale = 1 - size / (800 * 2);
scalePoint(vp, p0, scale);
scalePoint(vp, p1, scale);
scalePoint(vp, p2, scale);
scalePoint(vp, p3, scale);
drawPoly(col, width, p0, p1, p2, p3);
}
// Use function to do common tasks and save your self a lot of typing
function drawLine(p1, p2, col, width = 1) {
ctx.strokeStyle = col;
ctx.lineWidth = width;
ctx.beginPath();
ctx.lineTo(p1.x, p1.y); // First point after beginPath can be lineTo
ctx.lineTo(p2.x, p2.y);
ctx.stroke();
}
function drawPoly(col,width, ...points) {
ctx.strokeStyle = col;
ctx.lineWidth = width;
ctx.beginPath();
for(const p of points){
ctx.lineTo(p.x, p.y); // First point after beginPath can be lineTo
}
ctx.closePath(); // draw closing line
ctx.stroke();
}
function pathLine(p1, p2) {
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
}
canvas {
position : absolute;
top: 0px;
left: 0px;
background-color: lightgray;
z-index: -20;
}
<canvas id="canvas"></canvas>
<input type="range" min="1" max="800" value="50" id="slider">
<code id="info"></code>
wow thanks so much for the codereview :). I'm still a beginner at using<canvas>
so this was very helpful
– Vincent Tang
Nov 26 '18 at 0:05
That will obviously depend on the type of application, but for the ones that only do draw in response to user events, keeping an rAF loop active is probably not the best direction either ;-) You might want to throttle your event handlers instead, so that your tab can actually be free of computation when not interacting with it. Here is an old and basic implementation of a rAF based throttler
– Kaiido
Nov 26 '18 at 15:05
@Kaiido frames are call as soon as possible after the display refresh, How do you stop renders in the time after the frame and before the next display refresh? Even the most basic renderctx.clearRect(0,0,1,1)
takes 2000 time longer thanif(redraw){ ...}
ifredraw
isfalse
Your throttle on average lets through 1 extra render per frame (rounding down and on slow machine) when moving the mouse, so in one second of move events your throttle generates unneeded renders consuming the equivalent of half an hour idle frame calls or 1 render = 33 seconds of rAF non renders
– Blindman67
Nov 26 '18 at 17:19
@Blindman67 I think you forgot rAF itself in your calculations ;-) even if internal code, it is far from being a noop. And I don't see where you see the extra render, throttling causes one lost render on average (we are always on the late frame)
– Kaiido
Nov 26 '18 at 22:30
@Your throttle lets extra rAF calls in the time between rAF exit, and the next display refresh, which could be as long as 15+ms. Seq.. Display refresh, then mouse event requests frame, Frame gets called immediately after event exits and clears the active flag and exits, Then another mouse event fires, and requests another frame, that gets called after event exits. thats two renders in less than 16ms. How do you stop renders in the time after the frame and before the next display refresh?
– Blindman67
Nov 26 '18 at 23:01
|
show 12 more comments
Decouple render from input events
Your question as been answered but your question has some bad practice parts that need to be pointed out or they get copied.
oninput
is a mouse move driven event.
Never call a render function or requestAnimationFrame
from any events that are the result of mouse move events. Mouse move events on many devices can fire at rates much higher than the display rate (as much as 1000 times a second). The display can only display 1 frame every 60th second, drawing more will not be seen and can chew through the client's batteries.
If you call requestAnimationFrame
from within a mouse driven input event you end up queuing many renders for the next display refresh, and as requestAnimationFrame
tries to balance the load, it may queue renders for the next frame, thus the latest update can be up to 2 display frames late. Most frames will never be seen and you still chew up power.
Use a semaphore and a standard render loop that monitors the semaphore and redraws only when needed, and only once per frame. (see example)
Don`t scale down the canvas.
Unless you are transforming the canvas as part of an animation dont scale it down via the CSS rule transform: scale(0.5);
(or any other scaling method) Rendering performance is all about pixels per second, if you half the size of the displayed canvas that means you need to render 4 times as many pixels, and use 4 times as much memory.
You can do the scaling via the canvas 2D API and will save the clients battery life, and increase performance, doing so.
Example
I have totally re-written the code, hopefully it will help. The two main points, Updates, and Scale are commented. Added code to use points rather than x,y coords as I am lazy.
requestAnimationFrame(update); // start anim loop
const ctx = canvas.getContext("2d");
const width = 1600; // The ideal resolution
const height = 800; // used to scale content
canvas.width = innerWidth;
canvas.height = innerHeight;
//Scales 2D context to always show the ideal resolution area
const scaleToFit = () => { // sets canvas scale to fit content
var scale = Math.min(canvas.width / width, canvas.height / height);
ctx.setTransform(scale, 0, 0, scale, 0, 0);
}
var redraw = true; // when true scene is redrawn ready for the next display refresh
// Working with points is easier
const point = (x = 0, y = 0) => ({x, y});
const pointCpy = (p, x = 0, y = 0) => ({x: p.x + x, y: p.y + y});
const scalePoint = (origin, point, scale) => {
point.x = (point.x - origin.x) * scale + origin.x;
point.y = (point.y - origin.y) * scale + origin.y;
};
const p1 = point(400,400);
const pA = point(p1.x, p1.y * 2);
const pB = point(p1.x * 2, p1.y * 2);
var delta = 50;
// the slider input event should not directly trigger a render
slider.addEventListener("input",(e) => {
delta = Number(e.target.value);
redraw = true; // use a semaphore to indicate content needs to redraw.
});
function update() { // this is the render loop it only draws when redraw is true
if (redraw) { // monitor semaphore
redraw = false; // clear semaphore
ctx.setTransform(1,0,0,1,0,0); // resets transform
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
scaleToFit();
draw();
}
requestAnimationFrame(update);
}
// this was your function init()
function draw() {
drawLine(p1, pA, "red");
drawLine(p1, pB, "green");
drawVBox(pB, delta, p1, "blue");
}
function drawVBox(p, size, vp, col, width) { // p is bottom left vp is vanish point
ctx.strokeStyle = col;
ctx.lineWidth = width;
const p0 = pointCpy(p); // get corners
const p1 = pointCpy(p, size);
const p2 = pointCpy(p, size, -size);
const p3 = pointCpy(p, 0, -size);
drawPoly(col, width, p0, p1, p2, p3)
ctx.beginPath(); // draw vanish lines
pathLine(p0, vp);
pathLine(p1, vp);
pathLine(p2, vp);
pathLine(p3, vp);
ctx.stroke();
const scale = 1 - size / (800 * 2);
scalePoint(vp, p0, scale);
scalePoint(vp, p1, scale);
scalePoint(vp, p2, scale);
scalePoint(vp, p3, scale);
drawPoly(col, width, p0, p1, p2, p3);
}
// Use function to do common tasks and save your self a lot of typing
function drawLine(p1, p2, col, width = 1) {
ctx.strokeStyle = col;
ctx.lineWidth = width;
ctx.beginPath();
ctx.lineTo(p1.x, p1.y); // First point after beginPath can be lineTo
ctx.lineTo(p2.x, p2.y);
ctx.stroke();
}
function drawPoly(col,width, ...points) {
ctx.strokeStyle = col;
ctx.lineWidth = width;
ctx.beginPath();
for(const p of points){
ctx.lineTo(p.x, p.y); // First point after beginPath can be lineTo
}
ctx.closePath(); // draw closing line
ctx.stroke();
}
function pathLine(p1, p2) {
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
}
canvas {
position : absolute;
top: 0px;
left: 0px;
background-color: lightgray;
z-index: -20;
}
<canvas id="canvas"></canvas>
<input type="range" min="1" max="800" value="50" id="slider">
<code id="info"></code>
wow thanks so much for the codereview :). I'm still a beginner at using<canvas>
so this was very helpful
– Vincent Tang
Nov 26 '18 at 0:05
That will obviously depend on the type of application, but for the ones that only do draw in response to user events, keeping an rAF loop active is probably not the best direction either ;-) You might want to throttle your event handlers instead, so that your tab can actually be free of computation when not interacting with it. Here is an old and basic implementation of a rAF based throttler
– Kaiido
Nov 26 '18 at 15:05
@Kaiido frames are call as soon as possible after the display refresh, How do you stop renders in the time after the frame and before the next display refresh? Even the most basic renderctx.clearRect(0,0,1,1)
takes 2000 time longer thanif(redraw){ ...}
ifredraw
isfalse
Your throttle on average lets through 1 extra render per frame (rounding down and on slow machine) when moving the mouse, so in one second of move events your throttle generates unneeded renders consuming the equivalent of half an hour idle frame calls or 1 render = 33 seconds of rAF non renders
– Blindman67
Nov 26 '18 at 17:19
@Blindman67 I think you forgot rAF itself in your calculations ;-) even if internal code, it is far from being a noop. And I don't see where you see the extra render, throttling causes one lost render on average (we are always on the late frame)
– Kaiido
Nov 26 '18 at 22:30
@Your throttle lets extra rAF calls in the time between rAF exit, and the next display refresh, which could be as long as 15+ms. Seq.. Display refresh, then mouse event requests frame, Frame gets called immediately after event exits and clears the active flag and exits, Then another mouse event fires, and requests another frame, that gets called after event exits. thats two renders in less than 16ms. How do you stop renders in the time after the frame and before the next display refresh?
– Blindman67
Nov 26 '18 at 23:01
|
show 12 more comments
Decouple render from input events
Your question as been answered but your question has some bad practice parts that need to be pointed out or they get copied.
oninput
is a mouse move driven event.
Never call a render function or requestAnimationFrame
from any events that are the result of mouse move events. Mouse move events on many devices can fire at rates much higher than the display rate (as much as 1000 times a second). The display can only display 1 frame every 60th second, drawing more will not be seen and can chew through the client's batteries.
If you call requestAnimationFrame
from within a mouse driven input event you end up queuing many renders for the next display refresh, and as requestAnimationFrame
tries to balance the load, it may queue renders for the next frame, thus the latest update can be up to 2 display frames late. Most frames will never be seen and you still chew up power.
Use a semaphore and a standard render loop that monitors the semaphore and redraws only when needed, and only once per frame. (see example)
Don`t scale down the canvas.
Unless you are transforming the canvas as part of an animation dont scale it down via the CSS rule transform: scale(0.5);
(or any other scaling method) Rendering performance is all about pixels per second, if you half the size of the displayed canvas that means you need to render 4 times as many pixels, and use 4 times as much memory.
You can do the scaling via the canvas 2D API and will save the clients battery life, and increase performance, doing so.
Example
I have totally re-written the code, hopefully it will help. The two main points, Updates, and Scale are commented. Added code to use points rather than x,y coords as I am lazy.
requestAnimationFrame(update); // start anim loop
const ctx = canvas.getContext("2d");
const width = 1600; // The ideal resolution
const height = 800; // used to scale content
canvas.width = innerWidth;
canvas.height = innerHeight;
//Scales 2D context to always show the ideal resolution area
const scaleToFit = () => { // sets canvas scale to fit content
var scale = Math.min(canvas.width / width, canvas.height / height);
ctx.setTransform(scale, 0, 0, scale, 0, 0);
}
var redraw = true; // when true scene is redrawn ready for the next display refresh
// Working with points is easier
const point = (x = 0, y = 0) => ({x, y});
const pointCpy = (p, x = 0, y = 0) => ({x: p.x + x, y: p.y + y});
const scalePoint = (origin, point, scale) => {
point.x = (point.x - origin.x) * scale + origin.x;
point.y = (point.y - origin.y) * scale + origin.y;
};
const p1 = point(400,400);
const pA = point(p1.x, p1.y * 2);
const pB = point(p1.x * 2, p1.y * 2);
var delta = 50;
// the slider input event should not directly trigger a render
slider.addEventListener("input",(e) => {
delta = Number(e.target.value);
redraw = true; // use a semaphore to indicate content needs to redraw.
});
function update() { // this is the render loop it only draws when redraw is true
if (redraw) { // monitor semaphore
redraw = false; // clear semaphore
ctx.setTransform(1,0,0,1,0,0); // resets transform
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
scaleToFit();
draw();
}
requestAnimationFrame(update);
}
// this was your function init()
function draw() {
drawLine(p1, pA, "red");
drawLine(p1, pB, "green");
drawVBox(pB, delta, p1, "blue");
}
function drawVBox(p, size, vp, col, width) { // p is bottom left vp is vanish point
ctx.strokeStyle = col;
ctx.lineWidth = width;
const p0 = pointCpy(p); // get corners
const p1 = pointCpy(p, size);
const p2 = pointCpy(p, size, -size);
const p3 = pointCpy(p, 0, -size);
drawPoly(col, width, p0, p1, p2, p3)
ctx.beginPath(); // draw vanish lines
pathLine(p0, vp);
pathLine(p1, vp);
pathLine(p2, vp);
pathLine(p3, vp);
ctx.stroke();
const scale = 1 - size / (800 * 2);
scalePoint(vp, p0, scale);
scalePoint(vp, p1, scale);
scalePoint(vp, p2, scale);
scalePoint(vp, p3, scale);
drawPoly(col, width, p0, p1, p2, p3);
}
// Use function to do common tasks and save your self a lot of typing
function drawLine(p1, p2, col, width = 1) {
ctx.strokeStyle = col;
ctx.lineWidth = width;
ctx.beginPath();
ctx.lineTo(p1.x, p1.y); // First point after beginPath can be lineTo
ctx.lineTo(p2.x, p2.y);
ctx.stroke();
}
function drawPoly(col,width, ...points) {
ctx.strokeStyle = col;
ctx.lineWidth = width;
ctx.beginPath();
for(const p of points){
ctx.lineTo(p.x, p.y); // First point after beginPath can be lineTo
}
ctx.closePath(); // draw closing line
ctx.stroke();
}
function pathLine(p1, p2) {
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
}
canvas {
position : absolute;
top: 0px;
left: 0px;
background-color: lightgray;
z-index: -20;
}
<canvas id="canvas"></canvas>
<input type="range" min="1" max="800" value="50" id="slider">
<code id="info"></code>
Decouple render from input events
Your question as been answered but your question has some bad practice parts that need to be pointed out or they get copied.
oninput
is a mouse move driven event.
Never call a render function or requestAnimationFrame
from any events that are the result of mouse move events. Mouse move events on many devices can fire at rates much higher than the display rate (as much as 1000 times a second). The display can only display 1 frame every 60th second, drawing more will not be seen and can chew through the client's batteries.
If you call requestAnimationFrame
from within a mouse driven input event you end up queuing many renders for the next display refresh, and as requestAnimationFrame
tries to balance the load, it may queue renders for the next frame, thus the latest update can be up to 2 display frames late. Most frames will never be seen and you still chew up power.
Use a semaphore and a standard render loop that monitors the semaphore and redraws only when needed, and only once per frame. (see example)
Don`t scale down the canvas.
Unless you are transforming the canvas as part of an animation dont scale it down via the CSS rule transform: scale(0.5);
(or any other scaling method) Rendering performance is all about pixels per second, if you half the size of the displayed canvas that means you need to render 4 times as many pixels, and use 4 times as much memory.
You can do the scaling via the canvas 2D API and will save the clients battery life, and increase performance, doing so.
Example
I have totally re-written the code, hopefully it will help. The two main points, Updates, and Scale are commented. Added code to use points rather than x,y coords as I am lazy.
requestAnimationFrame(update); // start anim loop
const ctx = canvas.getContext("2d");
const width = 1600; // The ideal resolution
const height = 800; // used to scale content
canvas.width = innerWidth;
canvas.height = innerHeight;
//Scales 2D context to always show the ideal resolution area
const scaleToFit = () => { // sets canvas scale to fit content
var scale = Math.min(canvas.width / width, canvas.height / height);
ctx.setTransform(scale, 0, 0, scale, 0, 0);
}
var redraw = true; // when true scene is redrawn ready for the next display refresh
// Working with points is easier
const point = (x = 0, y = 0) => ({x, y});
const pointCpy = (p, x = 0, y = 0) => ({x: p.x + x, y: p.y + y});
const scalePoint = (origin, point, scale) => {
point.x = (point.x - origin.x) * scale + origin.x;
point.y = (point.y - origin.y) * scale + origin.y;
};
const p1 = point(400,400);
const pA = point(p1.x, p1.y * 2);
const pB = point(p1.x * 2, p1.y * 2);
var delta = 50;
// the slider input event should not directly trigger a render
slider.addEventListener("input",(e) => {
delta = Number(e.target.value);
redraw = true; // use a semaphore to indicate content needs to redraw.
});
function update() { // this is the render loop it only draws when redraw is true
if (redraw) { // monitor semaphore
redraw = false; // clear semaphore
ctx.setTransform(1,0,0,1,0,0); // resets transform
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
scaleToFit();
draw();
}
requestAnimationFrame(update);
}
// this was your function init()
function draw() {
drawLine(p1, pA, "red");
drawLine(p1, pB, "green");
drawVBox(pB, delta, p1, "blue");
}
function drawVBox(p, size, vp, col, width) { // p is bottom left vp is vanish point
ctx.strokeStyle = col;
ctx.lineWidth = width;
const p0 = pointCpy(p); // get corners
const p1 = pointCpy(p, size);
const p2 = pointCpy(p, size, -size);
const p3 = pointCpy(p, 0, -size);
drawPoly(col, width, p0, p1, p2, p3)
ctx.beginPath(); // draw vanish lines
pathLine(p0, vp);
pathLine(p1, vp);
pathLine(p2, vp);
pathLine(p3, vp);
ctx.stroke();
const scale = 1 - size / (800 * 2);
scalePoint(vp, p0, scale);
scalePoint(vp, p1, scale);
scalePoint(vp, p2, scale);
scalePoint(vp, p3, scale);
drawPoly(col, width, p0, p1, p2, p3);
}
// Use function to do common tasks and save your self a lot of typing
function drawLine(p1, p2, col, width = 1) {
ctx.strokeStyle = col;
ctx.lineWidth = width;
ctx.beginPath();
ctx.lineTo(p1.x, p1.y); // First point after beginPath can be lineTo
ctx.lineTo(p2.x, p2.y);
ctx.stroke();
}
function drawPoly(col,width, ...points) {
ctx.strokeStyle = col;
ctx.lineWidth = width;
ctx.beginPath();
for(const p of points){
ctx.lineTo(p.x, p.y); // First point after beginPath can be lineTo
}
ctx.closePath(); // draw closing line
ctx.stroke();
}
function pathLine(p1, p2) {
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
}
canvas {
position : absolute;
top: 0px;
left: 0px;
background-color: lightgray;
z-index: -20;
}
<canvas id="canvas"></canvas>
<input type="range" min="1" max="800" value="50" id="slider">
<code id="info"></code>
requestAnimationFrame(update); // start anim loop
const ctx = canvas.getContext("2d");
const width = 1600; // The ideal resolution
const height = 800; // used to scale content
canvas.width = innerWidth;
canvas.height = innerHeight;
//Scales 2D context to always show the ideal resolution area
const scaleToFit = () => { // sets canvas scale to fit content
var scale = Math.min(canvas.width / width, canvas.height / height);
ctx.setTransform(scale, 0, 0, scale, 0, 0);
}
var redraw = true; // when true scene is redrawn ready for the next display refresh
// Working with points is easier
const point = (x = 0, y = 0) => ({x, y});
const pointCpy = (p, x = 0, y = 0) => ({x: p.x + x, y: p.y + y});
const scalePoint = (origin, point, scale) => {
point.x = (point.x - origin.x) * scale + origin.x;
point.y = (point.y - origin.y) * scale + origin.y;
};
const p1 = point(400,400);
const pA = point(p1.x, p1.y * 2);
const pB = point(p1.x * 2, p1.y * 2);
var delta = 50;
// the slider input event should not directly trigger a render
slider.addEventListener("input",(e) => {
delta = Number(e.target.value);
redraw = true; // use a semaphore to indicate content needs to redraw.
});
function update() { // this is the render loop it only draws when redraw is true
if (redraw) { // monitor semaphore
redraw = false; // clear semaphore
ctx.setTransform(1,0,0,1,0,0); // resets transform
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
scaleToFit();
draw();
}
requestAnimationFrame(update);
}
// this was your function init()
function draw() {
drawLine(p1, pA, "red");
drawLine(p1, pB, "green");
drawVBox(pB, delta, p1, "blue");
}
function drawVBox(p, size, vp, col, width) { // p is bottom left vp is vanish point
ctx.strokeStyle = col;
ctx.lineWidth = width;
const p0 = pointCpy(p); // get corners
const p1 = pointCpy(p, size);
const p2 = pointCpy(p, size, -size);
const p3 = pointCpy(p, 0, -size);
drawPoly(col, width, p0, p1, p2, p3)
ctx.beginPath(); // draw vanish lines
pathLine(p0, vp);
pathLine(p1, vp);
pathLine(p2, vp);
pathLine(p3, vp);
ctx.stroke();
const scale = 1 - size / (800 * 2);
scalePoint(vp, p0, scale);
scalePoint(vp, p1, scale);
scalePoint(vp, p2, scale);
scalePoint(vp, p3, scale);
drawPoly(col, width, p0, p1, p2, p3);
}
// Use function to do common tasks and save your self a lot of typing
function drawLine(p1, p2, col, width = 1) {
ctx.strokeStyle = col;
ctx.lineWidth = width;
ctx.beginPath();
ctx.lineTo(p1.x, p1.y); // First point after beginPath can be lineTo
ctx.lineTo(p2.x, p2.y);
ctx.stroke();
}
function drawPoly(col,width, ...points) {
ctx.strokeStyle = col;
ctx.lineWidth = width;
ctx.beginPath();
for(const p of points){
ctx.lineTo(p.x, p.y); // First point after beginPath can be lineTo
}
ctx.closePath(); // draw closing line
ctx.stroke();
}
function pathLine(p1, p2) {
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
}
canvas {
position : absolute;
top: 0px;
left: 0px;
background-color: lightgray;
z-index: -20;
}
<canvas id="canvas"></canvas>
<input type="range" min="1" max="800" value="50" id="slider">
<code id="info"></code>
requestAnimationFrame(update); // start anim loop
const ctx = canvas.getContext("2d");
const width = 1600; // The ideal resolution
const height = 800; // used to scale content
canvas.width = innerWidth;
canvas.height = innerHeight;
//Scales 2D context to always show the ideal resolution area
const scaleToFit = () => { // sets canvas scale to fit content
var scale = Math.min(canvas.width / width, canvas.height / height);
ctx.setTransform(scale, 0, 0, scale, 0, 0);
}
var redraw = true; // when true scene is redrawn ready for the next display refresh
// Working with points is easier
const point = (x = 0, y = 0) => ({x, y});
const pointCpy = (p, x = 0, y = 0) => ({x: p.x + x, y: p.y + y});
const scalePoint = (origin, point, scale) => {
point.x = (point.x - origin.x) * scale + origin.x;
point.y = (point.y - origin.y) * scale + origin.y;
};
const p1 = point(400,400);
const pA = point(p1.x, p1.y * 2);
const pB = point(p1.x * 2, p1.y * 2);
var delta = 50;
// the slider input event should not directly trigger a render
slider.addEventListener("input",(e) => {
delta = Number(e.target.value);
redraw = true; // use a semaphore to indicate content needs to redraw.
});
function update() { // this is the render loop it only draws when redraw is true
if (redraw) { // monitor semaphore
redraw = false; // clear semaphore
ctx.setTransform(1,0,0,1,0,0); // resets transform
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
scaleToFit();
draw();
}
requestAnimationFrame(update);
}
// this was your function init()
function draw() {
drawLine(p1, pA, "red");
drawLine(p1, pB, "green");
drawVBox(pB, delta, p1, "blue");
}
function drawVBox(p, size, vp, col, width) { // p is bottom left vp is vanish point
ctx.strokeStyle = col;
ctx.lineWidth = width;
const p0 = pointCpy(p); // get corners
const p1 = pointCpy(p, size);
const p2 = pointCpy(p, size, -size);
const p3 = pointCpy(p, 0, -size);
drawPoly(col, width, p0, p1, p2, p3)
ctx.beginPath(); // draw vanish lines
pathLine(p0, vp);
pathLine(p1, vp);
pathLine(p2, vp);
pathLine(p3, vp);
ctx.stroke();
const scale = 1 - size / (800 * 2);
scalePoint(vp, p0, scale);
scalePoint(vp, p1, scale);
scalePoint(vp, p2, scale);
scalePoint(vp, p3, scale);
drawPoly(col, width, p0, p1, p2, p3);
}
// Use function to do common tasks and save your self a lot of typing
function drawLine(p1, p2, col, width = 1) {
ctx.strokeStyle = col;
ctx.lineWidth = width;
ctx.beginPath();
ctx.lineTo(p1.x, p1.y); // First point after beginPath can be lineTo
ctx.lineTo(p2.x, p2.y);
ctx.stroke();
}
function drawPoly(col,width, ...points) {
ctx.strokeStyle = col;
ctx.lineWidth = width;
ctx.beginPath();
for(const p of points){
ctx.lineTo(p.x, p.y); // First point after beginPath can be lineTo
}
ctx.closePath(); // draw closing line
ctx.stroke();
}
function pathLine(p1, p2) {
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
}
canvas {
position : absolute;
top: 0px;
left: 0px;
background-color: lightgray;
z-index: -20;
}
<canvas id="canvas"></canvas>
<input type="range" min="1" max="800" value="50" id="slider">
<code id="info"></code>
answered Nov 25 '18 at 12:34
Blindman67Blindman67
27.4k52764
27.4k52764
wow thanks so much for the codereview :). I'm still a beginner at using<canvas>
so this was very helpful
– Vincent Tang
Nov 26 '18 at 0:05
That will obviously depend on the type of application, but for the ones that only do draw in response to user events, keeping an rAF loop active is probably not the best direction either ;-) You might want to throttle your event handlers instead, so that your tab can actually be free of computation when not interacting with it. Here is an old and basic implementation of a rAF based throttler
– Kaiido
Nov 26 '18 at 15:05
@Kaiido frames are call as soon as possible after the display refresh, How do you stop renders in the time after the frame and before the next display refresh? Even the most basic renderctx.clearRect(0,0,1,1)
takes 2000 time longer thanif(redraw){ ...}
ifredraw
isfalse
Your throttle on average lets through 1 extra render per frame (rounding down and on slow machine) when moving the mouse, so in one second of move events your throttle generates unneeded renders consuming the equivalent of half an hour idle frame calls or 1 render = 33 seconds of rAF non renders
– Blindman67
Nov 26 '18 at 17:19
@Blindman67 I think you forgot rAF itself in your calculations ;-) even if internal code, it is far from being a noop. And I don't see where you see the extra render, throttling causes one lost render on average (we are always on the late frame)
– Kaiido
Nov 26 '18 at 22:30
@Your throttle lets extra rAF calls in the time between rAF exit, and the next display refresh, which could be as long as 15+ms. Seq.. Display refresh, then mouse event requests frame, Frame gets called immediately after event exits and clears the active flag and exits, Then another mouse event fires, and requests another frame, that gets called after event exits. thats two renders in less than 16ms. How do you stop renders in the time after the frame and before the next display refresh?
– Blindman67
Nov 26 '18 at 23:01
|
show 12 more comments
wow thanks so much for the codereview :). I'm still a beginner at using<canvas>
so this was very helpful
– Vincent Tang
Nov 26 '18 at 0:05
That will obviously depend on the type of application, but for the ones that only do draw in response to user events, keeping an rAF loop active is probably not the best direction either ;-) You might want to throttle your event handlers instead, so that your tab can actually be free of computation when not interacting with it. Here is an old and basic implementation of a rAF based throttler
– Kaiido
Nov 26 '18 at 15:05
@Kaiido frames are call as soon as possible after the display refresh, How do you stop renders in the time after the frame and before the next display refresh? Even the most basic renderctx.clearRect(0,0,1,1)
takes 2000 time longer thanif(redraw){ ...}
ifredraw
isfalse
Your throttle on average lets through 1 extra render per frame (rounding down and on slow machine) when moving the mouse, so in one second of move events your throttle generates unneeded renders consuming the equivalent of half an hour idle frame calls or 1 render = 33 seconds of rAF non renders
– Blindman67
Nov 26 '18 at 17:19
@Blindman67 I think you forgot rAF itself in your calculations ;-) even if internal code, it is far from being a noop. And I don't see where you see the extra render, throttling causes one lost render on average (we are always on the late frame)
– Kaiido
Nov 26 '18 at 22:30
@Your throttle lets extra rAF calls in the time between rAF exit, and the next display refresh, which could be as long as 15+ms. Seq.. Display refresh, then mouse event requests frame, Frame gets called immediately after event exits and clears the active flag and exits, Then another mouse event fires, and requests another frame, that gets called after event exits. thats two renders in less than 16ms. How do you stop renders in the time after the frame and before the next display refresh?
– Blindman67
Nov 26 '18 at 23:01
wow thanks so much for the codereview :). I'm still a beginner at using
<canvas>
so this was very helpful– Vincent Tang
Nov 26 '18 at 0:05
wow thanks so much for the codereview :). I'm still a beginner at using
<canvas>
so this was very helpful– Vincent Tang
Nov 26 '18 at 0:05
That will obviously depend on the type of application, but for the ones that only do draw in response to user events, keeping an rAF loop active is probably not the best direction either ;-) You might want to throttle your event handlers instead, so that your tab can actually be free of computation when not interacting with it. Here is an old and basic implementation of a rAF based throttler
– Kaiido
Nov 26 '18 at 15:05
That will obviously depend on the type of application, but for the ones that only do draw in response to user events, keeping an rAF loop active is probably not the best direction either ;-) You might want to throttle your event handlers instead, so that your tab can actually be free of computation when not interacting with it. Here is an old and basic implementation of a rAF based throttler
– Kaiido
Nov 26 '18 at 15:05
@Kaiido frames are call as soon as possible after the display refresh, How do you stop renders in the time after the frame and before the next display refresh? Even the most basic render
ctx.clearRect(0,0,1,1)
takes 2000 time longer than if(redraw){ ...}
if redraw
is false
Your throttle on average lets through 1 extra render per frame (rounding down and on slow machine) when moving the mouse, so in one second of move events your throttle generates unneeded renders consuming the equivalent of half an hour idle frame calls or 1 render = 33 seconds of rAF non renders– Blindman67
Nov 26 '18 at 17:19
@Kaiido frames are call as soon as possible after the display refresh, How do you stop renders in the time after the frame and before the next display refresh? Even the most basic render
ctx.clearRect(0,0,1,1)
takes 2000 time longer than if(redraw){ ...}
if redraw
is false
Your throttle on average lets through 1 extra render per frame (rounding down and on slow machine) when moving the mouse, so in one second of move events your throttle generates unneeded renders consuming the equivalent of half an hour idle frame calls or 1 render = 33 seconds of rAF non renders– Blindman67
Nov 26 '18 at 17:19
@Blindman67 I think you forgot rAF itself in your calculations ;-) even if internal code, it is far from being a noop. And I don't see where you see the extra render, throttling causes one lost render on average (we are always on the late frame)
– Kaiido
Nov 26 '18 at 22:30
@Blindman67 I think you forgot rAF itself in your calculations ;-) even if internal code, it is far from being a noop. And I don't see where you see the extra render, throttling causes one lost render on average (we are always on the late frame)
– Kaiido
Nov 26 '18 at 22:30
@Your throttle lets extra rAF calls in the time between rAF exit, and the next display refresh, which could be as long as 15+ms. Seq.. Display refresh, then mouse event requests frame, Frame gets called immediately after event exits and clears the active flag and exits, Then another mouse event fires, and requests another frame, that gets called after event exits. thats two renders in less than 16ms. How do you stop renders in the time after the frame and before the next display refresh?
– Blindman67
Nov 26 '18 at 23:01
@Your throttle lets extra rAF calls in the time between rAF exit, and the next display refresh, which could be as long as 15+ms. Seq.. Display refresh, then mouse event requests frame, Frame gets called immediately after event exits and clears the active flag and exits, Then another mouse event fires, and requests another frame, that gets called after event exits. thats two renders in less than 16ms. How do you stop renders in the time after the frame and before the next display refresh?
– Blindman67
Nov 26 '18 at 23:01
|
show 12 more comments
After fixing the Syntax Error of calling requestAnimationFrame(init())
instead of requestAnimationFrame(init)
, note the ()
, all that remains is to coerce your HTMLInput's value
to a Number so you don't end up doing "800" + 150
which results in "800150"
.
myRange.oninput = function() {
console.log(this.value + 150);
}
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
var canvas = document.querySelector("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.width = 1600;
canvas.height = 800;
var ct = canvas.getContext("2d");
// TODO
// 1. Make a center point
// 2. Draw lines jutting from center
// 3. Draw a line parallel to canvas bottom
// 4. Draw an adjoining item upward
// x, y
// right, down
// Nomenclature
// x0a
// coordinate type, vanishingPt#, endPtName
// Vanishing point 0
var x0 = 400;
var y0 = 400;
// Vanishing point end 0a
var x0a = 0;
var y0a = 2 * y0;
// Vanishing point end 0b
var x0b = 2 * x0;
var y0b = 2 * y0;
// Define delta
var delta = 700;
function init() {
console.log(delta, "delta");
console.log(x0b, "x0b");
console.log(y0b, "y0b");
console.log(x0, "x0");
console.log(y0, "y0");
// First Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0a, y0a);
ct.strokeStyle = 'red';
ct.stroke();
// Second Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0b, x0b);
ct.strokeStyle = 'green';
ct.stroke();
// House based on second Line
ct.beginPath();
ct.moveTo(x0b, y0b); // starting point
ct.lineTo(x0b + delta, y0b); // right x+100
ct.lineTo(x0b + delta, y0b - delta); // up y-100
ct.lineTo(x0b, y0b - delta); // left x-100
ct.lineTo(x0b, y0b); // down y+100
ct.lineTo(x0b, y0b - delta); // back up y-100
//calculate
ct.lineTo(x0, y0);
ct.lineTo(x0b + delta, y0b - delta);
ct.strokeStyle = 'blue';
ct.stroke();
}
init();
var slider = document.getElementById("myRange");
slider.oninput = function () {
// coerce to Number
delta = +this.value;
requestAnimationFrame(init); // redraw everything
}
body {
background-color: lightgray;
display: flex;
justify-content: center;
align-items: center;
}
.slideContainer {
position: fixed;
right: 30px;
top: 30px;
background-color: lightblue;
z-index: 20;
}
canvas {
border: 1px dotted red;
padding: 80px;
background-color: lightgray;
transform: scale(0.5);
}
<div class="wrapper">
<div class="slideContainer">
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
</div>
<canvas id="canvas"></canvas>
</div>
ah I see now.this.value
from the slider is a string. Thanks for the help :)
– Vincent Tang
Nov 25 '18 at 5:27
add a comment |
After fixing the Syntax Error of calling requestAnimationFrame(init())
instead of requestAnimationFrame(init)
, note the ()
, all that remains is to coerce your HTMLInput's value
to a Number so you don't end up doing "800" + 150
which results in "800150"
.
myRange.oninput = function() {
console.log(this.value + 150);
}
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
var canvas = document.querySelector("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.width = 1600;
canvas.height = 800;
var ct = canvas.getContext("2d");
// TODO
// 1. Make a center point
// 2. Draw lines jutting from center
// 3. Draw a line parallel to canvas bottom
// 4. Draw an adjoining item upward
// x, y
// right, down
// Nomenclature
// x0a
// coordinate type, vanishingPt#, endPtName
// Vanishing point 0
var x0 = 400;
var y0 = 400;
// Vanishing point end 0a
var x0a = 0;
var y0a = 2 * y0;
// Vanishing point end 0b
var x0b = 2 * x0;
var y0b = 2 * y0;
// Define delta
var delta = 700;
function init() {
console.log(delta, "delta");
console.log(x0b, "x0b");
console.log(y0b, "y0b");
console.log(x0, "x0");
console.log(y0, "y0");
// First Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0a, y0a);
ct.strokeStyle = 'red';
ct.stroke();
// Second Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0b, x0b);
ct.strokeStyle = 'green';
ct.stroke();
// House based on second Line
ct.beginPath();
ct.moveTo(x0b, y0b); // starting point
ct.lineTo(x0b + delta, y0b); // right x+100
ct.lineTo(x0b + delta, y0b - delta); // up y-100
ct.lineTo(x0b, y0b - delta); // left x-100
ct.lineTo(x0b, y0b); // down y+100
ct.lineTo(x0b, y0b - delta); // back up y-100
//calculate
ct.lineTo(x0, y0);
ct.lineTo(x0b + delta, y0b - delta);
ct.strokeStyle = 'blue';
ct.stroke();
}
init();
var slider = document.getElementById("myRange");
slider.oninput = function () {
// coerce to Number
delta = +this.value;
requestAnimationFrame(init); // redraw everything
}
body {
background-color: lightgray;
display: flex;
justify-content: center;
align-items: center;
}
.slideContainer {
position: fixed;
right: 30px;
top: 30px;
background-color: lightblue;
z-index: 20;
}
canvas {
border: 1px dotted red;
padding: 80px;
background-color: lightgray;
transform: scale(0.5);
}
<div class="wrapper">
<div class="slideContainer">
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
</div>
<canvas id="canvas"></canvas>
</div>
ah I see now.this.value
from the slider is a string. Thanks for the help :)
– Vincent Tang
Nov 25 '18 at 5:27
add a comment |
After fixing the Syntax Error of calling requestAnimationFrame(init())
instead of requestAnimationFrame(init)
, note the ()
, all that remains is to coerce your HTMLInput's value
to a Number so you don't end up doing "800" + 150
which results in "800150"
.
myRange.oninput = function() {
console.log(this.value + 150);
}
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
var canvas = document.querySelector("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.width = 1600;
canvas.height = 800;
var ct = canvas.getContext("2d");
// TODO
// 1. Make a center point
// 2. Draw lines jutting from center
// 3. Draw a line parallel to canvas bottom
// 4. Draw an adjoining item upward
// x, y
// right, down
// Nomenclature
// x0a
// coordinate type, vanishingPt#, endPtName
// Vanishing point 0
var x0 = 400;
var y0 = 400;
// Vanishing point end 0a
var x0a = 0;
var y0a = 2 * y0;
// Vanishing point end 0b
var x0b = 2 * x0;
var y0b = 2 * y0;
// Define delta
var delta = 700;
function init() {
console.log(delta, "delta");
console.log(x0b, "x0b");
console.log(y0b, "y0b");
console.log(x0, "x0");
console.log(y0, "y0");
// First Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0a, y0a);
ct.strokeStyle = 'red';
ct.stroke();
// Second Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0b, x0b);
ct.strokeStyle = 'green';
ct.stroke();
// House based on second Line
ct.beginPath();
ct.moveTo(x0b, y0b); // starting point
ct.lineTo(x0b + delta, y0b); // right x+100
ct.lineTo(x0b + delta, y0b - delta); // up y-100
ct.lineTo(x0b, y0b - delta); // left x-100
ct.lineTo(x0b, y0b); // down y+100
ct.lineTo(x0b, y0b - delta); // back up y-100
//calculate
ct.lineTo(x0, y0);
ct.lineTo(x0b + delta, y0b - delta);
ct.strokeStyle = 'blue';
ct.stroke();
}
init();
var slider = document.getElementById("myRange");
slider.oninput = function () {
// coerce to Number
delta = +this.value;
requestAnimationFrame(init); // redraw everything
}
body {
background-color: lightgray;
display: flex;
justify-content: center;
align-items: center;
}
.slideContainer {
position: fixed;
right: 30px;
top: 30px;
background-color: lightblue;
z-index: 20;
}
canvas {
border: 1px dotted red;
padding: 80px;
background-color: lightgray;
transform: scale(0.5);
}
<div class="wrapper">
<div class="slideContainer">
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
</div>
<canvas id="canvas"></canvas>
</div>
After fixing the Syntax Error of calling requestAnimationFrame(init())
instead of requestAnimationFrame(init)
, note the ()
, all that remains is to coerce your HTMLInput's value
to a Number so you don't end up doing "800" + 150
which results in "800150"
.
myRange.oninput = function() {
console.log(this.value + 150);
}
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
var canvas = document.querySelector("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.width = 1600;
canvas.height = 800;
var ct = canvas.getContext("2d");
// TODO
// 1. Make a center point
// 2. Draw lines jutting from center
// 3. Draw a line parallel to canvas bottom
// 4. Draw an adjoining item upward
// x, y
// right, down
// Nomenclature
// x0a
// coordinate type, vanishingPt#, endPtName
// Vanishing point 0
var x0 = 400;
var y0 = 400;
// Vanishing point end 0a
var x0a = 0;
var y0a = 2 * y0;
// Vanishing point end 0b
var x0b = 2 * x0;
var y0b = 2 * y0;
// Define delta
var delta = 700;
function init() {
console.log(delta, "delta");
console.log(x0b, "x0b");
console.log(y0b, "y0b");
console.log(x0, "x0");
console.log(y0, "y0");
// First Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0a, y0a);
ct.strokeStyle = 'red';
ct.stroke();
// Second Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0b, x0b);
ct.strokeStyle = 'green';
ct.stroke();
// House based on second Line
ct.beginPath();
ct.moveTo(x0b, y0b); // starting point
ct.lineTo(x0b + delta, y0b); // right x+100
ct.lineTo(x0b + delta, y0b - delta); // up y-100
ct.lineTo(x0b, y0b - delta); // left x-100
ct.lineTo(x0b, y0b); // down y+100
ct.lineTo(x0b, y0b - delta); // back up y-100
//calculate
ct.lineTo(x0, y0);
ct.lineTo(x0b + delta, y0b - delta);
ct.strokeStyle = 'blue';
ct.stroke();
}
init();
var slider = document.getElementById("myRange");
slider.oninput = function () {
// coerce to Number
delta = +this.value;
requestAnimationFrame(init); // redraw everything
}
body {
background-color: lightgray;
display: flex;
justify-content: center;
align-items: center;
}
.slideContainer {
position: fixed;
right: 30px;
top: 30px;
background-color: lightblue;
z-index: 20;
}
canvas {
border: 1px dotted red;
padding: 80px;
background-color: lightgray;
transform: scale(0.5);
}
<div class="wrapper">
<div class="slideContainer">
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
</div>
<canvas id="canvas"></canvas>
</div>
myRange.oninput = function() {
console.log(this.value + 150);
}
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
myRange.oninput = function() {
console.log(this.value + 150);
}
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
var canvas = document.querySelector("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.width = 1600;
canvas.height = 800;
var ct = canvas.getContext("2d");
// TODO
// 1. Make a center point
// 2. Draw lines jutting from center
// 3. Draw a line parallel to canvas bottom
// 4. Draw an adjoining item upward
// x, y
// right, down
// Nomenclature
// x0a
// coordinate type, vanishingPt#, endPtName
// Vanishing point 0
var x0 = 400;
var y0 = 400;
// Vanishing point end 0a
var x0a = 0;
var y0a = 2 * y0;
// Vanishing point end 0b
var x0b = 2 * x0;
var y0b = 2 * y0;
// Define delta
var delta = 700;
function init() {
console.log(delta, "delta");
console.log(x0b, "x0b");
console.log(y0b, "y0b");
console.log(x0, "x0");
console.log(y0, "y0");
// First Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0a, y0a);
ct.strokeStyle = 'red';
ct.stroke();
// Second Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0b, x0b);
ct.strokeStyle = 'green';
ct.stroke();
// House based on second Line
ct.beginPath();
ct.moveTo(x0b, y0b); // starting point
ct.lineTo(x0b + delta, y0b); // right x+100
ct.lineTo(x0b + delta, y0b - delta); // up y-100
ct.lineTo(x0b, y0b - delta); // left x-100
ct.lineTo(x0b, y0b); // down y+100
ct.lineTo(x0b, y0b - delta); // back up y-100
//calculate
ct.lineTo(x0, y0);
ct.lineTo(x0b + delta, y0b - delta);
ct.strokeStyle = 'blue';
ct.stroke();
}
init();
var slider = document.getElementById("myRange");
slider.oninput = function () {
// coerce to Number
delta = +this.value;
requestAnimationFrame(init); // redraw everything
}
body {
background-color: lightgray;
display: flex;
justify-content: center;
align-items: center;
}
.slideContainer {
position: fixed;
right: 30px;
top: 30px;
background-color: lightblue;
z-index: 20;
}
canvas {
border: 1px dotted red;
padding: 80px;
background-color: lightgray;
transform: scale(0.5);
}
<div class="wrapper">
<div class="slideContainer">
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
</div>
<canvas id="canvas"></canvas>
</div>
var canvas = document.querySelector("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.width = 1600;
canvas.height = 800;
var ct = canvas.getContext("2d");
// TODO
// 1. Make a center point
// 2. Draw lines jutting from center
// 3. Draw a line parallel to canvas bottom
// 4. Draw an adjoining item upward
// x, y
// right, down
// Nomenclature
// x0a
// coordinate type, vanishingPt#, endPtName
// Vanishing point 0
var x0 = 400;
var y0 = 400;
// Vanishing point end 0a
var x0a = 0;
var y0a = 2 * y0;
// Vanishing point end 0b
var x0b = 2 * x0;
var y0b = 2 * y0;
// Define delta
var delta = 700;
function init() {
console.log(delta, "delta");
console.log(x0b, "x0b");
console.log(y0b, "y0b");
console.log(x0, "x0");
console.log(y0, "y0");
// First Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0a, y0a);
ct.strokeStyle = 'red';
ct.stroke();
// Second Line
ct.beginPath();
ct.moveTo(x0, y0);
ct.lineTo(x0b, x0b);
ct.strokeStyle = 'green';
ct.stroke();
// House based on second Line
ct.beginPath();
ct.moveTo(x0b, y0b); // starting point
ct.lineTo(x0b + delta, y0b); // right x+100
ct.lineTo(x0b + delta, y0b - delta); // up y-100
ct.lineTo(x0b, y0b - delta); // left x-100
ct.lineTo(x0b, y0b); // down y+100
ct.lineTo(x0b, y0b - delta); // back up y-100
//calculate
ct.lineTo(x0, y0);
ct.lineTo(x0b + delta, y0b - delta);
ct.strokeStyle = 'blue';
ct.stroke();
}
init();
var slider = document.getElementById("myRange");
slider.oninput = function () {
// coerce to Number
delta = +this.value;
requestAnimationFrame(init); // redraw everything
}
body {
background-color: lightgray;
display: flex;
justify-content: center;
align-items: center;
}
.slideContainer {
position: fixed;
right: 30px;
top: 30px;
background-color: lightblue;
z-index: 20;
}
canvas {
border: 1px dotted red;
padding: 80px;
background-color: lightgray;
transform: scale(0.5);
}
<div class="wrapper">
<div class="slideContainer">
<input type="range" min="1" max="800" value="50" class="slider" id="myRange">
</div>
<canvas id="canvas"></canvas>
</div>
answered Nov 25 '18 at 5:23
KaiidoKaiido
46.4k468109
46.4k468109
ah I see now.this.value
from the slider is a string. Thanks for the help :)
– Vincent Tang
Nov 25 '18 at 5:27
add a comment |
ah I see now.this.value
from the slider is a string. Thanks for the help :)
– Vincent Tang
Nov 25 '18 at 5:27
ah I see now.
this.value
from the slider is a string. Thanks for the help :)– Vincent Tang
Nov 25 '18 at 5:27
ah I see now.
this.value
from the slider is a string. Thanks for the help :)– Vincent Tang
Nov 25 '18 at 5:27
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53464401%2fcanvas-request-animation-out-of-frame-on-slider-input-to-javascript-variable%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown