Considering I'm trying to make an algorithm that finds the least expansive path.
Every computation of the current path is async.
My algorithm just kills the stack. Any other alternative?
The code for what I've been coding is:
function DFS(unvisitedNodes, currentVertex, currentRouteFromStart, depth, minimalPath, finalVertex, maxDepth, doneCallback) {
// Add the final destination to the top of the list.
var copiedUnvisitedVertices = unvisitedNodes.slice(0);
copiedUnvisitedVertices.splice(0, 0, finalVertex);
var i = 0;
var singleIteration = function (i) {
if (i == copiedUnvisitedVertices.length) {
doneCallback(minimalPath);
return;
}
if (i > 0) {
// Putting the check here makes sure we compute the edge
// for the last depth for the destination vertex only.
if (depth == maxDepth) {
currentRouteFromStart.pop();
doneCallback(minimalPath);
return;
}
}
var dest = copiedUnvisitedVertices[i];
computeEdge(currentVertex, dest, function (edgeInfo) {
currentRouteFromStart.push(edgeInfo);
var currentCost = edgeCost(currentRouteFromStart);
var afterBFSDone = function (_minimalPath) {
currentRouteFromStart.pop();
singleIteration(i + 1);
return;
}
if (dest == finalVertex) {
var minPrice = edgeCost(minimalPath);
if (currentCost < minPrice) {
minimalPath = currentRouteFromStart.slice(0);
}
}
else {
DFS(unvisitedNodes.slice(0).splice(i - 1), dest, currentRouteFromStart, depth + 1, minimalPath, finalVertex, maxDepth, afterBFSDone);
}
afterBFSDone(minimalPath);
});
};
singleIteration(0);
}
Related
I'm trying to implement A* algorithm in react.js but I'm quite stuck when it comes to implement the fScore function. I know that f=g+h where g is the gScore from the start node till the current node and h is the heuristic distance from the currentNode till the end node. I calculated the heuristic using the euclidean distance where I'm sending the coordinates of the current and End nodes but I don't know how to calculate the gScore.
Each node in my graph has:
id,
name,
x,
y,
connectedToIds:[] //list of neihbours or connectedNodes. Update: I added the variables parentId, fscore, gscore, hscore to each node. So now each node has the variables : id,
name,
x,
y,
connectedToIds:[],
fscore: 0,
gscore: 0,
hscore: 0,
parentId: null.
Update2: originLocationId is the id of the start node. destinationLocationId is the id of the end node. locations is a list of all nodes.
my code:
export default class TurnByTurnComponent extends React.PureComponent {
constructor(props) {
super(props);
}
render() {
const {
destinationLocationId,
locations,
originLocationId
} = this.props;
console.log(locations)
console.log(originLocationId)
console.log(destinationLocationId)
var openedList = [];
var closedList = [];
if (destinationLocationId != null && originLocationId != null) {
openedList.push(originLocationId);
while (openedList.length != 0) {
var currentLoc = openedList[0]; //minFvalue
const currIndex = openedList.indexOf(currentLoc);
openedList.splice(currIndex, 1); //deleting currentNode from openedList
closedList.push(currentLoc) //adding currentNode to closedList
if (currentLoc == destinationLocationId) {
//return path
}
}
}
function heuristic(currentNode, endNode) { //euclidean distance
var x = Math.pow(endNode.x - currentNode.x, 2);
var y = Math.pow(endNode.y - currentNode.y, 2);
var dist = Math.sqrt(x + y);
return dist;
}
function gScore(startNode, currentNode) {
}
return (
<div className="turn-by-turn-component">
{locations.map(loc => (
<li key={loc.id}>
{loc.name}
</li>
))}
<TodoList
title="Mandatory work"
list={[
]}
/>
<TodoList
title="Optional work"
list={[
]}
/>
</div>
);
}
}
TurnByTurnComponent.propTypes = {
destinationLocationId: PropTypes.number,
locations: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired,
connectedToIds: PropTypes.arrayOf(PropTypes.number.isRequired).isRequired
})),
originLocationId: PropTypes.number
};
Update3: New version of my code
export default class TurnByTurnComponent extends React.PureComponent {
constructor(props) {
super(props);
this.state = { shortestPath: [] }
}
render() {
const {
destinationLocationId,
locations,
originLocationId
} = this.props;
if (destinationLocationId != null && originLocationId != null) {
if (originLocationId == destinationLocationId) { //check if the startNode node is the end node
return originLocationId;
}
var openList = [];
let startNode = getNodeById(originLocationId);
let endNode = getNodeById(destinationLocationId)
startNode.gcost = 0
startNode.heuristic = manhattanDistance(startNode, endNode)
startNode.fcost = startNode.gcost + startNode.heuristic;
//start A*
openList.push(startNode); //starting with the startNode
while (openList.length) {
console.log("inside while")
var currentNode = getNodeOfMinFscore(openList);
if (currentIsEqualDistanation(currentNode)) {
var path = getPath(currentNode)
this.setState({
shortestPath: path,
});
return path //todo
}
deleteCurrentFromOpenList(currentNode, openList);
for (let neighbourId of currentNode.connectedToIds) {
var neighbourNode = getNodeById(neighbourId);
var currentNodeGcost = currentNode.gcost + manhattanDistance(currentNode, neighbourNode);
console.log(currentNodeGcost)
console.log(neighbourNode.gcost)
if (currentNodeGcost < neighbourNode.gcost) {
console.log("Helloooo")
neighbourNode.parentId = currentNode.id;
// keep track of the path
// total cost saved in neighbour.g
neighbourNode.gcost = currentNodeGcost;
neighbourNode.heuristic = manhattanDistance(neighbourNode, endNode);
neighbourNode.fcost = neighbourNode.gcost + neighbourNode.heuristic;
if (!openList.includes(neighbourId)) {
openList.push(neighbourNode);
}
}
}
}
return null;
}
function deleteCurrentFromOpenList(currentNode, openList) {
const currIndex = openList.indexOf(currentNode);
openList.splice(currIndex, 1); //deleting currentNode from openList
}
function currentIsEqualDistanation(currentNode) {
//check if we reached out the distanation node
return (currentNode.id == destinationLocationId)
}
function getNodeById(id) {
var node;
for (let i = 0; i < locations.length; i++) {
if (locations[i].id == id) {
node = locations[i]
}
}
return node
}
function getPath(endNode) {
var path = []
while (endNode.parentId) {
path.push(endNode.name)
endNode = endNode.parentId;
}
return path;
}
function getNodeOfMinFscore(openList) {
var minFscore = openList[0].fcost; //initValue
var nodeOfminFscore;
for (let i = 0; i < openList.length; i++) {
if (openList[i].fcost <= minFscore) {
minFscore = openList[i].fcost //minFvalue
nodeOfminFscore = openList[i]
}
}
return nodeOfminFscore
}
//manhattan distance is for heuristic and gScore. Here I use Manhattan instead of Euclidean
//because in this example we dont have diagnosal path.
function manhattanDistance(startNode, endNode) {
var x = Math.abs(endNode.x - startNode.x);
var y = Math.abs(endNode.y - startNode.y);
var dist = x + y;
return dist;
}
return (
<div className="turn-by-turn-component">
{locations.map(loc => (
<li key={loc.id}>
{JSON.stringify(loc.name)},
</li>
))}
<TodoList
title="Mandatory work"
list={
this.state.shortestPath
}
/>
<TodoList
title="Optional work"
list={[
]}
/>
</div>
);
}
}
TurnByTurnComponent.propTypes = {
destinationLocationId: PropTypes.number,
locations: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired,
connectedToIds: PropTypes.arrayOf(PropTypes.number.isRequired).isRequired
})),
originLocationId: PropTypes.number
};
While h is the heuristic, a plausible guess of the possible cost it will be needed to reach the end node, g is the actual cost spent to reach the current node. In your case it could be even the same euclidian distance you use for h.
In a real case scenario, using euclidian distance, a graph connecting different cities, h is the air-distance of two cities while g is their road-distance.
Furthermore, if you are using a monotonic heuristic (or an underestimating heuristic, such as the euclidian distance) you will not need the close list, since it is provent that the first found path will also be the shortest: longer or already visited paths will be dropped before being explored.
Probably what is confusing is the fact that you need to keep track of g during the exploration of the graph, while h just measure a straight line between current and end nodes, g measure all the lines between the nodes you explored to reach the current.
// h
function heuristic(n1, n2) {
return Math.sqrt(
Math.pow(n1.x - n2.x, 2) +
Math.pow(n1.y - n2.y, 2)
);
}
// g - actually is the same as h
const cost = heuristic;
function astar(start, end, graph, h, g) {
if (start.id == end.id) { return [ start.id ] }
// omitted CLEAN-UP of the graph
// close is not needed with an optimistic heuristic
// so I've commented the "close" parts.
// An optimistic heuristic works also if you decomment them
// var close = [];
var open = [];
start.g = 0;
start.h = h(start, end);
start.f = start.g + start.h;
open.push(start);
while (open.length) {
// since open is sorted, by popping
// the last element we take the cheapest node
var curr = open.pop();
if (curr == end) { return resolvePath(curr, graph); }
// close.push(curr);
for (let nid of curr.connectedToIds) {
// if (close.some(n => n.id == nid)) { continue; }
var neighbour = graph.find(n => n.id == nid);
// HERE you compute and store
// the current g of the node
var current_g = curr.g + g(curr, neighbour);
var isBetter_g = false;
var isInOpen = open.some(n => n.id == nid);
// Some implementations skip this check
// because they assume that the cost function
// is a non-negative distance.
// if so you could check just the two nodes g
// and insert the node if not already in the open set
// because the default g of a node is 0
if (!isInOpen) {
// unexplored node, maybe we should explore it
// later, so we add to the open set and
// we update it with the current path cost
open.push(neighbour)
isBetter_g = true;
}
else if (current_g < neighbour.g) {
// the current path is better than
// those already explored, we need to
// update the neighbour with the current path cost
isBetter_g = true;
}
if (isBetter_g) {
// === path cost update ===
// track current path
neighbour.parent = curr.id;
// HERE you keep track of the path
// total cost saved in neighbour.g
neighbour.g = current_g;
// neighbour.h is redundant, can be stored directly in f
// but keep it for debugging purpose
neighbour.h = h(neighbour, end);
neighbour.f = neighbour.g + neighbour.h;
if (!isInOpen) {
// sorting makes the last element of
// open the cheapest node. We sort after
// the path cost update to ensure this property
open.sort((n1, n2) => n2.f - n1.f)
}
}
}
}
// failure
return []; // or return null
}
// utility to retrieve an array of ids
// from the tracked path
function resolvePath(end, graph) {
let path = [ end.id ];
while (end && end.parent >= 0) {
path.unshift(end.parent);
end = graph.find(n => n.id == end.parent);
}
return path;
}
// example of using the function
astar(startNode, endNode, locations, heuristic, cost);
I have a MultiSelectDropDown, that is, several RadComboBox controls are used in a combined way. For example, I can have a dropdown for regions, another for depots and another for user. The idea is to change the content of lower levels dynamically whenever items are selected or unselected on a higher level. The problem is that in the case when many items are selected, this becomes brutally slow due to some Telerik functions, but I do not understand why. This is a chunk from the client-side of the MultiSelectDropDown prototype:
changeLowerLevels: function (valueIndex, values, value) {
if (!this.canChange) return;
//Get selected values from combobox
var combo = $find(this.ddlIDs[valueIndex - 1]);
var cbItems = combo.get_checkedItems();
var selectedItems = [];
var change = null;
var counter = 0;
if (cbItems.length) this.filterString = "";
for (var i = 0; i < cbItems.length; i++) {
counter++;
if (this.filterString == "") this.filterString = cbItems[i].get_text();
selectedItems.push(cbItems[i].get_value());
}
if (counter > 1) this.filterString += " with " + (counter - 1) + " other" + ((counter > 2) ? "s" : "");
if (JSON.stringify(selectedItems) === JSON.stringify(this.selectedItems[valueIndex - 1]) || selectedItems == [])
return;
this.selectedItems[valueIndex - 1] = selectedItems;
var controlObject = this;
var combo = $find(this.ddlIDs[valueIndex]);
var comboItems = combo.get_items();
if(!this.disabled) combo.enable();
combo.clearItems();
if (valueIndex == 1) this.twoLevelCache = values;
var val = values;
//break if all items are found
var nrOfSelectedItems = this.selectedItems[valueIndex - 1].length;
var nrOfFoundItems = 0;
var index = 0;
var indexes = [];
var found = false;
while (nrOfFoundItems < nrOfSelectedItems && val[index] !== undefined) {
found = (this.selectedItems[valueIndex - 1].indexOf(val[index].Value) != -1);
if (!(found))
index++;
else {
indexes.push(index)
nrOfFoundItems++;
index++;
}
}
//separators from valuesIndex - 1 level
var controlObject = this;
for (var i = 0; i < indexes.length; i++) {
var separator = new Telerik.Web.UI.RadComboBoxItem();
separator.set_text("<span><a class=\"checkAll tt-multi-uncheck-icon\" index=\"" + index + "\">U</a>" + $find(this.ddlIDs[valueIndex - 1]).findItemByValue(val[indexes[i]].Value).get_text() + "</span>");
separator.set_value("");
separator.set_isSeparator(true);
comboItems.add(separator);
this.twoLevelCache.push(val[indexes[i]].Levels);
//valuesIndex level
var valuesArray = val;
var comboItem = new Telerik.Web.UI.RadComboBoxItem();
for (var depot in valuesArray[indexes[i]].Levels) {
comboItem = new Telerik.Web.UI.RadComboBoxItem();
comboItem.set_text(valuesArray[indexes[i]].Levels[depot].Name);
comboItem.set_value(valuesArray[indexes[i]].Levels[depot].Value);
comboItems.add(comboItem);
comboItem = null;
}
$('#' + this.ddlIDs[valueIndex] + '_DropDown a.checkAll').unbind().on("click", function () {
checkAllLowerItems(this, controlObject.ddlIDs[valueIndex]);
});
}
combo.set_emptyMessage(this.allText);
//$("#" + this.ddlIDs[valueIndex]).html(returnValue);
if (this.ddlIDs.length > valueIndex + 1) {
var paramToPass = (((val == undefined) || (val[index] === undefined)) ? ("") : (val[index]));
if (this.allText.length > 0)
this.changeLowerLevels(valueIndex + 1, paramToPass, "");
else {
if (paramToPass !== "")
paramToPass = paramToPass.Levels;
if ((val[index] == undefined) || (val[index].Levels[0] === undefined) || (val[index].Levels[0].Value === "")) {
this.changeLowerLevels(valueIndex + 1, paramToPass, "");
}
else {
this.changeLowerLevels(valueIndex + 1, paramToPass, val[index].Levels[0].Value);
}
}
}
else {
if (this.allText.length > 0)
this.selectedItems[valueIndex] = "";
else
if ((val[index] == undefined) || (val[index].Levels[0] === undefined) || (val[index].Levels[0].Value === "")) {
this.selectedItems[valueIndex] = "";
}
else {
this.selectedItems[valueIndex] = val[index].Levels[0].Value;
}
}
this.setText();
}
combo.clearItems() is extremeley slow. I have take a look on how it is implemented:
function (){var f=this._parent._getControl();?if(f._checkBoxes){f._checkedIndicesJson="[]";?f._checkedIndices=[];?var g=f.get_items();?for(var d=0,e=g.get_count();?d<e;?d++){var c=f.get_items().getItem(d);?c.set_checked(false);?}f.updateClientState();?}a.RadComboBoxItemCollection.callBaseMethod(this,"clear");?}
How can I make sure that this Javascript function speeds up?
I have finally solved the problem by rewriting Telerik client-side functionalities. It was a long and difficult debugging, but it yielded a large performance boost in the most difficult circumstances. From ~30 000 milliseconds, to ~300. Let's see the parts of the optimization:
The actual rewrite
/* Overriding Telerik functions Start */
var overridenTelerikControls = false;
function overrideTelerikFunctionalities() {
if (!overridenTelerikControls) {
overridenTelerikControls = true;
Telerik.Web.UI.RadComboBox.prototype.clearItems = function (isMultiSelectDropDown) {
this.get_items().clear(isMultiSelectDropDown);
this._itemData = null;
};
Telerik.Web.UI.RadComboBoxItemCollection.prototype.clear = function (isMultiSelectDropDown){
var f=this._parent._getControl();
if(f._checkBoxes){
f._checkedIndicesJson="[]";
f._checkedIndices=[];
var g = f.get_items();
for(var d=0,e=g.get_count();d<e;d++){
var c=f.get_items().getItem(d);
c.set_checked(false, isMultiSelectDropDown);
}
if (isMultiSelectDropDown) {
f._updateComboBoxText();
if (f._checkAllCheckBoxElement != null) {
f._updateCheckAllState();
}
}
f.updateClientState();
}
Telerik.Web.UI.RadComboBoxItemCollection.callBaseMethod(this, "clear");
};
Telerik.Web.UI.RadComboBoxItem.prototype.set_checked = function (d, isMultiSelectDropDown){
if(!this.get_enabled()){
return;
}
this._setChecked(d);
var c=this.get_comboBox();
if(c){
if(d){
c._registerCheckedIndex(this.get_index());
}else{
c._unregisterCheckedIndex(this.get_index());
}
if (!isMultiSelectDropDown) {
c._updateComboBoxText();
}
if((!isMultiSelectDropDown) && (c._checkAllCheckBoxElement!=null)){
c._updateCheckAllState();
}
}
};
}
}
/* Overriding Telerik functions End*/
My approach was to keep the old way of their working by default, but if an isMultiSelectDropDown parameter is passed, then work in the optimized manners. So we have a switch materialized as a parameter and we can turn it on/off. The main difference was that the old way was to change the label text showing the selected elements each time a checkbox is checked/unchecked. The main improvement was to do this change after all the checkboxes were checked/unchecked. This extremely simple idea was the driving force behind the boost of performance.
Actual usage
overrideTelerikFunctionalities();
combo.clearItems(true);
This was the functionalities were overriden if they were not already and the parameter was true, therefore the new approach was chosen.
Test, test, test
I am working on a project that needs an excel like calculation engine in the browser. But, it doesn't need the grid UI.
Currently, I am able to do it by hiding the 'div' element of Handsontable. But, it isn't elegant. It is also a bit slow.
Is there a client side spreadsheet calculation library in javascript that does something like this?
x = [ [1, 2, "=A1+B1"],
[2, "=SUM(A1,A2"),3] ];
y = CalculateJS(x);
##############
y: [[1, 2, 3],
[2,3,3]]
I'm not aware of any (although I haven't really looked), but if you wish to implement your own, you could do something along these lines (heavily unoptimized, no error checking):
functions = {
SUM: function(args) {
var result = 0;
for (var i = 0; i < args.length; i++) {
result += parseInt(args[i]);
}
return result;
}
};
function get_cell(position) {
// This function returns the value of a cell at `position`
}
function parse_cell(position) {
cell = get_cell(position);
if (cell.length < 1 || cell[0] !== '=')
return cell;
return parse_token(cell.slice(1));
}
function parse_token(tok) {
tok = tok.trim();
if (tok.indexOf("(") < 0)
return parse_cell(tok);
var name = tok.slice(0, tok.indexOf("("));
if (!(name in functions)) {
return 0; // something better than this?
}
var arguments_tok = tok.slice(tok.indexOf("(") + 1);
var arguments = [];
while (true) {
var arg_end = arguments_tok.indexOf(",");
if (arg_end < 0) {
arg_end = arguments_tok.lastIndexOf(")");
if (arg_end < 0)
break;
}
if (arguments_tok.indexOf("(") >= 0 && (arguments_tok.indexOf("(") < arg_end)) {
var paren_amt = 1;
arg_end = arguments_tok.indexOf("(") + 1;
var end_tok = arguments_tok.slice(arguments_tok.indexOf("(") + 1);
while (true) {
if (paren_amt < 1) {
var last_index = end_tok.indexOf(",");
if (last_index < 0)
last_index = end_tok.indexOf(")");
arg_end += last_index;
end_tok = end_tok.slice(last_index);
break;
}
if (end_tok.indexOf("(") > 0 && (end_tok.indexOf("(") < end_tok.indexOf(")"))) {
paren_amt++;
arg_end += end_tok.indexOf("(") + 1;
end_tok = end_tok.slice(end_tok.indexOf("(") + 1);
} else {
arg_end += end_tok.indexOf(")") + 1;
end_tok = end_tok.slice(end_tok.indexOf(")") + 1);
paren_amt--;
}
}
}
arguments.push(parse_token(arguments_tok.slice(0, arg_end)));
arguments_tok = arguments_tok.slice(arg_end + 1);
}
return functions[name](arguments);
}
Hopefully this will give you a starting point!
To test in your browser, set get_cell to function get_cell(x) {return x;}, and then run parse_cell("=SUM(5,SUM(1,7,SUM(8,111)),7,8)"). It should result in 147 :)
I managed to do this using bacon.js. It accounts for cell interdependencies. As of now, it calculates values for javascript formula instead of excel formula by using an eval function. To make it work for excel formulae, all one has to do is replace eval with Handsontable's ruleJS library. I couldn't find a URI for that library... hence eval.
https://jsfiddle.net/sandeep_muthangi/3src81n3/56/
var mx = [[1, 2, "A1+A2"],
[2, "A2", "A3"]];
var output_reference_bus = {};
var re = /\$?[A-N]{1,2}\$?[1-9]{1,4}/ig
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split('');
function convertToCellRef(rows, cols) {
var alphabet_index = rows+1,
abet = "";
while (alphabet_index>0) {
abet = alphabet[alphabet_index%alphabet.length-1]+abet;
alphabet_index = Math.floor(alphabet_index/alphabet.length);
}
return abet+(cols+1).toString();
}
function getAllReferences(value) {
if (typeof value != "string")
return null;
var references = value.match(re)
if (references.length == 0)
return null;
return references;
}
function replaceReferences(equation, args) {
var index = 0;
return equation.replace(re, function(match, x, string) {
return args[index++];
});
}
//Assign an output bus to each cell
mx.forEach(function(row, row_index) {
row.forEach(function(cell, cell_index) {
output_reference_bus[convertToCellRef(row_index, cell_index)] = Bacon.Bus();
})
})
//assign input buses based on cell references... and calculate the result when there is a value on all input buses
mx.forEach(function(row, row_index) {
row.forEach(function(cell, cell_index) {
if ((all_refs = getAllReferences(cell)) != null) {
var result = Bacon.combineAsArray(output_reference_bus[all_refs[0]]);
for (i=1; i<all_refs.length; i++) {
result = Bacon.combineAsArray(result, output_reference_bus[all_refs[i]]);
}
result = result.map(function(data) {
return eval(replaceReferences(cell, data));
})
result.onValue(function(data) {
console.log(convertToCellRef(row_index, cell_index), data);
output_reference_bus[convertToCellRef(row_index, cell_index)].push(data);
});
}
else {
if (typeof cell != "string")
output_reference_bus[convertToCellRef(row_index, cell_index)].push(cell);
else
output_reference_bus[convertToCellRef(row_index, cell_index)].push(eval(cell));
}
})
})
output_reference_bus["A2"].push(20);
output_reference_bus["A1"].push(1);
output_reference_bus["A1"].push(50);
Now before everyone is helpful (seriously, you guys are awesome) I am doing a coding challenge that means I can't get code from other users/people. This does not, however, extend to advice so I wanted to know why my code crashes google chrome. I don't want am not allowed any code so please just point me in the right direction. I am sorry for such an odd request but I am at my wit's end.
http://jsfiddle.net/clarinetking/c49mutqw/9/
var chars;
var keyword = [];
var cipher;
var done = false;
var list1 = [];
var list2 = [];
var list3 = [];
var list4 = [];
var list5 = [];
var keylngth = 0;
$('#apnd').click(function () {
cipher = $('#Input').val();
chars = cipher.split('');
$('#Output').append(chars);
});
$('#key').click(function () {
while (done === false) {
var letter = prompt('insert letter, xyz to close');
keylngth++;
if (letter == 'xyz') {
done = true;
} else {
//Push letter to keyword array
keyword.push(letter);
}
}
});
$('#list').click(function () {
for (i = 0; i < chars.length; i++) {
var x = 1;
for (i = 1; i < keylngth+1; i++) {
if (i/x === 1) {
list1.push(chars[x]);
}
if (i/x === 2) {
list1.push(chars[x]);
}
if (i/x === 3) {
list1.push(chars[x]);
}
if (i/x === 4) {
list1.push(chars[x]);
}
if (i/x === 5) {
list1.push(chars[x]);
}
if (i/x === 6) {
list1.push(chars[x]);
}
if (i/x === 7) {
list1.push(chars[x]);
}
if (i/x === 8) {
list1.push(chars[x]);
}
}
x++;
}
alert(list1);
alert(list2);
});
I apologize to all you coders out there that are probably screaming at me USE A REPEAT LOOP! but for the list function I see no way to. As previously mentioned, no code please unless it's pseudo code :)
In your $('#list').click(function ()) function you are running an infinite for bucle, it's because you use the same i counter for the two for bucles so you javascript will run forerver and crash the browser
I'm creating an animated strip chart that redraws on every new packet message received from the header. First I create a function that checks if the chart already exists and if not builds it:
function drawAccel() {
if (chart == null) {
chart = Stripchart(document.getElementById('accel'));
}
if (orienteer == null) {
orienteer = Orienteer(document.getElementById('orienteer'));
}
chart.draw();
orienteer.draw();
}
Following that I run this function which loops and redraws the chart on every header packet recieved:
function messagecb(header, message) {
if(header.type == 6) {
// echo reply
// processEchoReply(message);
}else if(header.type == 4) {
// accel
var accels = message.b64UnpackAccelMsg();
for(var index in accels) {
var accel = accels[index];
var totalClock = accelEpochAdjust(accel.clock);
addAccelDatum(totalClock, accel.x, accel.y, accel.z);
}
drawAccel();
} else if(header.type == 3) {
// info
var info2 = message.b64UnpackInfo2Msg();
displayCurrentPosition(info2.fixtime, info2.lat, info2.lon, info2.alt);
displayMobileStatus(info2.rssi, info2.bandClass, info2.batt);
} else if(header.type == 11) {
btReceive(header, message);
}
}
I have no issues in all the modern browsers using this method, but in IE8 it really slows down a lot. This causes a slow running script error to occur which eventually ends up breaking the app. I also think something about my current logic is causing the chart to redraw even if the graph hasn't visually changed, but I'm unsure of how to check on that. Sorry for being long winded any help is greatly appreciated!
This might not be much help so please dont downvote.
I had a similar problem and only redrew every so many packets or over a set time frame like:
var mycars = new Array();
var count = 0;
function newPakcet(pck) {
mycars[mycars.length + 1] = pck;
redraw();
}
var redrawSize = 10;
function redraw(pck) {
if (mycars.length > 10) {
for(var i = 0 ;i < mycars.length;i++){
//Draw here
}
mycars = new Array();
}
}
Not tested it so there may be more syntax error.
After some trial and error along with a little help from some one else this ended up solving the problem. Set a local variable rather than a global to act as a counter that can be checked to see if it is a multiple of 10. Wrap the draw function with it so that it draws on every tenth packet.
function messagecb(header, message) {
if(header.type == 6) {
// processEchoReply(message);
} else if(header.type == 4) {
var accels = message.b64UnpackAccelMsg();
for(var index = 0; index < accels.length; ++index) {
var accel = accels[index];
var totalClock = accelEpochAdjust(accel.clock);
addAccelDatum(totalClock, accel.x, accel.y, accel.z);
}
if ( typeof messagecb.counter == 'undefined' ) {
messagecb.counter = 0;
}
++messagecb.counter;
if (messagecb.counter % 10 == 0) {
drawAccel();
}
} else if(header.type == 3) {
// info
var info2 = message.b64UnpackInfo2Msg();
displayCurrentPosition(info2.fixtime, info2.lat, info2.lon, info2.alt);
displayMobileStatus(info2.rssi, info2.bandClass, info2.batt);
} else if(header.type == 11) {
btReceive(header, message);
}
}