xlib how to show a blinking cursor for an input box - xlib

I'm trying to implement an input box with xlib, but i cannot find any ifnormation on how to show the blinking cursor.
Like the following:
How can it be done?

xlib has no built-in notions of animation or blinking. You have to run a timer and draw and erase the cursor periodically.

I use something like:
This is an excerpt from my project http://open.source.sveena.com
You have to complete the missing parts.
// call this periodically
void FlipCaret()
{
if( !s_caretgc )return;
if( s_hidecaret )return;
XACCESSLOCK;
if( !s_caretgc )return;
XFillRectangle(s_caretdisplay, s_caretwindow, s_caretgc, s_caretx, s_carety, s_caretcx, s_caretcy);
XFlush(s_caretdisplay);
s_caretvisible = s_caretvisible ? 0 : 1;
}
// to create and destroy caret
static void s_DestroyCaret()
{
if( !s_caretgc )return;
XACCESSLOCK;
if( s_caretgc ){
if( s_caretvisible ){
FlipCaret();
}
XFreeGC( s_caretdisplay, s_caretgc );
XFlush( s_caretdisplay );
s_caretgc = 0;
}
}
static void s_CreateCaret( MWND* mwnd, Window w )
{
s_DestroyCaret();
XACCESSLOCK;
s_caretdisplay = mwnd->m_Display;
s_caretmwnd = mwnd;
s_caretwindow = w;
s_caretx = mwnd->Caretx;
s_carety = mwnd->Carety;
s_caretcx = mwnd->CaretCx;
s_caretcy = mwnd->CaretCy;
if( s_caretcx<5 )s_caretcx = 5;
if( s_caretcx>20 )s_caretcx = 20;
if( s_caretcy<16 )s_caretcy = 16;
if( s_caretcy>100 )s_caretcy = 100;
XGCValues gcval;
gcval.function = GXinvert;
gcval.fill_style = FillSolid;
if( IsValidXWindow( w, "XCreateGC" ) )
s_caretgc = XCreateGC(s_caretdisplay,w,GCFunction|GCFillStyle,&gcval);
XFlush( s_caretdisplay );
}

Related

Need to upload user's image input - P5 JavaScript library

I have a Sketch in Processing written in P5.js, but I don't know how to implement user's input.
The program needs to get .jpg image and it's working on it.
Every my attempt of user-input implementation ends with blank screen or endless "Loading..." screen.
Below is example with preloaded image (I need user to do it).
let img;
let size;
let pixels = [];
function preload(){
img=loadImage('image.jpg');
}
function setup() {
img.resize(windowHeight,0);
size = img.height/2;
createCanvas(img.width, img.height);
background(0);
makePixels();
drawPortrait();
}
function makePixels(){
for(let y=0; y<height; y+=size){
for(let x=0; x<width; x+=size){
let c = img.get(x,y);
tint(c);
pixels.push ( new Pixel (x,y,size,c) );
}
}
}
function drawPortrait(){
for(let p of pixels){
p.show();
}
}
function drawLastFour(){
for(let i = pixels.length-4; i<pixels.length; i++){
pixels[i].show();
}
}
function mouseMoved(){
for(let i = 0; i<pixels.length; i++){
if( (mouseX > pixels[i].x) && (mouseX <= pixels[i].x+pixels[i].s) && (mouseY > pixels[i].y) && (mouseY <= pixels[i].y+pixels[i].s) ){
for(let py = pixels[i].y; py<pixels[i].y+pixels[i].s; py+=pixels[i].s/2){
for(let px = pixels[i].x; px<pixels[i].x+pixels[i].s; px+=pixels[i].s/2){
let c = img.get(px, py);
pixels.push( new Pixel(px,py,pixels[i].s/2, c) );
}
}
pixels.splice(i,1);
break;
}
}
drawLastFour();
}
You can use the createFileInput function to create an input element of type file. Your user can then select an image file, which can be used by your sketch. Here is the (slightly modified) example code that shows how you can use it:
let inputElement;
let userImage;
function setup() {
inputElement = createFileInput(handleFile);
inputElement.position(0, 0);
}
function draw() {
background(255);
if (userImage != null) {
image(userImage, 0, 0, width, height);
}
}
function handleFile(file) {
print(file);
if (file.type === 'image') {
userImage = createImg(file.data, '');
userImage.hide();
} else {
userImage = null;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>

GtkLabel is not hidden using the property visible = false

I am trying to create a Calendar Widget in vala with GTK. I have a class whose constructor fills a Gtk.Grid with 42 labels that will be the days. But when calling the method fill_grid_days () that is responsible for iterating a List of Labels (hide or show them according to the maximum of days) When running for the first time does not hide the Labels until in an external class I use the same method fill_grid_days () by pressing a button.
CalendarView Class - Constructor
public CalendarView () {
this.orientation = Gtk.Orientation.VERTICAL;
int max_labels = 42;
var days_header = new DaysRow();
/*
* Grid that contains any number of days
* day_of_week is the start day(m,t,w,t,f,s,s) of month
* end_day is the final number day
*/
day_grid = new Grid ();
var col = 0;
var row = 0;
for (int i = 0; i < max_labels; i++) {
var label_day = new Label("");
label_day.get_style_context ().add_class ("label-day");
label_day.expand = true;
label_day.halign = Align.CENTER;
label_day.valign = Align.START;
day_grid.attach (label_day, col, row, 1, 1);
col++;
if (col != 0 && col % 7 == 0) {
row++;
col = 0;
}
labels.append(label_day);
}
this.pack_start (days_header);
this.pack_end (day_grid);
}
CalendarView Class - fill_grid_days Method
public void fill_grid_days (int start_day, int max_day, int current_day) {
/*
* All days in interation to add a new Label
*/
var day_number = 1;
for (int i = 0; i < 42; i++) {
Label label = labels.nth_data (i);
label.get_style_context ().remove_class ("label-today");
label.visible = true;
/*
* max_day + start_day, it is necessary to
* find the correct label in list
*/
if (i < start_day || i >= max_day + start_day) {
print ("\nMe pongo invisible");
label.visible = false;
} else {
/*
* current_day + start_day, it is necessary to
* find the correct label in list
*/
if ( current_day != -1 && (i+1) == current_day + start_day ) {
label.get_style_context ().add_class ("label-today");
}
//label.set_label (day_number.to_string());
label.label = day_number.to_string();
day_number++;
}
}
}
Full code
https://github.com/calo001/luna/blob/master/src/views/CalendarView.vala

Efficient algorithm to generate a kind of maze

I have done a lot of searching for this and have found lots of help to generate a maze, but I have a very specific requirement and all the loops Iv tried have failed horribly.
I created an editor where I could draw what I need, but a generator would help a great deal and this has failed.
Requirement:
Given a square grid of DIV elements (no smaller than 10x10 and no larger than 60x60) I need a joined path through and around the grid that will not touch itself at any point except at start/finish.
There must always be at least one blank square between all path squares (any number of blanks is fine so long as the path never comes into contact with itself).
There can be no dead ends and no loops (Where the path would cross itself).
This is kind of like a reverse maze - I do not need to fill the entire grid, in fact I have no problem with lots of space around the path. It might be easier to think of this along similar lines to a Monopoly board game where the path around the board wanders about instead of going around the edges. I'm actually stuck for an adequate description, hence calling it a reverse maze.
Things I tried:
Lots and lots of overly complex loops. Iv not really come very close and the issue is also one of performance.
Lots and lots of code designed to generate a maze. Some of these have been very good indeed, but they all generate a typical maze, which is not what I need at all really, and adapting the code has proven trickier than writing an insane set of loops within loops.
Any ideas would be helpful. Thanks.
Update Code
Okay, I have translated KIKO's PHP code into Javascript but somewhere along the line I have made a simple error that I cannot track down: The code works and generates a table of the correct dimensions and generates a path through it.
However, in the function "isWithinGrid" I have to subtract 1 from the width and height of the table or the entire thing will fail, and, if I do this, the code will work and created a path through the table minus one cell which will be incorrectly colored although clearly a part of the path.
Note that sometimes the path will be broken or touching itself. I have little doubt that some small problem is causing all of this, but currently this is the best I have come up with and any further help would be much appreciated.
class Grid{
constructor(width,height){
this.width = width;
this.height = height;
this.cells = [];
for(var x=0; x < this.width; x++){
var tmparray = [];
for(var y=0; y < this.height; y++){
tmparray.push(false);
}
this.cells.push(tmparray);
}
}
isWithinGrid(x,y){
return (x >= 0) && (x <= this.width-1) && (y >= 0) && (y <= this.height-1);
}
isWithinPath(x,y){
return this.isWithinGrid(x,y) && this.cells[x][y];
}
setCellInPath(x,y,boolean){
this.cells[x][y] = boolean;
return this;
}
drawHorizontalLine(x1,x2,y){
for(var x=x1; x < x2; x++){
this.setCellInPath(x,y,true);
}
return this;
}
drawVerticalLine(x,y1,y2){
for(var y=y1; y < y2; y++){
this.setCellInPath(x,y,true);
}
return this;
}
drawSquare(){
var left = Math.round(this.width/5);
var right = Math.round(4*this.width/5);
var top = Math.round(this.height/5);
var bottom = Math.round(4*this.height/5);
this.drawHorizontalLine(left,right,top)
.drawHorizontalLine(left,right,bottom)
.drawVerticalLine(left,top,bottom)
.drawVerticalLine(right,top,bottom);
return this;
}
moveCell(x,y,dx,dy){
this.setCellInPath(x,y,false);
this.setCellInPath(x+dx,y+dy,true);
}
canMoveCell(x,y,dx,dy){
return this.isWithinPath(x,y) &&
this.isWithinGrid(x+dx,y+dy) &&
!this.isWithinPath(x+dx,y+dy) &&
!this.isWithinPath(x+2*dx,y+2*dy) &&
!this.isWithinPath(x+dy+dx,y+dx+dy)
!this.isWithinPath(x-dy+dx,y-dx+dy);
}
tryToDistortOnce(x,y,dx,dy){
if (!this.canMoveCell(x,y,dx,dy)) return false;
if (!this.canMoveCell(x+dy,y+dx,dx,dy)) return false;
if (!this.canMoveCell(x-dy,y-dx,dx,dy)) return false;
this.moveCell(x,y,dx,dy);
this.setCellInPath(x+dy+dx,y+dx+dy,true);
this.setCellInPath(x-dy+dx,y-dx+dy,true);
return true;
}
distortOnce(){
var x=0, y=0, dx=0, dy=0;
do {
x = Math.floor(Math.random() * this.width) + 1;
y = Math.floor(Math.random() * this.height) + 1;
} while (!this.isWithinPath(x,y));
switch (Math.floor(Math.random() * 4) + 1){
case 1: dx = -1; dy = 0; break;
case 2: dx = +1; dy = 0; break;
case 3: dx = 0; dy = +1; break;
case 4: dx = 0; dy = -1; break;
}
if (this.tryToDistortOnce(x,y,dx,dy)){
do {
x += dx;
y += dy;
} while (this.tryToDistortOnce(x,y,dx,dy));
return true;
}
return false;
}
distortPath(numberOfDistortions = 10){
for(var counter=1; counter < numberOfDistortions; counter++){
var tries = 0;
while (!this.distortOnce() && (tries < this.width+this.height)){ tries++; }
}
return this;
}
renderGrid(){
var str = '<table class="TSTTAB">';
for(var y=0; y < this.width; y++){
for(var x=0; x < this.height; x++){
str += '<td'+(this.cells[y][x] ? ' class="path">' : '>');
}
str += '</tr>';
}
str += '</table>';
document.getElementById('cont').innerHTML =str;
return this;
}
}
var Testgrid = new Grid(20,20);
Testgrid.drawSquare().distortPath(10).renderGrid();
.TSTTAB{background-color:#7F7F7F;border-collapse:collapse;}
.TSTTAB td{ width:20px; height: 20px; border: 1px solid #000;background-color: #E5E5E5; }
.TSTTAB td.path { background-color: #44F; }
<div id='cont'></div>
Well, I've given it a try. One hour of work seems more than enough for a simple question. It is, of course, far from perfect, but it illustrates what I was talking about. It generates solutions like this:
The complete code is:
<?php
// error reporting
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// configuration
const SIZE_X = 20;
const SIZE_Y = 20;
const COMPLEXITY = 20;
// grid class
class Grid
{
public function __construct($width,$height)
{
// remember
$this->width = $width;
$this->height = $height;
// initiate grid
foreach (range(1,$width) as $x) {
foreach (range(1,$height) as $y) {
$this->cells[$x][$y] = FALSE; // false means: not in path
}
}
}
public function isWithinGrid($x,$y)
// testb whether (x,y) is within the grid
{
return ($x >= 1) && ($x <= $this->width) &&
($y >= 1) && ($y <= $this->height);
}
public function isWithinPath($x,$y)
// is a cell part of the path?
{
return $this->isWithinGrid($x,$y) && $this->cells[$x][$y];
}
public function setCellInPath($x,$y,$boolean)
// remember whether a cell is part of the path or not
{
$this->cells[$x][$y] = $boolean;
return $this;
}
public function drawHorizontalLine($x1,$x2,$y)
// simple horizontal line
{
foreach (range($x1,$x2) as $x) $this->setCellInPath($x,$y,TRUE);
return $this;
}
public function drawVerticalLine($x,$y1,$y2)
// simple vertical line
{
foreach (range($y1,$y2) as $y) $this->setCellInPath($x,$y,TRUE);
return $this;
}
public function drawSquare()
// simple square
{
$left = round($this->width/5);
$right = round(4*$this->width/5);
$top = round($this->height/5);
$bottom = round(4*$this->height/5);
$this->drawHorizontalLine($left,$right,$top)
->drawHorizontalLine($left,$right,$bottom)
->drawVerticalLine($left,$top,$bottom)
->drawVerticalLine($right,$top,$bottom);
return $this;
}
private function moveCell($x,$y,$dx,$dy)
// move a cell
{
$this->setCellInPath($x,$y,FALSE);
$this->setCellInPath($x+$dx,$y+$dy,TRUE);
}
private function canMoveCell($x,$y,$dx,$dy)
// answers the question whether or not we can move (x,y) by (dx,dy)
{
return $this->isWithinPath($x,$y) && // must be part of path
$this->isWithinGrid($x+$dx,$y+$dy) && // stay within grid
!$this->isWithinPath($x+$dx,$y+$dy) && // but not on the path
!$this->isWithinPath($x+2*$dx,$y+2*$dy) && // and don't touch path
!$this->isWithinPath($x+$dy+$dx,$y+$dx+$dy) && // and don't touch path
!$this->isWithinPath($x-$dy+$dx,$y-$dx+$dy); // and don't touch path
}
private function tryToDistortOnce($x,$y,$dx,$dy)
{
// this one should be able to move
if (!$this->canMoveCell($x,$y,$dx,$dy)) return FALSE;
// but also its neighbours must be able to move
if (!$this->canMoveCell($x+$dy,$y+$dx,$dx,$dy)) return FALSE;
if (!$this->canMoveCell($x-$dy,$y-$dx,$dx,$dy)) return FALSE;
// move the target cell by displacement
$this->moveCell($x,$y,$dx,$dy);
// move neighbours by adding two cells
$this->setCellInPath($x+$dy+$dx,$y+$dx+$dy,TRUE);
$this->setCellInPath($x-$dy+$dx,$y-$dx+$dy,TRUE);
return TRUE; // success!
}
private function distortOnce()
// distort a random cell, returns success or failure
{
// find a random cell in path
do {
$x = rand(1,$this->width);
$y = rand(1,$this->height);
} while (!$this->isWithinPath($x,$y));
// choose one of four directions to move in
switch (rand(1,4))
{
case 1: $dx = -1; $dy = 0; break;
case 2: $dx = +1; $dy = 0; break;
case 3: $dx = 0; $dy = +1; break;
case 4: $dx = 0; $dy = -1; break;
}
// try to do it
if ($this->tryToDistortOnce($x,$y,$dx,$dy))
{
// more moves
do {
$x += $dx;
$y += $dy;
} while ($this->tryToDistortOnce($x,$y,$dx,$dy));
return TRUE; // it was a success!
}
return FALSE; // we failed
}
public function distortPath($numberOfDistortions = 10)
// distort up to a certain amount of times
{
// find a random cell that is part of the path to distort
for ($counter = 1; $counter <= $numberOfDistortions; $counter++) {
// we try that a limited number of times, depending on the grid size
$tries = 0;
while (!$this->distortOnce() &&
($tries < $this->width+$this->height)) { $tries++; }
}
return $this;
}
public function renderGrid()
// render grid
{
echo '<!DOCTYPE HTML><html><head><style>'.
' td { width:20px; height: 20px; border: 1px solid #000; }'.
' .path { background-color: #44F; }'.
'</style></head><body><table>';
foreach (range(1,SIZE_Y) as $y) {
echo '<tr>';
foreach (range(1,SIZE_X) as $x) {
echo '<td'.($this->cells[$x][$y] ? ' class="path">' : '>');
}
echo '</tr>';
}
echo '</body></html></table>';
return $this;
}
}
// create grid
$grid = new Grid(SIZE_X,SIZE_Y);
// start with a square, distort and then render
$grid->drawSquare()
->distortPath(COMPLEXITY)
->renderGrid();
There are lots of things you can do to improve on this.... have fun!
On my server this code takes between 2 and 5 milliseconds to execute. Mileage may vary...

Is there any solution to Firefox 37's poor Canvas rendering performance

I've deliberately provided the version number in the question as this is the kind of question that will go out of date at some point.
Here is a simple animation that will run perfectly smoothly in Chrome and Safari, but will be very jerky in Firefox:
function lerp(a,b,λ) {
return a + λ*(b-a);
}
function random(a,b) {
return lerp( a, b, Math.random() );
}
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
$(document).ready( function()
{
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var balls = new Array(12);
for( var i=0; i<balls.length; i++ )
{
while(true)
{
var density = Math.sqrt( random(1,100) );
var r = random(5, 30);
var x = random( r+1, canvas.width-1 -(r+1) ),
y = random( r+1, canvas.height-1 -(r+1) );
var overlap = false;
for( var j=0; j<i; j++ )
{
var _x = balls[j].x - x,
_y = balls[j].y - y,
d2 = _x*_x + _y*_y,
_r = balls[j].r + r;
if( d2 < _r*_r )
overlap = true;
}
if( overlap )
continue;
balls[i] = {
color : d3.hsl( lerp(0,240,density/10), random(.3,.7), random(.3,.7) ).toString(),
x : x,
y : y,
vx : random(0, 0.2),
vy : random(0, 0.2),
r : r,
advance: function(t) {
this.x += t * this.vx;
this.y += t * this.vy;
}
};
break;
}
};
window.requestAnimationFrame(vsync);
var t_last;
function vsync(t)
{
if( t_last )
render( t - t_last );
t_last = t;
window.requestAnimationFrame(vsync);
}
function render(t_frame)
{
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
ctx.fillStyle="gray";
ctx.fillRect(0,0, canvas.width, canvas.height);
function advance_all(t) {
balls.forEach( function(b) {
b.advance(t);
});
}
var t_remaining = t_frame;
while(true) {
var hit = get_next_collision( balls, canvas.width, canvas.height );
if( t_remaining < hit.t )
break;
advance_all( hit.t );
t_remaining -= hit.t;
collide_wall( balls[hit.i], hit.wall );
balls[hit.i].advance(.001);
};
advance_all( t_remaining );
// draw balls
balls.forEach( function(ball) {
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI*2, true);
ctx.closePath();
ctx.fillStyle = ball.color;
ctx.fill();
});
}
});
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
function get_next_collision(balls,W,H)
{
var winner;
// ball-wall
balls.forEach( function(ball,i)
{
var t = [];
t['L'] = (ball.r - ball.x) / ball.vx; // s.x + t v.x = r
t['T'] = (ball.r - ball.y) / ball.vy;
t['R'] = (W-1-ball.r - ball.x) / ball.vx; // s.x + t v.x = (W-1)-r
t['B'] = (H-1-ball.r - ball.y) / ball.vy;
// get index of smallest positive t
var LR = t['L'] >= 0 ? 'L' : 'R',
TB = t['T'] >= 0 ? 'T' : 'B',
wall = t[LR] < t[TB] ? LR : TB;
if( ! winner || ( t[wall] <= winner.t ) )
winner = {
t : t[wall],
i : i,
wall: wall
};
});
return winner;
}
function collide_wall( A, wall )
{
if( wall == 'L' || wall == 'R' )
A.vx *= -1;
else
A.vy *= -1;
}
html, body {
width: 100%;
height: 100%;
margin: 0px;
}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/mathjs/1.5.1/math.min.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<canvas id="myCanvas">
<!-- Insert fallback content here -->
</canvas>
Why is Firefox performing significantly worse than its competitors?
If I take the number of balls to 500 Chrome is still smooth, Firefox is seriously choppy.
If I take the number of balls down to 1 Firefox is still burring it.
Another experiment I did was applying a fixed velocity increment each frame, so that the smoothness of the animation accurately reflects the evenness of the render callback. This showed Firefox to be all over the place. Chrome on the other hand was smooth.
If there is sufficient interest, I can provide a snippet for that also and maybe tidy up the first one so that it offers a slider to modify the ball count.
As far as I can see, (1) Firefox definitely isn't giving us a genuine VSYNC callback, I suspect it is just using a timer, (2) even correcting for that by manually calculating elapsed time for each frame, it burrs the animation, maybe suggesting that it sometimes the callback fires in time to catch the VSYNC and sometimes it misses the boat, (3) there is an additional compositing hit that is disproportionate compared with Chrome.
Is there anything to be done about this?
EDIT: I found this question from four years ago! Poor performance of html5 canvas under firefox -- please don't mark this question as the duplicate unless it is certain that the answer to that question is still the only relevant answer four years later. I've deliberately included the version number in the question, as the question pertains specifically to the current version.

Attempt at Circular Buffer - Javascript

Right! Here is my attempt at a circular buffer (For use in a graphing program, using the canvas element). Have yet to get round to testing it out.
Question is - Can anyone see any flaws in my logic? Or bottlenecks?
/**
* A circular buffer class.
* #To add value -> bufferObject.addValue(xValue, yValue);
* #To get the First-in value use -> bufferObject.getValue(0);
* #To get the Last-in value use -> bufferObject.getValue(bufferObject.length);
**/
var circularBuffer = function (bufferSize) {
this.bufferSize = bufferSize;
this.buffer = new Array(this.bufferSize); // After testing on jPerf -> 2 x 1D array seems fastest solution.
this.end = 0;
this.start = 0;
// Adds values to array in circular.
this.addValue = function(xValue, yValue) {
this.buffer[this.end] = {x : xValue, y: yValue};
if (this.end != this.bufferSize) this.end++;
else this.end = 0;
if(this.end == this.start) this.start ++;
};
// Returns a value from the buffer
this.getValue = function(index) {
var i = index+this.start;
if(i >= this.bufferSize) i -= this.bufferSize; //Check here.
return this.buffer[i]
};
// Returns the length of the buffer
this.getLength = function() {
if(this.start > this.end || this.start == this.bufferSize) {
return this.xBuffer.length;
} else {
return this.end - this.start;
}
};
// Returns true if the buffer has been initialized.
this.isInitialized = function() {
if(this.end != this.start) return true;
else return false;
};
}
Please feel free to reuse this code.
Updated twice (and tested!).
Update: Found another implementation Circular buffer in JavaScript
Made class variables private, corrected old xBuffer reference. Will do more edits tonight.
/**
* A circular buffer class.
* #To add value -> bufferObject.addValue(xValue, yValue);
* #To get the First-in value use -> bufferObject.getValue(0);
* #To get the Last-in value use -> bufferObject.getValue(bufferObject.length);
**/
var circularBuffer = function (buffer_size) {
var bufferSize = buffer_size;
var buffer = new Array(bufferSize); // After testing on jPerf -> 2 x 1D array seems fastest solution.
var end = 0;
var start = 0;
// Adds values to array in circular.
this.addValue = function(xValue, yValue) {
buffer[end] = {x : xValue, y: yValue};
if (end != bufferSize) end++;
else end = 0;
if(end == start) start++;
};
// Returns a value from the buffer
this.getValue = function(index) {
var i = index+start;
if(i >= bufferSize) i -= bufferSize; //Check here.
return buffer[i];
};
// Returns the length of the buffer
this.getLength = function() {
if(start > end || start == bufferSize) {
return buffer.length;
} else {
return end - start;
}
};
// Returns true if the buffer has been initialized.
this.isInitialized = function() {
return (end != start) ? true : false;
};
}
I implemented Vogomatix's code above, and got a few bugs. The code writes off the end of the buffer, expanding the buffer size automatically, and the addValue function is bound to a particular type. I've adjusted the code to work with any object type, added some private subroutines to simplify, and added a function to dump the contents out to a string, with an optional delimiter. Also used a namespace.
What's missing is a removeValue() but it would be just a check of count to be greater than zero, then a call to _pop().
This was done because I needed a rolling, scrolling text buffer for inbound messages, that did not grow indefinitely. I use the object with a textarea, so I get behaviour like a console window, a scrolling text box that does not chew up memory indefinitely.
This has been tested with expediency in mind, in that I am coding quickly, posted here in the hope that fellow OverFlow-ers use and anneal the code.
///////////////////////////////////////////////////////////////////////////////
// STYLE DECLARATION
// Use double quotes in JavaScript
///////////////////////////////////////////////////////////////////////////////
// Global Namespace for this application
//
var nz = nz || {};
nz.cbuffer = new Object();
///////////////////////////////////////////////////////////////////////////////
// CIRCULAR BUFFER
//
// CREDIT:
// Based on...
// Vogomatix http://stackoverflow.com/questions/20119513/attempt-at-circular-buffer-javascript
// But re-written after finding some undocumented features...
/**
* A circular buffer class, storing any type of Javascript object.
* To add value -> bufferObject.addValue(obj);
* To get the First-in value use -> bufferObject.getValue(0);
* To get the Last-in value use -> bufferObject.getValue(bufferObject.length);
* To dump to string use -> bufferObject.streamToString(sOptionalDelimiter); // Defaults to "\r\n"
**/
nz.cbuffer.circularBuffer = function (buffer_size) {
var bufferSize = buffer_size > 0 ? buffer_size : 1; // At worst, make an array of size 1
var buffer = new Array(bufferSize);
var end = 0; // Index of last element.
var start = 0; // Index of first element.
var count = 0; // Count of elements
// 'Private' function to push object onto buffer.
this._push = function (obj) {
buffer[end] = obj; // Write
end++; // Advance
if (end == bufferSize) {
end = 0; // Wrap if illegal
}
count++;
}
// 'Private' function to pop object from buffer.
this._pop = function () {
var obj = buffer[start];
start++;
if (start == bufferSize) {
start = 0; // Wrap
}
count--;
return obj;
}
// Adds values to buffer.
this.addValue = function (obj) {
if (count < bufferSize) {
// Just push
this._push(obj);
}
else {
// Pop, then push
this._pop();
this._push(obj);
}
}
// Returns a value from the buffer. Index is relative to current notional start.
this.getValue = function (index) {
if (index >= count || index < 0) return; // Catch attempt to access illegal index
var i = index + start;
if (i >= bufferSize) {
i -= bufferSize;
}
return buffer[i];
}
// Returns the length of the buffer.
this.getLength = function () {
return count;
}
// Returns all items as strings, separated by optional delimiter.
this.streamToString = function (delim) {
delim = (typeof delim === "undefined") ? "\r\n" : delim; // Default syntax; Default to CRLF
var strReturn = "";
var once = 0;
var index = 0;
var read = index + start;
for (; index < count; ++index) {
if (once == 1) strReturn += delim.toString();
strReturn += buffer[read].toString();
read++;
if (read >= bufferSize) read = 0;
once = 1;
}
return strReturn;
}
}

Resources