How to assign indexes to variable names? For instance, project0, project1, project2, etc?
for (var i=0; i<data.length; i++)
{
var project+i = new GanttProjectInfo(1, "Applet redesign", new Date(2010, 5, 11));
var parentTask+i = new GanttTaskInfo(1, "Old code review", new Date(2010, 5, 11), 208, 50, "");
project1.addTask(parentTask+i);
// Load data structure
ganttChartControl.addProject(project+i);
// Build control on the page
}
Just as #JaredFarrish suggested, you can simply use an array to store all the projects. Create them and add them to the array before the variable gets overwritten:
var projects = [];
for (var i = 0; i < data.length; i++) {
var project = new GanttProjectInfo(1, "Applet redesign", new Date(2010, 5, 11));
var parentTask = new GanttTaskInfo(1, "Old code review", new Date(2010, 5, 11), 208, 50, "");
project.addTask(parentTask);
ganttChartControl.addProject(project);
// Push this project to the array to save it
projects.push(project);
}
// Need to access the first project?
projects[0].foo();
using eval()
eval(("varname" + i) + " = " + 5 + i);
but using eval is not really recommended there is always a way around for what you are trying to do.
Related
I need to combine 2 parts of 2 existing arrayBuffers into a new one.
I am building a parser and the data comes in arraybuffers of random sizes, the data will spill over the end of one, into the beginning of the other. So I need to create a new output buffer and copy in a portion of the end of one buffer and a portion of the beginning of the other. The output will just be an Arraybuffer.
Starting out with this demo, I was going to make Uint8Arrays with some offsets then use set, the problem is certain combinations throw Invalid typed array length. I will not know the length of each array or offsets beforehand.
var buffer1 = new ArrayBuffer(8);
var buffer2 = new ArrayBuffer(8);
var buffer3 = new ArrayBuffer(8);
var uint8_1 = new Uint8Array(buffer1);
var uint8_2 = new Uint8Array(buffer2);
var uint8_3 = new Uint8Array(buffer3);
uint8_1.fill(1);
uint8_2.fill(2);
var uint8_1_slice = new Uint8Array(buffer1 , 0 , 3);
var uint8_2_slice = new Uint8Array(buffer2 , 4, 7);
For this demo need to get buffer3 to be 1,1,1,1,2,2,2,2.
Cannot Use Slice
I have seen some people only use array.length. It's fine as long as the array is only 1 byte per element. It's also fine if the other typed arrays are filled up but in this example a2 isn't. That is why it's better to use byteLength this is also how Blob constructor concatenate the parts.
// Concatenate a mix of typed arrays
function concatenate(...arrays) {
// Calculate byteSize from all arrays
let size = arrays.reduce((a,b) => a + b.byteLength, 0)
// Allcolate a new buffer
let result = new Uint8Array(size)
// Build the new array
let offset = 0
for (let arr of arrays) {
result.set(arr, offset)
offset += arr.byteLength
}
return result
}
// the total length of 1-3 = 5
// the total byteLength of 1-3 = 6
let a1 = Uint8Array.of(1, 2) // [1, 2]
let a2 = Uint16Array.of(3) // [3] just for the fun of it 16 takes up 2 bytes
let a3 = Uint8Array.of(4, 5) // [4, 5]
concatenate(a1, a2, a3) // [1, 2, 3, 0, 4, 5]
/********/
var blob = new Blob([a1, a2, a3])
var res = new Response(blob)
res.arrayBuffer().then(buffer => console.log(new Uint8Array(buffer)))
// [1, 2, 3, 0, 4, 5]
For this demo need to get buffer3 to be 1,1,1,1,2,2,2,2.
You can use for loop, set uint8_3 to uint8_1 value if variable n is less than uint8_1.byteLength / 2 else set uint8_3 to value at uint8_2 .
var len = 8;
var buffer1 = new ArrayBuffer(len);
var buffer2 = new ArrayBuffer(len);
var buffer3 = new ArrayBuffer(len);
var uint8_1 = new Uint8Array(buffer1);
var uint8_2 = new Uint8Array(buffer2);
var uint8_3 = new Uint8Array(buffer3);
uint8_1.fill(1);
uint8_2.fill(2);
// `len` : uint8_1.byteLength / 2 + uint8_2.byteLength / 2
for (var n = 0; n < len; n++) {
uint8_3[n] = n < len / 2 ? uint8_1[n] : uint8_2[n];
}
console.log(uint8_3);
So I've got this code for creating a dialog box in photoshop which contains 4 panels. It worked fine when I wasn't running it through a loop, but the code was bulky and ugly. now I get an error saying "panel1 is undefined". Can I not put objects in arrays like this?
// create a dialog window, dig.panel = dialog panel
var dig = new Window('dialog', 'Poster Interface - Choose 4 Images', [550, 120, 1150, 800]);
//define variables for panel dimensions
var digX = 100;
var digY = 50;
var digWidth = 510;
var digHeight = 140;
var digUp = 110;
var panels = [
[panel1, panel2, panel3, panel4]
];
var labels = [
[label1, label2, label3, label4]
];
var texts = [
[t1, t2, t3, t4]
];
var buttons = [
[bt1, bt2, bt3, bt4]
];
//create panels for the image components
//first loop for panel dimensions multiply by x
// nested loop for contents using i
for (x = 0; x < 4; x++) {
dig.panels[x] = dig.add('panel', [digX, digY + (digUp * x), digWidth, digHeight + (digUp * x)], 'Image ' + (x + 1) + ':');
for (i = 0; i < 4; i++) {
dig.panels[i].labels[i] = dig.panels[i].add('statictext', [20, 20, 120, 40], 'Choose Image' + (i + 1) + ':');
dig.panels[i].texts[i] = dig.panels[i].add('edittext', [125, 20, 325, 40], 'image' + (i + 1) + '.jpg');
dig.panels[i].buttons[i] = dig.panels[i].add('button', [330, 20, 380, 40], 'Open');
}
}
This is wrecking my head. Any advice would be appreciated
To create an array of variables in javascript:
var var1 = "value";
var var2 = "value";
var array = [var1,var2];
You are creating an array, with an array inside it, with variables inside the inner array.
var panels = [
[panel1, panel2, panel3, panel4]
];
You have not displayed to us that those variables have been defined.
Here is a fiddle:
https://jsfiddle.net/chrislewispac/rfhq01L3/
with the following code:
var var1 = "value";
var var2 = "value";
var array = [var1,var2];
var array2 = [[var1,var2]];
console.log(array);
console.log(array2);
Go there and look at the console. You will notice the length of array2 is only 1 while the length of array is 2. So, you need to define your variables, then build the array in the format you want it (do you really want an array of arrays?) Then you can loop and add properties.
Also, an object means something in javascript. In javascript it is typical to see an object created using object literal syntax.
Object = {
property1 : "property",
property2: "property"
}
So when you asked if you could have an array of object, yes you can. However you have to create those objects and their properties first.
I am working on a jquery form file that uses an array to populate a dropdown of sizes based on the selection of the material. This works fine but now we are adding an additional dropdown and we need to have different values in the array based on that selection.
this is the part of the current working code:
var Material = new Array();
Material['UNC'] = new Array('40', '32');
Material['UNF'] = new Array('10', '24');
This is basically what I am trying to, not sure how:
if($("#style").val() == "long") { var Material = new Array();
Material['UNC'] = new Array('45', '35');
Material['UNF'] = new Array('15', '29');} else {
var Material = new Array();
Material['UNC'] = new Array('40', '32');
Material['UNF'] = new Array('10', '24');}
I'm not having any luck, I'm not super familiar with Javascript functions. Thanks
One way:
var isLong = $('#style').val() === 'long';
var material = {};
material.UNC = (isLong) ? [45, 35] : [40, 32];
material.UNF = (isLong) ? [15, 29] : [10, 24];
Another way:
var isLong = $('#style').val() === 'long';
var material = {};
if (isLong) {
material.UNC = [45, 35];
material.UNF = [15, 29];
}
else {
material.UNC = [40, 32];
material.UNF = [10, 24];
}
As Felix Kling points out, it is better to use an object over an array for material. I've also used JavaScript convention of a lowercase variable name. Instead of using new Array use [] and instead of new Object, you can use {}.
You just need to move the declaration of the Material variable outside the blocks:
var Material = new Array();
if($("#style").val() == "long") {
Material['UNC'] = new Array('45', '35');
Material['UNF'] = new Array('15', '29');
} else {
Material['UNC'] = new Array('40', '32');
Material['UNF'] = new Array('10', '24');
}
However, as others have pointed out, you should be using an object rather than an array for these kinds of non-numeric indexes. You should also use object and array notation:
var Material = {};
if($("#style").val() == "long") {
Material['UNC'] = ['45', '35'];
Material['UNF'] = ['15', '29'];
} else {
Material['UNC'] = ['40', '32'];
Material['UNF'] = ['10', '24'];
}
I'm working with ArrayBuffer objects, and I would like to duplicate them. While this is rather easy with actual pointers and memcpy, I couldn't find any straightforward way to do it in Javascript.
Right now, this is how I copy my ArrayBuffers:
function copy(buffer)
{
var bytes = new Uint8Array(buffer);
var output = new ArrayBuffer(buffer.byteLength);
var outputBytes = new Uint8Array(output);
for (var i = 0; i < bytes.length; i++)
outputBytes[i] = bytes[i];
return output;
}
Is there a prettier way?
I prefer the following method
function copy(src) {
var dst = new ArrayBuffer(src.byteLength);
new Uint8Array(dst).set(new Uint8Array(src));
return dst;
}
It appears that simply passing in the source dataview performs a copy:
var a = new Uint8Array([2,3,4,5]);
var b = new Uint8Array(a);
a[0] = 6;
console.log(a); // [6, 3, 4, 5]
console.log(b); // [2, 3, 4, 5]
Tested in FF 33 and Chrome 36.
ArrayBuffer is supposed to support slice (http://www.khronos.org/registry/typedarray/specs/latest/) so you can try,
buffer.slice(0);
which works in Chrome 18 but not Firefox 10 or 11. As for Firefox, you need to copy it manually. You can monkey patch the slice() in Firefox because the Chrome slice() will outperform a manual copy. This would look something like,
if (!ArrayBuffer.prototype.slice)
ArrayBuffer.prototype.slice = function (start, end) {
var that = new Uint8Array(this);
if (end == undefined) end = that.length;
var result = new ArrayBuffer(end - start);
var resultArray = new Uint8Array(result);
for (var i = 0; i < resultArray.length; i++)
resultArray[i] = that[i + start];
return result;
}
Then you can call,
buffer.slice(0);
to copy the array in both Chrome and Firefox.
Hmmm... if it's the Uint8Array you want to slice (which logically, it should be), this may work.
if (!Uint8Array.prototype.slice && 'subarray' in Uint8Array.prototype)
Uint8Array.prototype.slice = Uint8Array.prototype.subarray;
Faster and slightly more complicated version of chuckj's answer. Should use ~8x less copy operations on large Typed Arrays. Basically we copy as much 8-byte chunks as possible and then copy the remaining 0-7 bytes. This is especially useful in current version of IE, since it doesn't have slice method implemented for ArrayBuffer.
if (!ArrayBuffer.prototype.slice)
ArrayBuffer.prototype.slice = function (start, end) {
if (end == undefined) end = that.length;
var length = end - start;
var lengthDouble = Math.floor(length / Float64Array.BYTES_PER_ELEMENT);
// ArrayBuffer that will be returned
var result = new ArrayBuffer(length);
var that = new Float64Array(this, start, lengthDouble)
var resultArray = new Float64Array(result, 0, lengthDouble);
for (var i = 0; i < resultArray.length; i++)
resultArray[i] = that[i];
// copying over the remaining bytes
that = new Uint8Array(this, start + lengthDouble * Float64Array.BYTES_PER_ELEMENT)
resultArray = new Uint8Array(result, lengthDouble * Float64Array.BYTES_PER_ELEMENT);
for (var i = 0; i < resultArray.length; i++)
resultArray[i] = that[i];
return result;
}
Wrap a Buffer around the ArrayBuffer. This is shared memory and no copy is made. Then create a new Buffer from the wrapping Buffer. This will copy the data. Finally get a reference to the new Buffer's ArrayBuffer.
This is the most straighforward way I can find. The most efficient? Perhaps.
const wrappingBuffer = Buffer.from(arrayBuffer)
const copiedBuffer = Buffer.from(wrappingBuffer)
const copiedArrayBuffer = copiedBuffer.buffer
In some cases (like webaudio Audiobuffers) you only have a reference to the 2 arrays.
So if you have array1 as a float32Array and array2 as a float32Array,
you must do an element by element copy.
To do so you can use different methods.
var ib=z.inputBuffer.getChannelData(0);
var ob=z.outputBuffer.getChannelData(0);
this
ib.forEach((chd,i)=>ob[i]=chd);
or this nicer and probably faster
ob.set(ib);
That's because Array.set populates an existing array with multiple data (even from another array)
Some of the operations above only do "shallow" copies. When working with workers and transferable arrays, you need to do a deep copy.
function copyTypedArray(original, deep){
var copy;
var kon = original.constructor;
if(deep){
var len = original.length;
copy = new kon(len);
for (var k=len; --k;) {
copy[k] = original[k];
}
} else {
var sBuf = original.buffer;
copy = new kon(sBuf);
copy.set(original);
}
return copy;
}
HINT (for the confused): Typed Arrays contain an ArrayBuffer, which can be obtained via the "buffer" property.
var arr = new Float32Array(8);
arr.buffer <-- this is an ArrayBuffer
If you're in the browser you can do:
const copy = structuredClone(buffer);
Hey everyone, so I am working on creating a small class to help me work with the Google visualization API. You can see how it works here...
http://code.google.com/apis/visualization/documentation/gallery/annotatedtimeline.html
Here is google's implementation.
google.load('visualization', '1', {'packages':['annotatedtimeline']});
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', 'Sold Pencils');
data.addColumn('string', 'title1');
data.addColumn('string', 'text1');
data.addColumn('number', 'Sold Pens');
data.addColumn('string', 'title2');
data.addColumn('string', 'text2');
data.addRows([
[new Date(2008, 1 ,1), 30000, undefined, undefined, 40645, undefined, undefined],
[new Date(2008, 1 ,2), 14045, undefined, undefined, 20374, undefined, undefined],
[new Date(2008, 1 ,3), 55022, undefined, undefined, 50766, undefined, undefined],
[new Date(2008, 1 ,4), 75284, undefined, undefined, 14334, 'Out of Stock','Ran out of stock on pens at 4pm'],
[new Date(2008, 1 ,5), 41476, 'Bought Pens','Bought 200k pens', 66467, undefined, undefined],
[new Date(2008, 1 ,6), 33322, undefined, undefined, 39463, undefined, undefined]
]);
var chart = new google.visualization.AnnotatedTimeLine(document.getElementById('chart_div'));
chart.draw(data, {displayAnnotations: true});
Here is the class I made that I am having issues with.
The class makes adding data to the graph a little easier and better for what I am trying to do. Basically, instead of making columns with a bunch of undefined values, the class does it for you, and you don't have to keep track of the location/value of each column.
function GraphManager(dataTable)
{
this.graphData = new Array();
this.dataTable = dataTable;
this.titleFinder = new Object(); // used to keep track of the indices
this.dataTable.addColumn('date', 'Date');
this.addSet = function(title)
{
var setCount = (this.dataTable.getNumberOfColumns() -1) / 3; //used for the column name
var place = this.dataTable.getNumberOfColumns();
this.titleFinder[title] = place; //the title of the column and its location
this.dataTable.addColumn('number', title);
this.dataTable.addColumn('string', 'title' + setCount);
this.dataTable.addColumn('string', 'text' + setCount);
}
this.addPoint = function(title, date, number)
{
//this function finds the location of the category
//and inserts a column with data at the location
var place = titleFinder[title]; //get the location
var column = new Array(dataTable.getNumberOfColumns());
column[0] = date;
column[place] = number;
for (var i = 0;i<place; i++)
{
column[i] = undefined;
}
for (var i = place + 1; i<dataTable.getNumberOfColumns(); i++)
{
column[i] = undefined;
}
var next = this.graphData.length;
this.graphData[next] = column;
data.addRows(graphData);
}
}
And then this code can be used to do the same thing with a fewer amount of code.
function printGraph()
{
var data = new google.visualization.DataTable();
var gm = new GraphManager(data);
var title = "testcategory";
gm.addSet(title);
gm.addPoint(title, new Date[2010, 5, 10], 100);
gm.addPoint(title, new Date[2010, 6, 10], 200);
var chart = new google.visualization.AnnotatedTimeLine(document.getElementById('chart_div'));
chart.draw(gm.dataTable, {displayAnnotations: true});
}
With this HTML body
<input type="button" onclick="printGraph()" value="Draw Graph">
<div id='chart_div' style='width: 800px; height: 350px;'></div>
The issue: I am getting an "Object expected" error on the line gm.addSet(title). Basically, I am not able to use the class GraphManager. What am I doing wrong here?
Isn't supposed to be "dataTable" instead of "tableData"?
for (var i = place + 1; i<tableData.count; i++)
{
column[i] = undefined;
}
I don't know, as per:
http://code.google.com/apis/visualization/documentation/reference.html#DataTable
count is not an attribute, but I see you referring to it many places in your code:
var column = new Array(dataTable.count)
There is dataTable.getNumberOfColumns() however
Ok, I figured out the problem. Basically I had left out a bunch of "this" statements, and when I created a new date I used a bracket instead of a parentheses. I also realized that when I added a new set of data, I needed to go through the old data to add the empty columns. Here is the finished code if anyone is interested... It's pretty useful if you are adding data at different dates or if you don't know how many data sets you will have.
function GraphManager(adataTable)
{
this.graphData = new Array();
this.dataTable = adataTable;
this.titleFinder = new Object(); // used to keep track of the indices
this.dataTable.addColumn('date', 'Date');
this.addSet = function(title)
{
var setCount = (this.dataTable.getNumberOfColumns() -1) / 3; //used for the column name
var pointsCount = this.graphData.length;
var place = this.dataTable.getNumberOfColumns();
this.titleFinder[title] = place; //the title of the column and its location
this.dataTable.addColumn('number', title);
this.dataTable.addColumn('string', 'title' + setCount);
this.dataTable.addColumn('string', 'text' + setCount);
var newCount = this.dataTable.getNumberOfColumns();
for (var i = 0; i<pointsCount; i++)
{
for (var j=place; j<newCount; j++)
{
this.graphData[i][j] = undefined;
}
}
}
this.addPoint = function(title, date, number)
{
//this function finds the location of the category
//and inserts a column with data at the location
var place = this.titleFinder[title]; //get the location
var column = new Array(this.dataTable.getNumberOfColumns());
column[0] = date;
column[place] = number;
for (var i = 1;i<place; i++)
{
column[i] = undefined;
}
for (var i = place + 1; i<this.dataTable.getNumberOfColumns(); i++)
{
column[i] = undefined;
}
var next = this.graphData.length;
this.graphData[next] = column;
this.dataTable.addRows(this.graphData);
}
}
And its as easy to use as this:
var data = new google.visualization.DataTable();
var gm = new GraphManager(data);
var title = "testcategory";
var title2 = "cat";
gm.addSet(title);
gm.addPoint(title, new Date(2010, 5, 10), 100);
gm.addPoint(title, new Date(2010, 6, 10), 200);
gm.addPoint(title, new Date(2010, 2, 10), 300);
gm.addSet(title2);
gm.addPoint(title2, new Date(2010, 6, 10), 100);
gm.addPoint(title2, new Date(2010, 2, 10), 500);
var chart = newgoogle.visualization.AnnotatedTimeLine(document.getElementById('chart_div'));
chart.draw(gm.dataTable, {displayAnnotations: true});