Hello I have been trying to figure something out for a couple days, I'm hoping someone may be able to shed some light on the situation.
I've been trying to code out a learning project. The goal is basically a gantt chart where I'd like to plot some events on eventually.
I am drawing out the timeline on a canvas, right now I have the "Seconds" lines being drawn 50px apart, with 4 shorter lines between them representing 200ms spaces.enter code here
var aTime = "00:1:00.0";
var h, m, s, ms, totalSeconds, thecanvas = null;
// within the loop at line 76 I'm trying ( i * secondsSpacing ) to get the X
//position to draw the lines for each second.
//Why would this not drawing the lines 50 pixels apart?
var secondsSpaceing = 50;
var spaceTime = 44;
var mousePositioning = { x:0, y:0};
var zoom1a = 1;
function drawStroke(sX, sY, eX, eY, color) {
thecontext.strokeStyle=color;
thecontext.lineWidth=1;
thecontext.beginPath();
thecontext.moveTo(sX,sY);
thecontext.lineTo(eX,eY);
thecontext.stroke();
}
function secToMinSec(seconds) {
var min = Math.floor(seconds / 60);
var sec = Math.ceil(seconds % 60);
sec = (sec < 10) ? "0" + sec : sec;
return new Array(min, sec);
}
var mouseXY = function(eve) {
if(!eve) var eve = window.event;
var totalOffsetX = 0;
var totalOffsetY = 0;
var canvasX = 0;
var canvasY = 0;
var canvas = this;
do{
totalOffsetX += canvas.offsetLeft;
totalOffsetY += canvas.offsetTop;
}
while(canvas = canvas.offsetParent)
canvasX = eve.pageX - totalOffsetX;
canvasY = eve.pageY - totalOffsetY;
return {'x':canvasX, 'y':canvasY}
}
$(document).ready(function() {
thecanvas = document.getElementById("thecanvas");
thecontext = thecanvas.getContext("2d");
HTMLCanvasElement.prototype.xy = mouseXY;
$(thecanvas).mousemove(function(e) {
mousePositioning = thecanvas.xy(e);
$("#output").html( "X = " + mousePositioning.x +
"<br> Y = " + mousePositioning.y );
});
var splitTimeStrMS = aTime.split('.');
var splitTimeStr = splitTimeStrMS[0].split(':');
h = parseInt(splitTimeStr[0]);
m = parseInt(splitTimeStr[1]);
s = parseInt(splitTimeStr[2]);
ms = parseFloat(splitTimeStrMS[1]);
var X = 60;
totalSeconds = (h * X * X) + (m * X) + s;
var divided = Math.ceil(totalSeconds / zoom1a);
var timeChartArray = new Array();
for(var i = 0; i <= divided; i++) {
timeChartArray.push(i * zoom1a);
}
var neededCanvasWidth = Math.ceil(timeChartArray.length * secondsSpaceing);
var timeStr = null;
var lineColor = "#000000";
if(neededCanvasWidth > ($("#thecanvas").attr("width"))) {
$("#thecanvas").attr("width", neededCanvasWidth);
thecontext.font="normal 12px Arial";
thecontext.fillStyle = lineColor;
for(var i = 0; i < timeChartArray.length; i++) {
//draw the line
var xline = parseFloat(i * secondsSpaceing);
drawStroke(xline, 0, xline, 8, lineColor);
//draw the time text
var timeStr = secToMinSec( timeChartArray[i] );
var timeFormatted = timeStr[0] + ":" + timeStr[1];
var timeXpos = (xline - 10);
if(timeFormatted != "0:00") {
thecontext.fillText(timeFormatted, timeXpos,24);
}
}
}
});
#canvasOut {position:relative; width:100%; width:700px; background:#222222;
overflow:visible; }
#thecanvas {position:relative; height:140px; background:#fff; }
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div id="canvasOut">
<canvas width="200" id="thecanvas"></canvas>
</div>
<div id="output">
</div>
<div id="output2">
</div>
If you move the mouse over the one second mark, you will see it is at x:50, two second mark is x:100 but then the three second mark is x:149, the same pattern continues and I keep losing seconds. By the fifth second, it should be at x:250 but its lost two seconds and is x:248. I'm still trying to figure this out myself but hopeful someone can shed some light as it's becoming discouraging. Thanks for reading.
EDIT: the code snippet worked in the editor, but I noticed when I press the "Run snippet" button that it's not showing the mouse position as it did in the editor, and on jsFiddle.
Here is a link to the project on jsFiddle:
https://jsfiddle.net/4y0q2pdw/19/
Thanks again
Check this.I saw that every 1 sec the function subtracted 4px. So I replace the
var xline = parseFloat(i * secondsSpaceing);
with the
var xline =parseFloat((i * secondsSpaceing)+3.6*i);
Initially I set instead of 3.6 the integer 4 but the function added then 1 or 2px after the 8 seconds line.So to be more accurate I replace the 4 by 3.6 that is more accurate.
Related
I have a repeat function which runs on a button on-click event, however it's not working properly. Maybe because there are too many setIntervals running although I tried to clear them all. I also made sure to reset the variables used back to their initial values, however the moving circle keeps showing up faded when the shoot again button is pressed, so I'm assuming there's an issue with the setInterval, however, I don't know what it is.It's also not drawing the basketball again.
var level = prompt("Type 1 for hard, 2 for medium, and 3 for easy.")
var dt = level / 100;
var ctx = canvas.getContext("2d");
var intervalId2;
var intervalId1;
//Initializing Variables
var dt = level / 100;
const PI = 3.14;
var r = 20;
var x = r + 1;
var y = 500 / 1.2;
var a = 1;
var shift = 380;
var leftshift = 35;
var xc = 145;
var yc = 300;
var rc = 50;
var dxc = 95;
var dyc = 300;
var theta = 0;
var resetVars = function() {
dt = 0.01;
var x = r + 1;
var y = 500 / 1.2;
var xc = 145;
var yc = 300;
var dxc = 95;
var dyc = 300;
var theta = 0;
};
//resetVars();
var reset = function() {
ctx.clearRect(0, 0, 800, 800);
drawHoop()
};
//Interval Id to eventually clear it to stop this to shoot
var intervalID = setInterval(moveCirc, 10000 * dt);
var count = 0;
//shoot when spacebar is pressed
document.body.onkeyup = function(shoot1) {
if (dxc <= 110 && shoot1.keyCode == 32) {
console.log(dxc);
clearInterval(intervalID);
make();
count = count + 1;
document.getElementById("count").innerHTML = "You've made " + count + " baskets.";
}
if (dxc > 110 && shoot1.keyCode == 32) {
console.log(dxc);
clearInterval(intervalID);
miss();
document.getElementById("count").innerHTML = "You've made " + count + " baskets.";
}
};
var repeat = function() {
reset();
clearInterval(intervalID);
clearInterval(intervalId2);
clearInterval(intervalId1);
resetVars();
drawBasketball();
drawHoop();
moveCirc();
intervalID = setInterval(moveCirc, 10000 * dt);
document.body.onkeyup = function(shoot1) {
if (dxc <= 110 && shoot1.keyCode == 32) {
console.log(dxc);
clearInterval(intervalID);
make();
count = count + 1;
document.getElementById("count").innerHTML = "You've made " + count + " baskets.";
}
if (dxc > 110 && shoot1.keyCode == 32) {
console.log(dxc);
clearInterval(intervalID);
miss();
document.getElementById("count").innerHTML = "You've made " + count + " baskets.";
}
};
};
<html>
<canvas id="canvas" width="1000" height="500"> </canvas>
<body style="background-color:powderblue;">
<p id="count"></p>
<button id="again" onclick="repeat()"> Shoot Again </button>
</body>
This should make a stop button for a repeating function
<script>
var int=self.setInterval(function, 60000);
</script>
<!-- Stop Button -->
Stop
I'm using setInterval to call a function that animates a fractal on a HTML5 canvas. There is also a slider to allow the user to change the quality of the fractal. Everything works fine until I start changing the slider. When I change it, the fractal animation becomes choppy, and eventually the "drawFractal" function stops being called.
Here is the slider HTML:
<input type="range" id="qualitySlider" min="1" max="10"></input>
Here is the javascript (it just generates a fractal):
var count = 0.5;
var slider = document.getElementById("qualitySlider");
var g = document.getElementById("drawingCanvas").getContext("2d");
function drawFractal() {
var cellSize = Math.ceil(slider.value);
//canvas is 700 by 400
g.fillStyle = "black";
g.clearRect(0, 0, 700, 400);
//Eveything from here to the end of this function generates the fractal
var imagC = Math.cos(count)*0.8;
var realC = Math.sin(count)*0.5;
for (x = 0; x < 700; x+=cellSize) {
for (y = 0; y < 400; y+=cellSize) {
var yCoord = (x / 700.0 - 0.5)*3;
var xCoord = (y / 400.0 - 0.5)*3;
var real = xCoord;
var imag = yCoord;
var broken = 0;
for (i = 0; i < 8; i++) {
var temp = real*real - imag*imag + realC;
imag = 2*imag*real + imagC;
real = temp;
if (real*real + imag*imag >= 4) {
broken = true;
break;
}
}
if (!broken) {
g.fillRect(x, y, cellSize, cellSize);
}
}
}
count = count + 0.04;
}
setInterval(drawFractal, 60);
I just need the "drawFractal" function to be called reliably every 60 milliseconds.
This is my improved code. I just used requestAnimationFrame to recursively call the "drawFractal" function. I also restricted the animation to 24 frames/sec with the setTimeout function.
var count = 0.5;
var qualitySlider = document.getElementById("qualitySlider");
var g = document.getElementById("drawingCanvas").getContext("2d");
function drawFractal() {
var cellSize = Math.ceil(qualitySlider.value);
//canvas is 700 by 400
g.fillStyle = "black";
g.clearRect(0, 0, 700, 400);
var imagC = Math.cos(count)*0.8;
var realC = Math.sin(count)*0.5;
for (x = 0; x < 700; x+=cellSize) {
for (y = 0; y < 400; y+=cellSize) {
var yCoord = (x / 700.0 - 0.5)*3;
var xCoord = (y / 400.0 - 0.5)*3;
var real = xCoord;
var imag = yCoord;
var broken = 0;
for (i = 0; i < 8; i++) {
var temp = real*real - imag*imag + realC;
imag = 2*imag*real + imagC;
real = temp;
if (real*real + imag*imag >= 4) {
broken = true;
break;
}
}
if (!broken) {
g.fillRect(x, y, cellSize, cellSize);
}
}
}
count = count + 0.04;
setTimeout(function() {
requestAnimationFrame(drawFractal);
}, 41);
}
drawFractal();
You are using setInterval() to call drawFractal every 60 ms, and then every time drawFractal is executed, you're calling setInterval() again, which is unnecessary. You now have two timers attempting to draw fractals every 60 ms... then you'll have 4, then 8, etc.
You need to either (1) call setInterval() once at the start of program execution and not call it again, or (2) switch to using setTimeout(), and call it at the end of each drawFractal().
I'd use the second option, just in case your fractal ever takes more than 60 ms to draw.
We're working with the HTML5 canvas, displaying lots of images at one time.
This is working pretty well but recently we've had a problem with chrome.
When drawing images on to a canvas you seem to reach a certain point where the performance degrades very quickly.
It's not a slow effect, it seems that you go right from 60fps to 2-4fps.
Here's some reproduction code:
// Helpers
// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/random
function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }
// http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
window.requestAnimFrame = (function () { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000 / 60); }; })();
// https://github.com/mrdoob/stats.js
var Stats = function () { var e = Date.now(), t = e; var n = 0, r = Infinity, i = 0; var s = 0, o = Infinity, u = 0; var a = 0, f = 0; var l = document.createElement("div"); l.id = "stats"; l.addEventListener("mousedown", function (e) { e.preventDefault(); y(++f % 2) }, false); l.style.cssText = "width:80px;opacity:0.9;cursor:pointer"; var c = document.createElement("div"); c.id = "fps"; c.style.cssText = "padding:0 0 3px 3px;text-align:left;background-color:#002"; l.appendChild(c); var h = document.createElement("div"); h.id = "fpsText"; h.style.cssText = "color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px"; h.innerHTML = "FPS"; c.appendChild(h); var p = document.createElement("div"); p.id = "fpsGraph"; p.style.cssText = "position:relative;width:74px;height:30px;background-color:#0ff"; c.appendChild(p); while (p.children.length < 74) { var d = document.createElement("span"); d.style.cssText = "width:1px;height:30px;float:left;background-color:#113"; p.appendChild(d) } var v = document.createElement("div"); v.id = "ms"; v.style.cssText = "padding:0 0 3px 3px;text-align:left;background-color:#020;display:none"; l.appendChild(v); var m = document.createElement("div"); m.id = "msText"; m.style.cssText = "color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px"; m.innerHTML = "MS"; v.appendChild(m); var g = document.createElement("div"); g.id = "msGraph"; g.style.cssText = "position:relative;width:74px;height:30px;background-color:#0f0"; v.appendChild(g); while (g.children.length < 74) { var d = document.createElement("span"); d.style.cssText = "width:1px;height:30px;float:left;background-color:#131"; g.appendChild(d) } var y = function (e) { f = e; switch (f) { case 0: c.style.display = "block"; v.style.display = "none"; break; case 1: c.style.display = "none"; v.style.display = "block"; break } }; var b = function (e, t) { var n = e.appendChild(e.firstChild); n.style.height = t + "px" }; return { REVISION: 11, domElement: l, setMode: y, begin: function () { e = Date.now() }, end: function () { var f = Date.now(); n = f - e; r = Math.min(r, n); i = Math.max(i, n); m.textContent = n + " MS (" + r + "-" + i + ")"; b(g, Math.min(30, 30 - n / 200 * 30)); a++; if (f > t + 1e3) { s = Math.round(a * 1e3 / (f - t)); o = Math.min(o, s); u = Math.max(u, s); h.textContent = s + " FPS (" + o + "-" + u + ")"; b(p, Math.min(30, 30 - s / 100 * 30)); t = f; a = 0 } return f }, update: function () { e = this.end() } } }
// Firefox events suck
function getOffsetXY(eventArgs) { return { X: eventArgs.offsetX == undefined ? eventArgs.layerX : eventArgs.offsetX, Y: eventArgs.offsetY == undefined ? eventArgs.layerY : eventArgs.offsetY }; }
function getWheelDelta(eventArgs) { if (!eventArgs) eventArgs = event; var w = eventArgs.wheelDelta; var d = eventArgs.detail; if (d) { if (w) { return w / d / 40 * d > 0 ? 1 : -1; } else { return -d / 3; } } else { return w / 120; } }
// Reproduction Code
var stats = new Stats();
document.body.appendChild(stats.domElement);
var masterCanvas = document.getElementById('canvas');
var masterContext = masterCanvas.getContext('2d');
var viewOffsetX = 0;
var viewOffsetY = 0;
var viewScaleFactor = 1;
var viewMinScaleFactor = 0.1;
var viewMaxScaleFactor = 10;
var mouseWheelSensitivity = 10; //Fudge Factor
var isMouseDown = false;
var lastMouseCoords = null;
var imageDimensionPixelCount = 25;
var paddingPixelCount = 2;
var canvasDimensionImageCount = 50;
var totalImageCount = Math.pow(canvasDimensionImageCount, 2);
var images = null;
function init() {
images = createLocalImages(totalImageCount, imageDimensionPixelCount);
initInteraction();
renderLoop();
}
function initInteraction() {
var handleMouseDown = function (eventArgs) {
isMouseDown = true;
var offsetXY = getOffsetXY(eventArgs);
lastMouseCoords = [
offsetXY.X,
offsetXY.Y
];
};
var handleMouseUp = function (eventArgs) {
isMouseDown = false;
lastMouseCoords = null;
}
var handleMouseMove = function (eventArgs) {
if (isMouseDown) {
var offsetXY = getOffsetXY(eventArgs);
var panX = offsetXY.X - lastMouseCoords[0];
var panY = offsetXY.Y - lastMouseCoords[1];
pan(panX, panY);
lastMouseCoords = [
offsetXY.X,
offsetXY.Y
];
}
};
var handleMouseWheel = function (eventArgs) {
var mouseX = eventArgs.pageX - masterCanvas.offsetLeft;
var mouseY = eventArgs.pageY - masterCanvas.offsetTop;
var zoom = 1 + (getWheelDelta(eventArgs) / mouseWheelSensitivity);
zoomAboutPoint(mouseX, mouseY, zoom);
if (eventArgs.preventDefault !== undefined) {
eventArgs.preventDefault();
} else {
return false;
}
}
masterCanvas.addEventListener("mousedown", handleMouseDown, false);
masterCanvas.addEventListener("mouseup", handleMouseUp, false);
masterCanvas.addEventListener("mousemove", handleMouseMove, false);
masterCanvas.addEventListener("mousewheel", handleMouseWheel, false);
masterCanvas.addEventListener("DOMMouseScroll", handleMouseWheel, false);
}
function pan(panX, panY) {
masterContext.translate(panX / viewScaleFactor, panY / viewScaleFactor);
viewOffsetX -= panX / viewScaleFactor;
viewOffsetY -= panY / viewScaleFactor;
}
function zoomAboutPoint(zoomX, zoomY, zoomFactor) {
var newCanvasScale = viewScaleFactor * zoomFactor;
if (newCanvasScale < viewMinScaleFactor) {
zoomFactor = viewMinScaleFactor / viewScaleFactor;
} else if (newCanvasScale > viewMaxScaleFactor) {
zoomFactor = viewMaxScaleFactor / viewScaleFactor;
}
masterContext.translate(viewOffsetX, viewOffsetY);
masterContext.scale(zoomFactor, zoomFactor);
viewOffsetX = ((zoomX / viewScaleFactor) + viewOffsetX) - (zoomX / (viewScaleFactor * zoomFactor));
viewOffsetY = ((zoomY / viewScaleFactor) + viewOffsetY) - (zoomY / (viewScaleFactor * zoomFactor));
viewScaleFactor *= zoomFactor;
masterContext.translate(-viewOffsetX, -viewOffsetY);
}
function renderLoop() {
clearCanvas();
renderCanvas();
stats.update();
requestAnimFrame(renderLoop);
}
function clearCanvas() {
masterContext.clearRect(viewOffsetX, viewOffsetY, masterCanvas.width / viewScaleFactor, masterCanvas.height / viewScaleFactor);
}
function renderCanvas() {
for (var imageY = 0; imageY < canvasDimensionImageCount; imageY++) {
for (var imageX = 0; imageX < canvasDimensionImageCount; imageX++) {
var x = imageX * (imageDimensionPixelCount + paddingPixelCount);
var y = imageY * (imageDimensionPixelCount + paddingPixelCount);
var imageIndex = (imageY * canvasDimensionImageCount) + imageX;
var image = images[imageIndex];
masterContext.drawImage(image, x, y, imageDimensionPixelCount, imageDimensionPixelCount);
}
}
}
function createLocalImages(imageCount, imageDimension) {
var tempCanvas = document.createElement('canvas');
tempCanvas.width = imageDimension;
tempCanvas.height = imageDimension;
var tempContext = tempCanvas.getContext('2d');
var images = new Array();
for (var imageIndex = 0; imageIndex < imageCount; imageIndex++) {
tempContext.clearRect(0, 0, imageDimension, imageDimension);
tempContext.fillStyle = "rgb(" + getRandomInt(0, 255) + ", " + getRandomInt(0, 255) + ", " + getRandomInt(0, 255) + ")";
tempContext.fillRect(0, 0, imageDimension, imageDimension);
var image = new Image();
image.src = tempCanvas.toDataURL('image/png');
images.push(image);
}
return images;
}
// Get this party started
init();
And a jsfiddle link for your interactive pleasure:
http://jsfiddle.net/BtyL6/14/
This is drawing 50px x 50px images in a 50 x 50 (2500) grid on the canvas. I've also quickly tried with 25px x 25px and 50 x 50 (2500) images.
We have other local examples that deal with bigger images and larger numbers of images and the other browser start to struggle with these at higher values.
As a quick test I jacked up the code in the js fiddle to 100px x 100px and 100 x 100 (10000) images and that was still running at 16fps when fully zoomed out. (Note: I had to lower the viewMinScaleFactor to 0.01 to fit it all in when zoomed out.)
Chrome on the other hand seems to hit some kind of limit and the FPS drops from 60 to 2-4.
Here's some info about what we've tried and the results:
We've tried using setinterval rather than requestAnimationFrame.
If you load 10 images and draw them 250 times each rather than 2500 images drawn once each then the problem goes away. This seems to indicate that chrome is hitting some kind of limit/trigger as to how much data it's storing about the rendering.
We have culling (not rendering images outside of the visual range) in our more complex examples and while this helps it's not a solution as we need to be able to show all the images at once.
We have the images only being rendered if there have been changes in our local code, against this helps (when nothing changes, obviously) but it isn't a full solution because the canvas should be interactive.
In the example code we're creating the images using a canvas, but the code can also be run hitting a web service to provide the images and the same behaviour (slowness) will be seen.
We've found it very hard to even search for this issue, most results are from a couple of years ago and woefully out of date.
If any more information would be useful then please ask!
EDIT: Changed js fiddle URL to reflect the same code as in the question. The code itself didn't actually change, just the formatting. But I want to be consistent.
EDIT: Updated jsfiddle and and code with css to prevent selection and call requestAnim after the render loop is done.
In Canary this code freezes it on my computer. As to why this happens in Chrome the simple answer is that it uses a different implementation than f.ex. FF. In-depth detail I don't know, but there is obviously room for optimizing the implementation in this area.
I can give some tip however on how you can optimize the given code to make it run in Chrome as well :-)
There are several things here:
You are storing each block of colors as images. This seem to have a huge performance impact on Canary / Chrome.
You are calling requestAnimationFrame at the beginning of the loop
You are clearing and rendering even if there are no changes
Try to (addressing the points):
If you only need solid blocks of colors, draw them directly using fillRect() instead and keep the color indexes in an array (instead of images). Even if you draw them to an off-screen canvas you will only have to do one draw to main canvas instead of multiple image draw operations.
Move requestAnimationFrame to the end of the code block to avoid stacking.
Use dirty flag to prevent unnecessary rendering:
I modified the code a bit - I modified it to use solid colors to demonstrate where the performance impact is in Chrome / Canary.
I set a dirty flag in global scope as true (to render the initial scene) which is set to true each time the mouse move occur:
//global
var isDirty = true;
//mouse move handler
var handleMouseMove = function (eventArgs) {
// other code
isDirty = true;
// other code
};
//render loop
function renderLoop() {
if (isDirty) {
clearCanvas();
renderCanvas();
}
stats.update();
requestAnimFrame(renderLoop);
}
//in renderCanvas at the end:
function renderCanvas() {
// other code
isDirty = false;
}
You will of course need to check for caveats for the isDirty flag elsewhere and also introduce more criteria if it's cleared at the wrong moment. I would store the old position of the mouse and only (in the mouse move) if it changed set the dirty flag - I didn't modify this part though.
As you can see you will be able to run this in Chrome and in FF at a higher FPS.
I also assume (I didn't test) that you can optimize the clearCanvas() function by only drawing the padding/gaps instead of clearing the whole canvas. But that need to be tested.
Added a CSS-rule to prevent the canvas to be selected when using the mouse:
For further optimizing in cases such as this, which is event driven, you don't actually need an animation loop at all. You can just call the redraw when the coords or mouse-wheel changes.
Modification:
http://jsfiddle.net/BtyL6/10/
This was a legitimate bug in chrome.
https://code.google.com/p/chromium/issues/detail?id=247912
It has now been fixed and should be in a chrome mainline release soon.
So I need function like this one, -link- but just to move text up, not left. How to achieve this?
So, this is code that moves text left:
//Text fade
var bgcolor;
var fcolor;
var heading;
//Number of steps to fade
var steps;
var colors;
var color = 0;
var step = 1;
var interval1;
var interval2;
//fade: fader function
// Fade from backcolor to forecolor in specified number of steps
function fade(headingtext,backcolor,forecolor,numsteps) {
if (color == 0) {
steps = numsteps;
heading = "<font color='{COLOR}'>"+headingtext+"</strong></font>";
bgcolor = backcolor;
fcolor = forecolor;
colors = new Array(steps);
getFadeColors(bgcolor,fcolor,colors);
}
// insert fader color into message
var text_out = heading.replace("{COLOR}", colors[color]);
// write the message to the document
document.getElementById("fader").innerHTML = text_out;
// select next fader color
color += step;
if (color >= steps) clearInterval(interval1);
}
//getFadeColors: fills colors, using predefined Array, with color hex strings fading from ColorA to ColorB
//Note: Colors.length equals the number of steps to fade
function getFadeColors(ColorA, ColorB, Colors) {
len = Colors.length;
//Strip '#' from colors if present
if (ColorA.charAt(0)=='#') ColorA = ColorA.substring(1);
if (ColorB.charAt(0)=='#') ColorB = ColorB.substring(1);
//Substract red green and blue components from hex string
var r = HexToInt(ColorA.substring(0,2));
var g = HexToInt(ColorA.substring(2,4));
var b = HexToInt(ColorA.substring(4,6));
var r2 = HexToInt(ColorB.substring(0,2));
var g2 = HexToInt(ColorB.substring(2,4));
var b2 = HexToInt(ColorB.substring(4,6));
// calculate size of step for each color component
var rStep = Math.round((r2 - r) / len);
var gStep = Math.round((g2 - g) / len);
var bStep = Math.round((b2 - b) / len);
// fill Colors array with fader colors
for (i = 0; i < len-1; i++) {
Colors[i] = "#" + IntToHex(r) + IntToHex(g) + IntToHex(b);
r += rStep;
g += gStep;
b += bStep;
}
Colors[len-1] = ColorB; // make sure we finish exactly at ColorB
}
//IntToHex: converts integers between 0 - 255 into a two digit hex string.
function IntToHex(n) {
var result = n.toString(16);
if (result.length==1) result = "0"+result;
return result;
}
//HexToInt: converts two digit hex strings into integer.
function HexToInt(hex) {
return parseInt(hex, 16);
}
var startwidth = 0;
//scroll: Make the text scroll using the marginLeft element of the div container
function scroll(startw) {
if (startwidth == 0) {
startwidth=startw;
}
document.getElementById("fader").style.marginLeft = startwidth + "px";
if (startwidth > 1) {
startwidth -= 1;
} else {
clearInterval(interval2);
}
}
function fadeandscroll(txt,color1,color2,numsteps,fademilli,containerwidth,scrollmilli) {
interval1 = setInterval("fade('"+txt+"','"+color1+"','"+color2+"',"+numsteps+")",fademilli);
interval2 = setInterval("scroll("+containerwidth+")",scrollmilli);
}
Something like this seems to do what you want, but jQuery would have been easier.
Demo: Vertical Marquee Demo
window.document.addEventListener("DOMContentLoaded", function()
{
var elm = window.document.querySelectorAll("#display span")[0], height = elm.parentNode.offsetHeight;
elm.style.position = "relative";
elm.style.top = "0px";
var timer = setInterval(function()
{
var top = Number(elm.style.top.replace(/[^\d\-]/g, ''));
top = top > -height ? top - 1 : height;
elm.style.top = top + "px";
}, 50);
/*
* If you want to stop scrolling, call clearInterval(timer);
*
* Example set to stop when clicked.
*/
elm.addEventListener("click", function()
{
clearInterval(timer);
}, false);
}, false);
I'm trying to simulate the Matrix code rain with the canvas element and javascript. I am able to make one element drop at a time but not multiple. How do I drop multiple matrix rain drops. Here is my code:
<html>
<head>
<title>Matrix Code Rain</title>
<style>
*{margin:0; padding:0; }
body{background:black;}
</style>
</head>
<body>
<canvas id="c"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("c");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.background = "black";
var c = canvas.getContext("2d");
var code = ["<html>","<p>","<b>","<strong>","<head>","<body>","<a>","<i>","<div>","<form>","<ol>","<li>","<ul>","<pre>","<nav>","<footer>","<header>","<article>","<section>","<em>","<style>","<title>","<meta>","<br>","<table>"];
var rain = [ ];
var max = 10;
for(var i = 0; i < max; i++){
var drop = {};
drop.code = Math.round(Math.random() * code.length);
drop.x = Math.random() * canvas.width;
drop.y = 0;
drop.size = Math.random() * 40;
drop.speed = drop.size/4;
rain.push(drop);
}
var y = 0;
c.fillStyle="lime";
setTimeout(function(){
c.clearRect(0,0,canvas.width,canvas.height);
for(var i = 0; i < max; i++){
var drop = rain[i];
c.font = drop.size+"pt arial";
c.fillText(drop.code,drop.x,drop.y);
drop.y += drop.speed;
if(drop.y > canvas.height + drop.size)
drop.y = 0;
}
},1000/60);
</script>
</body>
</html>
Make a bunch of independent objects that all get their own word and position and speed.
Then print them all and advance them by their speed.
Here's a clean example for you:
http://jsfiddle.net/U5eFJ/
The important code:
var code = ["<html>", "<p>", "<b>", "<strong>", "<head>", "<body>", "<a>", "<i>", "<div>", "<form>", "<ol>", "<li>", "<ul>", "<pre>", "<nav>", "<footer>", "<header>", "<article>", "<section>", "<em>", "<style>", "<title>", "<meta>", "<br>", "<table>"];
// make 90 things to fall with a random code element and random starting location
var things = [];
var THINGCOUNT = 90;
for (var i = 0; i < THINGCOUNT; i++) {
var a = {};
//randomly pick one tag
a.code = code[Math.round(Math.random() * code.length)];
a.x = Math.random()*500; //random X
a.y = Math.random()*500 -500; // random Y that is above the screen
a.speed = Math.random()*10;
things.push(a);
}
setInterval(function() {
ctx.clearRect(0,0,500,500);
for (var i = 0; i < THINGCOUNT; i++) {
var a = things[i];
ctx.fillText(a.code, a.x, a.y);
a.y += a.speed; // fall downwards by the speed amount
if (a.y > 600) a.y = -50; // if off the screen at bottom put back to top
}
}, 90);
If you are running a windows computer you can make the java script open a .bat file that just says this.
`#echo off
mode 1000
#color a
:A
echo %random%%random%%random%%random%%random%%random%%random%%random%%random%%random%%random%%random%%random%%random%%random%%random%%random%%random%%random%
goto A'
This may not be what you want but I hope it helps =)
`