Hi I am trying to implement scroller from Teechart libraries. I have encountered an issue while implementing the scroller. Loading data to the scroller might have gone wrong in my case. But same data loading works well with a slider implementation. I have attached my code for data loading as well as scroller here. I can see data loading after performing fast forward or play of signal, which is a different function for data loading. However, the scroller does not move freely on the canvas. It only moves initial 10 secs later it hangs up unless I load data from a play function. Is there a way I can set Min and max values instead of specifying intial length for the scroller axes. I have observed that when i setminmax value data loading parts gets affected too.
function AddDataSeries() {
Chart1.series.items=[]; // empty previous content
// Take care of boundaries
// Stop at both ends when scrolling/shifting on time
if (onset<0) {
cancelAnimationFrame(myAnimation);
onset = 0;
} // Reach the start
if (onset>nPoints-timeInterval) {
cancelAnimationFrame(myAnimation);
onset = nPoints-timeInterval;
} // Reach the end
// 1. Data Segmentation for current display
var ch = 0;
for (var i=1; i<=header_nChannels; i++) {
// Declare local version data to store the data
var str = "var Y"+i+"=[];"; // var Yi = []
eval(str);
// Segment using onset
var str = "Y"+i+"=Y"+i+"_all.slice(onset, onset+timeInterval);"; // Yi = Yi_all.slice(onset, onset+timeInterval);
eval(str);
}
}
Draw teechart function along with a scroller
function draw_TeeChart() {
var w = window.innerWidth, h = window.innerHeight;
// Initialize Teechart
Chart1 = new Tee.Chart("canvas");
document.getElementById("canvas").style.position = "relative";
document.getElementById("canvas").width= Math.round(0.82*w);document.getElementById("canvas").height= Math.round(0.89*h); //Chart1.bounds.x = Math.round(0.01*w);
Chart1.bounds.x = 14;Chart1.bounds.y= 10;
Chart1.bounds.width = Math.round(chartW*w);Chart1.bounds.height= Math.round(0.88*h);
Chart1.legend.visible = false; Chart1.panel.transparent = true;
Chart1.title.visible = false;Chart1.axes.bottom.title.text = " ";
Chart1.axes.left.increment = 1;
Chart1.panel.transparent = true;
Chart1.legend.visible = false;
// Chart1.axes.bottom.setMinMax(0, 1);
Chart1.axes.bottom.setMinMax(onset, onset+timeInterval);
Chart1.title.visible = false;
Chart1.axes.bottom.title.text = " ";
Chart1.zoom.enabled = false;
Chart1.scroll.mouseButton = 0;
Chart1.cursor = "pointer";
Chart1.scroll.direction = "horizontal";
scroller = new Tee.Scroller("canvas2", Chart1);
scroller.min=0;
scroller.max=nPoints;
scroller.position=onset;
scroller.useRange=false;
scroller.thumbSize=12;
scroller.cursor ="pointer";
scroller.scroller.onDrawThumb = "";
Chart1.draw();
// cancelAnimationFrame(myAnimation); // no auto-play
AddDataSeries();
//Slider implementation
var slider=new Tee.Slider(Chart1);
slider.min=0;
slider.max=nPoints;
slider.position=onset;
slider.useRange=false;
slider.thumbSize=12;
slider.horizontal=true;
slider.bounds.x=Math.round(0.052*w);
slider.bounds.y= Math.round(0.85*h);
slider.bounds.width=Math.round(sliderW*w);
slider.bounds.height=25;
// Text position at cursor
chartTop = Chart1.bounds.y;
chartLeft = slider.bounds.x;
chartWidth = slider.bounds.width;
chartHeight = Chart1.bounds.height;
// Tools Add beforehand
Chart1.tools.add(slider); // slider
// Chart1.tools.add(scroller); //scroller
nTools = Chart1.tools.items.length; // remove the extra texts out of range;
slider.onChanging=function(slider,value) {
var x = Math.round(value);
if (x<0){
onset = 0;
}
else if(x>nPoints-timeInterval){
onset = nPoints-timeInterval;
}
else{
onset = x;
}
cancelAnimationFrame(myAnimation); // no auto-play
AddDataSeries();
}
Related
I am trying to make a sine wave with createBuffer(). Like following code.
var TWOPI = Math.PI * 2;
var Sinewave = function(freq, amp, phase){
var self = this;
this.src;
this.init = function(){
var osc = new self.Osc(phase);
var buffer = ac.createBuffer(1, osc.samplerate, osc.samplerate);
var buffering = buffer.getChannelData(0);
for(i = 0; i < buffering.length; i++){
buffering[i] = amp * this.sinetick(osc, freq);
}
this.src = ac.createBufferSource();
this.src.buffer = buffer;
this.src.loop = true;
this.src.connect(contect.destination);
}
this.Osc = function(_phase){
this.samplerate = context.sampleRate;
this.twopiovsr = TWOPI/this.samplerate;
this.curfreq = 0;
this.curphase = _phase;
this.incr = 0.0;
}
this.sinetick = function(osc, freq){
var val = Math.sin(osc.curphase);
if(osc.curfreq != freq){
osc.curfreq = freq;
osc.incr = osc.twopiovsr * freq;
}
osc.curphase += osc.incr;
if(osc.curphase >= TWOPI){
osc.curphase -= TWOPI;
}
if(osc.curphase < 0.0){
osc.curphase += TWOPI;
}
return val;
}
this.play = function(duration){
this.src.start(0);
this.src.stop(duration);
}
}
This only contains function for sine wave but I've succeeded to implement other shapes as well.
Reason for this in the first place was to set phase offset, if there's a better option please give me a notice.
So, When I look at the output signal through oscilloscope they look like how they should be. However when I try to modulate frequency of a regular createOscillator node with the signal created by code above, output is not pretty. When regular createOscillators nodes fm themselves, waves on the oscilloscope changes horizontally, only frequencies, but with the signal generated with the code above gives changes in both horizontal and vertical giving clips
what could be the problem? Thanks
And the problem was
var buffer = ac.createBuffer(1, osc.samplerate, osc.samplerate);
which should be
var buffer = ac.createBuffer(1, osc.samplerate/2, osc.samplerate);
Thanks guys
I'm trying to create an online web tool for eeg signal analysis. The tool suppose to display a graph of an eeg signal synchronize with a movie that was display to a subject.
I've already implemented it successfully on csharp but I can't find a way to do it easily with any of the know javascript chart that I saw.
A link of a good tool that do something similar can be found here:
http://www.mesta-automation.com/real-time-line-charts-with-wpf-and-dynamic-data-display/
I've tried using dygraph, and google chart. I know that it should be relatively easy to create an background thread on the server that examine the movie state every ~50ms. What I was not able to do is to create a marker of the movie position on the chart itself dynamically. I was able to draw on the dygraph but was not able to change the marker location.
just for clarification, I need to draw a vertical line as a marker.
I'm in great suffering. Please help :)
Thanks to Danvk I figure out how to do it.
Below is a jsfiddler links that demonstrate such a solution.
http://jsfiddle.net/ng9vy8mb/10/embedded/result/
below is the javascript code that do the task. It changes the location of the marker in synchronizing with the video.
There are still several improvement that can be done.
Currently, if the user had zoomed in the graph and then click on it, the zoom will be reset.
there is no support for you tube movies
I hope that soon I can post a more complete solution that will also enable user to upload the graph data and video from their computer
;
var dc;
var g;
var v;
var my_graph;
var my_area;
var current_time = 0;
//when the document is done loading, intialie the video events listeners
$(document).ready(function () {
v = document.getElementsByTagName('video')[0];
v.onseeking = function () {
current_time = v.currentTime * 1000;
draw_marker();
};
v.oncanplay = function () {
CreateGraph();
};
v.addEventListener('timeupdate', function (event) {
var t = document.getElementById('time');
t.innerHTML = v.currentTime;
g.updateOptions({
isZoomedIgnoreProgrammaticZoom: true
});
current_time = v.currentTime * 1000;
}, false);
});
function change_movie_position(e, x, points) {
v.currentTime = x / 1000;
}
function draw_marker() {
dc.fillStyle = "rgba(255, 0, 0, 0.5)";
var left = my_graph.toDomCoords(current_time, 0)[0] - 2;
var right = my_graph.toDomCoords(current_time + 2, 0)[0] + 2;
dc.fillRect(left, my_area.y, right - left, my_area.h);
};
//data creation
function CreateGraph() {
number_of_samples = v.duration * 1000;
// A basic sinusoidal data series.
var data = [];
for (var i = 0; i < number_of_samples; i++) {
var base = 10 * Math.sin(i / 90.0);
data.push([i, base, base + Math.sin(i / 2.0)]);
}
// Shift one portion out of line.
var highlight_start = 450;
var highlight_end = 500;
for (var i = highlight_start; i <= highlight_end; i++) {
data[i][2] += 5.0;
}
g = new Dygraph(
document.getElementById("div_g"),
data, {
labels: ['X', 'Est.', 'Actual'],
animatedZooms: true,
underlayCallback: function (canvas, area, g) {
dc = canvas;
my_area = area;
my_graph = g;
bottom_left = g.toDomCoords(0, 0);
top_right = g.toDomCoords(highlight_end, +20);
draw_marker();
}
});
g.updateOptions({
clickCallback: change_movie_position
}, true);
}
Although I have used Javascript extensively in the past, I have never used classes and objects in my programs. This is also the first for me using the HTML5 canvas element with an extra Javascript library. The library I'm using is EaselJS.
Short and sweet, I'm trying to make a square move with keyboard input, using object-oriented programming. I've already looked over sample game files, but I've never been able to properly get one to work.
The following is my classes script:
/*global createjs*/
// Shorthand createjs.Shape Variable
var Shape = createjs.Shape;
// Main Square Class
function square(name) {
this.name = name;
this.vX = 0;
this.vY = 0;
this.canMove = false;
this.vX = this.vY = 0;
this.canMove = false;
this.body = new Shape();
this.body.graphics.beginFill("#ff0000").drawRect(0, 0, 100, 100);
}
And below is my main script:
/*global createjs, document, window, square, alert*/
// Canvas and Stage Variables
var c = document.getElementById("c");
var stage = new createjs.Stage("c");
// Shorthand Create.js Variables
var Ticker = createjs.Ticker;
// Important Keycodes
var keycode_w = 87;
var keycode_a = 65;
var keycode_s = 83;
var keycode_d = 68;
var keycode_left = 37;
var keycode_right = 39;
var keycode_up = 38;
var keycode_down = 40;
var keycode_space = 32;
// Handle Key Down
window.onkeydown = handleKeyDown;
var lfHeld = false;
var rtHeld = false;
// Create Protagonist
var protagonist = new square("Mr. Blue");
// Set Up Ticker
Ticker.setFPS(60);
Ticker.addEventListener("tick", stage);
if (!Ticker.hasEventListener("tick")) {
Ticker.addEventListener("tick", tick);
}
// Init Function, Prepare Protagonist Placement
function init() {
protagonist.x = c.width / 2;
protagonist.y = c.height / 2;
stage.addChild(protagonist);
}
// Ticker Test
function tick() {
if (lfHeld) {
alert("test");
}
}
// Handle Key Down Function
function handleKeyDown(event) {
switch(event.keyCode) {
case keycode_a:
case keycode_left: lfHeld = true; return false;
case keycode_d:
case keycode_right: rtHeld = true; return false;
}
}
This is the error I get in the Developer Tools of Chrome:
Uncaught TypeError: undefined is not a function
easeljs-0.7.0.min.js:13
In case you're wondering, the order of my script tags is the EaselJS CDN, followed by my class, followed by the main script file.
I would really like closure on this question. Thank you in advance.
I figured it out. I was adding the entire protagonist instance to the stage. I've fixed by adding the protagonist.body to the stage.
How can I make the snow clear after a certain time. I've tried using variables and the calling a timeout which switches on to false and stops the makesnow() function but that doesn't seem to clear the page at all.
<script language="javascript">
ns6 = document.getElementById;
ns = document.layers;
ie = document.all;
/*******************[AccessCSS]***********************************/
function accessCSS(layerID) { //
if(ns6){ return document.getElementById(layerID).style;} //
else if(ie){ return document.all[layerID].style; } //
else if(ns){ return document.layers[layerID]; } //
}/***********************************************************/
/**************************[move Layer]*************************************/
function move(layer,x,y) { accessCSS(layer).left=x; accessCSS(layer).top = y; }
function browserBredde() {
if (window.innerWidth) return window.innerWidth;
else if (document.body.clientWidth) return document.body.clientWidth;
else return 1024;
}
function browserHoyde() {
if (window.innerHeight) return window.innerHeight;
else if (document.body.clientHeight) return document.body.clientHeight;
else return 800;
}
function makeDiv(objName,parentDiv,w,h,content,x,y,overfl,positionType)
{
// positionType could be 'absolute' or 'relative'
if (parentDiv==null) parentDiv='body';
var oDiv = document.createElement ("DIV");
oDiv.id = objName;
if (w) oDiv.style.width = w;
if (h) oDiv.style.height= h;
if (content) oDiv.innerHTML=content;
if (positionType==null) positionType="absolute";
oDiv.style.position = positionType;
if (x) oDiv.style.left=x; else oDiv.style.left=-2000;
if (y) oDiv.style.top=y; else oDiv.style.top=-2000;
if (overfl) oDiv.style.overflow=overfl; else oDiv.style.overflow="hidden";
eval(' document.'+parentDiv+'.appendChild (oDiv); ');
delete oDiv;
}
var snowC=0;
var x = new Array();
var y = new Array();
var speed = new Array();
var t=0;
var cC = new Array();
var ra = new Array();
function makeSnow() {
x[snowC] = Math.round(Math.random()*(browserBredde()-60));
y[snowC] = 10;
makeDiv("snow"+snowC,"body",32,32,'<img src="http://i693.photobucket.com/albums/vv296/KIBBLESGRAMMY/CAT/Orange-tabby-cat-icon.gif">');
speed[snowC] = Math.round(Math.random()*8)+1;
cC[snowC]=Math.random()*10;
ra[snowC] = Math.random()*7;
snowC++;
}
function moveSnow() {
var r = Math.round(Math.random()*100);
if (r>70 && snowC<20) makeSnow();
for (t=0;t<snowC;t++) {
y[t]+=speed[t];move("snow"+t,x[t],y[t]);
if (y[t]>browserHoyde()-50) {y[t] = 10;x[t] = Math.round(Math.random()*(browserBredde()-60));}
cC[t]+=0.01;
x[t]+=Math.cos(cC[t]*ra[t]);
}
setTimeout('moveSnow()',20);
}
moveSnow();
</script>
makeSnow just adds the snowflakes. Stopping that, as you say, does not clear anything. moveSnow handles the animation, and calls itself at a timeout. If instead of setting a timeout for the next moveSnow each time, you set it up to run in an interval just once, you would have an easier time stopping it.
window.snowAnimation = window.setInterval(moveSnow, 20);
If you add a css class to your snow flakes, it would be easier to target them for deletion.
oDiv.className = 'snowflake';
Then your clear function could look something like:
function clearSnow() {
window.clearTimeout(window.snowAnimation);
var flakes = document.getElementsByTagName('snowflake');
for(var i = 0, l = flakes.length; i < l; i++) {
document.body.removeChild(flakes[i]);
}
}
Timeout doesnt help, it helps you only to stop creating new snowdivs, however if you see makeDiv is the one which creates new divs on to the body, if you clear / display:none the divs which got created on makeDiv i hope it will clear all the divs on the screen.
You need to remove the divs that were created. It might be easier if you give them all some sort of class, like ".snowflake" as you create them (in makeDiv), then start removing them from the dom.
You will have to clear the elements created after the time you wanna stop snow falling.
Following code snippet will help you to clear the elements
if(count < 500){
setTimeout('moveSnow()',20);
}else{
var i = 0;
var elem = document.getElementById('snow'+i);
do{
elem.parentNode.removeChild(elem);
elem = document.getElementById('snow'+ ++i);
}while(elem != null)
}
count++;
you have to create a global variable count.
(Yeah I'm from sweden so my english might not be perfect ;)
I have troubles with memory on the ipad. This code does not crash the broser, but it just stops. At some point it never goes in to any of the event handlers on the Image object. I have no clue why..? I have searched the forum and googled for a couple of days about workarounds. But they don't really fit what I am trying to achieve(?). (Because I only have 1 Image object).
What I have created is as follows:
1 main canvas which is visible to the user.
16 other canvases which I draw on.
1 Image Object which I load images with.
all images are pngs with alpha and have the following dimension 900x373 px. All the canvases have the same dimensions.
On the 16 other canvases there are drawn 8 images.
The purpose of this is to be able to rotate an object which has interchangable layers.
(1 angle is an object from a different angle, so it will look like it's rotating when the main loop runs.) The rotation is supposed to be controlled by touch/mouse but this should demonstrate what I want to achieve.
I know that this is a lot of code to look through and it might not be the best written code either since I'm a novice at javascript. However it does work fine on my laptop in chrome.
I've read something about events holding references to imageObjects and therefore they would not get GC'd. But does that imply here when I only have one Image Object ?
I also tried adding and removing the listeners with jquery syntax but no success.
It would be much appreciated if anyone would take the time to answer this.
Regards Oscar.
initialization of variables:
var drawingCanvas = null;
var context = null;
var numAngles = 8;
var angleStep = 32/ numAngles;
var canvasAngles = [];
var loadStatus = {};
var basePath = "assets_900/";
var layerPaths = [];
var layerPathsA = ["black/","v16/","f86/","fA00049/","fA00340/","fTG02/","fTG02/","fTJ02/"];
var layerPathsB = ["red/","v16/","f86/","fA00049/","fA00340/","fTG02/","fTG02/","fTJ02/"];
var layerPathsC = ["black/","v16/","f86/","fR134/","fA00340/","fTG02/","fTG02/","fTJ02/"];
var layerPathsD = ["red/","v16/","f86/","fR134/","fA00340/","fTG02/","fTG02/","fTJ02/"];
var layerPathsArr = [layerPathsA,layerPathsB,layerPathsC,layerPathsD];
layerPathsCounter = 0;
var numLayers = layerPaths.length;
var imageInit = null;
var SW = 900; //1920
var SH = 373; //796
var loopcounter = 0;
first setup of canvases and other stuf:
layerPaths = layerPathsArr[0];
drawingCanvas = document.getElementById('myDrawing');
context = drawingCanvas.getContext('2d');
for(var i = 0; i < numAngles; i++){
var canvas = document.createElement('canvas');
var canvasContext = canvas.getContext('2d');
canvasContext.createImageData(SW, SH);
canvas.height = SH;
canvas.width = SW;
canvasAngles.push(canvas);
}
this will init the loop, and then it will never stop, it will jsut continue until mobile safari crashes:
loadImage(0,0,0);
this is a loop that loads images:
when it has loaded 8 images it draws them on one of the 16 canvases and then that canvas gets drawn on the visible canvas. then it loads a new angle and 8 new images , and so on...
function loadImage(pathIndex,layerIndex,angleIndex){
if(layerIndex < layerPaths.length ){
//logger.log("path :" + pathIndex +" lajr : "+ layerIndex + " angl: " + angleIndex);
imageInit = new Image();
imageInit.onload = function(){
var canvas = canvasAngles[angleIndex];
var canvasContext = canvas.getContext('2d');
canvasContext.drawImage(imageInit,0, 0);
imageInit.onload = null;
imageInit.onerror = null;
imageInit.onabort = null;
imageInit.src = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";
imageInit = null;
delete imageInit;
loadImage(pathIndex,layerIndex+1,angleIndex);
}
imageInit.onerror = function(){
logger.log("Error loading, retrying....");
loadImage(pathIndex,layerIndex,angleIndex);
}
imageInit.onabort = function(){
logger.log("Error loading (aborted)");
}
var path = "";
if(pathIndex < 10){
path = basePath + layerPaths[layerIndex] + "img000"+ pathIndex + ".png";
}else{
path = basePath + layerPaths[layerIndex] + "img00"+ pathIndex + ".png";
}
imageInit.src = path;
}else{
displayAngle(angleIndex);
if(angleIndex > numAngles-2){
logger.log("turns : " + loopcounter++ +" C: " + layerPathsCounter);
clearCanvases();
loadImage(0,0,0);
layerPathsCounter++;
if(layerPathsCounter > layerPathsArr.length-1){
layerPathsCounter = 0;
}
layerPaths = layerPathsArr[layerPathsCounter];
}else{
loadImage(pathIndex+angleStep,0,angleIndex+1);
}
}
}
heres a couple of helper functions :
function clearCanvases(){
for(var i = 0; i < numAngles; i++){
var canvas = canvasAngles[i];
var canvasContext = canvas.getContext('2d');
canvasContext.clearRect(0,0,drawingCanvas.width, drawingCanvas.height);
}
}
function displayAngle(index){
context.clearRect(0,0,drawingCanvas.width, drawingCanvas.height);
var canvas = canvasAngles[index];
context.drawImage(canvas,0,0);
}
HTML :
<body >
<canvas id="myDrawing" width="900" height="373">
<p>Your browser doesn't support canvas. (HEHE)</p>
</canvas>
</body>
It seems like you can only load ~6.5 mb in one tab. And as far as I know there is no way to free up this memory (?)
this will load about 13 500kb imqages on an ipad and then stop..,
http://www.roblaplaca.com/examples/ipadImageLoading/img.html