Create complex SVG without intermediate strings - javascript

I'm creating/editing a lot (100s to 1000s) of SVG path elements, with integer coordinates, in real time in response to user input (dragging).
var pathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');
var coords = [[0,0], [1,0], [1,1], [0,1]]; // In real case can be list of 1000s, dynamically generated
var d = '';
for (var i = 0; i < coords.length; ++i) {
d += (i == 0 ? 'M' : 'L') + coords[i][0] + ',' + coords[i][1];
}
d += 'z';
pathElement.setAttributeNS(null, 'd', d);
I can and do pool the path elements, so it minimises creation of objects + garbage in that respect. However, it seems to be that a lot of intermediate strings are created with the repeated use of +=. Also, it seems a bit strange to have the coordinates as numbers, convert them to strings, and then the system has to parse them back into numbers internally.
This seems a bit wasteful, and I fear jank since the above is repeated during dragging for every mousemouse. Can any of the above be avoided?
Context: this is part of a http://projections.charemza.name/
, source at https://github.com/michalc/projections, that can rotate the world map before applying the Mercator projection to it.

Try this:
var pathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');
var coords = [[0,0], [1,0], [1,1], [0,1]]; // In real case can be list of 1000s, dynamically generated
var d = [];
for (var i = 0; i < coords.length; ++i) {
d.push((i == 0 ? 'M' : 'L') + coords[i][0] + ',' + coords[i][1]);
}
d.push('z');
pathElement.setAttributeNS(null, 'd', d.join(''));

There is a method, using Uint8Array and TextDecoder that seems faster than string concatenation in Firefox, but slower than string concatenation in Chrome: https://jsperf.com/integer-coordinates-to-svg-path/1.
Intermediate strings are not created, but it does create a Uint8Array (a view on an a re-useable ArrayBuffer)
You can...
Manually find the ASCII characters from a number
Set the characters in an Uint8Array
Use new TextDecoder.decode(.... to get a Javascript string from the buffer
As below
// Each coord pair is 6 * 2 chars (inc minuses), commas, M or L, and z for path
var maxCoords = 1024 * 5;
var maxChars = maxCoords * (2 + 6 + 1 + 1) + 1
var coordsString = new Uint8Array(maxChars);
var ASCII_ZERO = 48;
var ASCII_MINUS = 45;
var ASCII_M = 77;
var ASCII_L = 76;
var ASCII_z = 122;
var ASCII_comma = 44;
var decoder = new TextDecoder();
var digitsReversed = new Uint8Array(6);
function concatInteger(integer, string, stringOffset) {
var newInteger;
var asciiValue;
var digitValue;
var offset = 0;
if (integer < 0) {
string[stringOffset] = ASCII_MINUS;
++stringOffset;
}
integer = Math.abs(integer);
while (integer > 0 || offset == 0) {
digitValue = integer % 10;
asciiValue = ASCII_ZERO + digitValue;
digitsReversed[offset] = asciiValue;
++offset;
integer = (integer - digitValue) / 10;
}
for (var i = 0; i < offset; ++i) {
string[stringOffset] = digitsReversed[offset - i - 1];
++stringOffset
}
return stringOffset;
}
var pathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');
var coordsStringOffset = 0;
var coords = [[0,0], [1,0], [1,1], [0,1]]; // In real case can be list of 1000s, dynamically generated
for (var i = 0; i < coords.length; ++i) {
coordsString[coordsStringOffset] = (i == 0) ? ASCII_M : ASCII_L;
++coordsStringOffset;
coordsStringOffset = concatInteger(coords[i][0], coordsString, coordsStringOffset);
coordsString[coordsStringOffset] = ASCII_comma
++coordsStringOffset;
coordsStringOffset = concatInteger(coords[i][1], coordsString, coordsStringOffset);
}
coordsString[coordsStringOffset] = ASCII_z;
++coordsStringOffset;
var d = decoder.decode(new Uint8Array(coordsString.buffer, 0, coordsStringOffset));
pathElement.setAttributeNS(null, 'd', d);

Related

How to find degree of a polynomial equation in JavaScript?

I want to find the degree of polynomial equation
den = a^2+a+1
The output of equation should be
2
or
den=a^2+a^3+a+1
The output of the equation should be
3
But I am unable to find the correct solution for JavaScript
You can use a regexp to get all the exponents and calculate the maximum
var r = /a(\^\d)?/g;
var t = 'a^2+a^3+a+1';
var order = t.match(r).reduce((m, d) => {
var ex = d.split('^')[1];
if(ex && (ex > m)){
return ex;
}
return m;
},0);
console.log(order); // Logs '3'
You can also do the same without using Array.prototype.reduce (have used a simple for loop and avoided ES6 syntax for simplicity)
var r = /a(\^\d)?/g;
var t = 'a^2+a^3+a+1';
var order = 0;
var matches = t.match(r);
for(var i = 0, j = matches.length ; i< j; i++){
var exp = matches[i].split('^')[1];
if(exp && (exp > order)){
order = exp;
}
}
console.log(order); // Logs '3'

THREE JS Removing BOX Geometry from Merged Geometry

I have a 100k+ boxes that are added to a merged geometry. I need to remove some geometries occasionally from this merged geometry. Can I loop over the position attributes in steps of 108 or 72 vertices per cube to pull out the positions of these boxes or does merge also merge vertices?
function blockCubeAlter(grid, blockModel) {
function getGridElevation(n, e, grid) {
var y_grid = Math.floor((grid.metaData.yMax - n) / grid.metaData.yStep) + 1;
var x_grid = Math.floor((e - grid.metaData.xMin) / grid.metaData.xStep);
var array_pos = Math.round(y_grid * (grid.metaData.nCol + 1) + x_grid);
return isNaN(grid.elevations[array_pos]) ? Infinity : grid.elevations[array_pos];
}
var tmpBox = new THREE.BoxBufferGeometry(blockModel.x_step, blockModel.y_step, 2);
var myBlock = scene.getObjectByName('blockModel');
var pointsPerVertex = 3,
vertexPerFace = 4,// this might be 3 triangles?
facePerSide = 1, // this might be 2 triangles per face?
sidePerBox = 6;
var pointsPerCube = pointsPerVertex * vertexPerFace * facePerSide * sidePerBox;
for (var i = 0, j = myBlock.geometry.attributes.position.array.length; i < j; i += pointsPerCube) {
var above = false,
below = false;
for (var k = i; k < i + pointsPerCube; k += pointsPerVertex) {
var n = myBlock.geometry.attributes.position.array[k + 1];
var e = myBlock.geometry.attributes.position.array[k + 0];
var z = myBlock.geometry.attributes.position.array[k + 2];
if (z > getGridElevation(n + WEBGLyTranslate, e + WEBGLxTranslate, grid))
above = true;
else
below = true;
if (above && below) break; // intersect surface
}
if (above) {
if (below) {
var newBoxGeometry = tmpBox.clone();
newBoxGeometry.attributes.position.array = myBlock.geometry.attributes.position.array.slice(i, i + pointsPerCube);
for (var materialGroupIndex = 0, z = myBlock.geometry.groups.length; materialGroupIndex < z; materialGroupIndex++) {
var myGeometryGroup = myBlock.geometry.groups[materialGroupIndex];
if (i >= myGeometryGroup.start && i < myGeometryGroup.start + myGeometryGroup.count) {
var newMaterial = myBlock.material.materials[myGeometryGroup.materialIndex].clone();
var mesh = new THREE.Mesh(newBoxGeometry, newMaterial)
scene.add(mesh);
break;
}
}
}
for (var k = i; k < i + pointsPerCube; k++) {
myBlock.geometry.attributes.position.array[k] = undefined;
}
}
}
myBlock.geometry.attributes.position.needsUpdate = true;
}
I am getting pretty random results. how does merge set the position array, does it merge vertices or just append?
As seen in my comments the number of vertex between the tmpBox and the vertices per box in the merged blockModel were not the same. This change in vertices was because the orginal merge was made from boxGeometry, merged, and then converted to buffer geometry. this was how the merged mesh was converted.
finalGeometry = new THREE.BufferGeometry().fromGeometry(tmpGeometry);
I was able to resolve the issue by creating the tmpBox by using:
var tmpBox = new THREE.BufferGeometry().fromGeometry(new THREE.BoxGeometry(blockModel.x_step, blockModel.y_step, 2));
seems odd that
new THREE.BufferGeometry().fromGeometry(new THREE.BoxGeometry(blockModel.x_step, blockModel.y_step, 2)) != new THREE.BoxBufferGeometry(blockModel.x_step, blockModel.y_step, 2);
But they have different number of vertices. I think one is using a 4 vertexed face and the other is using three vertices faces.

Fill pdf form with javascript (client-side only)

I need to fill a pdf form automatically in my angularjs webapp. The pdf form is generated outside the app so I can configure it as I want.
In my app, I just need to load the pdf, modify the form fields and flatten the file so it doesn't look like a form anymore.
Do you know any way to do it?
Edit:
I've found iText but it's a java library which won't work for my project (the app runs on tablets so I'm looking for something 100% HTML5)
There is now another solution that worked for me.
It's this JS package: https://github.com/phihag/pdfform.js
Also available on NPM: https://www.npmjs.com/package/pdfform.js
If you have troubles opening your PDF files, the best bet is to use the mozilla's PDF.js library which works with every PDF files I tried.
The only drawback as of today is that it's not working as expected with webpack. You have to import the JS files with a script tag.
I've found a solution...not perfect but it should fit most requirements. It doesn't use any server (perfect for privacy requirements) or library! First of all, the PDF must be version 1.5 (Acrobat 6.0 or later). The original pdf can be another version but when you create the fields you must save it as compatible for Acrobat 6.0 or later. If you want to make sure the format is right, you can check there
So let's say I have 'myform.pdf' file (with no form fields); I open it with Acrobat Pro (I have Acrobat Pro 11 but it should work with other versions). I add fields and pre-fill the field's value (not the field name!) with a 'code' (unique text string). This code will be find/replace with the string you want by the javascript function below so let say '%address%' (you can add multiple fields but use a different code to differenciate fields). If you want to have a flatten look of the field, set the field to read-only. To save it, go to File -> Save as other... -> Optimized PDF and choose "Acrobat 6.0 and later" under Make compatible with (top right of the pop-up).
Once you have your file saved, you can check that the format is right by opening it in a text editor and looking for your codes (in my case '%address%'). Count number of occurences, it should appear three times.
The following function does three things:
- Changes the fields content
- Recalculate the content's length
- Fix the cross reference tables
So now the function (look at the end for the final pdf blob):
#param certificate: your pdf form (format of this variable must be compatible with FileReader)
#param changes: the field changes, [{find: '%address%', replace: '2386 5th Street, New York, USA'}, ...]
// Works only for PDF 1.5 (Acrobat 6.0 and later)
var fillCertificate = function (certificate, changes) {
// replace a a substring at a specific position
String.prototype.replaceBetween = function(start, end, what) {
return this.substring(0, start) + what + this.substring(end);
};
// format number with zeros at the beginning (n is the number and length is the total length)
var addLeadingZeros = function (n, length) {
var str = (n > 0 ? n : -n) + "";
var zeros = "";
for (var i = length - str.length; i > 0; i--)
zeros += "0";
zeros += str;
return n >= 0 ? zeros : "-" + zeros;
}
// Create the reader first and read the file (call after the onload method)
var reader = new FileReader();
// To change the content of a field, three things must be done; - change the text of the field, - change the length of the content field, - change the cross table reference
reader.onload = function(aEvent) {
var string = aEvent.target.result;
// Let's first change the content and the content's length
var arrayDiff = [];
var char;
for(var foo = 0; foo < changes.length; foo++) {
// Divide the string into a table of character for finding indices
char = new Array(string.length);
for (var int = 0; int < string.length; int++) {
char[int] = string.charAt(int);
}
// Let's find the content's field to change and change it everywhere
var find = changes[foo].find;
var replace = changes[foo].replace;
var lengthDiff = replace.length - find.length;
var search = new RegExp(find, "g");
var match;
var lastElements = [];
var int = 0;
var objectLenPos;
var objectLenEnd;
// Each time you change the content, compute the offset difference (number of characters). We'll add it later for the cross tables
while (match = search.exec(string)) {
arrayDiff.push({index: match.index, diff: lengthDiff});
lastElements.push({index: match.index, diff: lengthDiff});
// Find length object
if(int == 0){
var length = 0;
var index;
while(char[match.index - length] != '\r'){
index = match.index - length;
length++;
}
objectLenPos = index + 10;
length = 0;
while(char[objectLenPos + length] != ' '){
length++;
objectLenEnd = objectLenPos + length;
}
}
int++;
}
var lengthObject = string.slice(objectLenPos, objectLenEnd) + ' 0 obj';
var objectPositionStart = string.search(new RegExp('\\D' + lengthObject, 'g')) + lengthObject.toString().length + 2;
var length = 0;
var objectPositionEnd;
while(char[objectPositionStart + length] != '\r'){
length++;
objectPositionEnd = objectPositionStart + length;
}
// Change the length of the content's field
var lengthString = new RegExp('Length ', "g");
var fieldLength;
var newLength;
string = string.replace(lengthString, function (match, int) {
// The length is between the two positions calculated above
if (int > objectPositionStart && int < objectPositionEnd) {
var length = 0;
var end;
while (char[int + 7 + length] != '/') {
length++;
end = int + 7 + length;
}
fieldLength = string.slice(end - length, end);
newLength = parseInt(fieldLength) + lengthDiff;
if (fieldLength.length != newLength.toString().length) {
arrayDiff.push({index: int, diff: (newLength.toString().length - fieldLength.length)});
}
// Let's modify the length so it's easy to find and replace what interests us; the length number itself
return "Length%";
}
return match;
});
// Replace the length with the new one based on the length difference
string = string.replace('Length%' + fieldLength, 'Length ' + (newLength).toString());
string = string.replace(new RegExp(find, 'g'), replace);
}
// FIND xref and repair cross tables
// Rebuild the table of character
var char = new Array(string.length);
for (var int = 0; int < string.length; int++) {
char[int] = string.charAt(int);
};
// Find XRefStm (cross reference streams)
var regex = /XRefStm/g, result, indices = [];
while ( (result = regex.exec(string)) ) {
indices.push(result.index);
}
// Get the position of the stream
var xrefstmPositions = [];
for(var int = 0; int < indices.length; int++){
var start;
var length = 0;
while(char[indices[int] - 2 - length] != ' '){
start = indices[int] - 2 - length;
length++;
}
var index = parseInt(string.slice(start, start + length));
var tempIndex = parseInt(string.slice(start, start + length));
// Add the offset (consequence of the content changes) to the index
for(var num = 0; num < arrayDiff.length; num++){
if(index > arrayDiff[num].index){
index = index + arrayDiff[num].diff;
}
}
string = string.replaceBetween(start, start + length, index);
// If there is a difference in the string length then update what needs to be updated
if(tempIndex.toString().length != index.toString().length){
arrayDiff.push({index: start, diff: (index.toString().length - tempIndex.toString().length)});
char = new Array(string.length);
for (var int = 0; int < string.length; int++) {
char[int] = string.charAt(int);
};
}
xrefstmPositions.push(index);
}
// Do the same for non-stream
var regex = /startxref/g, result, indices = [];
while ( (result = regex.exec(string)) ) {
indices.push(result.index);
}
for(var int = 0; int < indices.length; int++){
var end;
var length = 0;
while(char[indices[int] + 11 + length] != '\r'){
length++;
end = indices[int] + 11 + length;
}
var index = parseInt(string.slice(end - length, end));
var tempIndex = parseInt(string.slice(end - length, end));
for(var num = 0; num < arrayDiff.length; num++){
if(index > arrayDiff[num].index){
index = index + arrayDiff[num].diff;
}
}
string = string.replaceBetween(end - length, end, index);
if(tempIndex.toString().length != index.toString().length){
arrayDiff.push({index: end - length, diff: (index.toString().length - tempIndex.toString().length)});
char = new Array(string.length);
for (var int = 0; int < string.length; int++) {
char[int] = string.charAt(int);
};
}
xrefstmPositions.push(index);
}
xrefstmPositions.reverse();
var firstObject, objectLength, end;
var offset;
// Updated the cross tables
for(var int = 0; int < xrefstmPositions.length; int++) {
var length = 0;
var end;
if(char[xrefstmPositions[int]] == 'x'){
offset = 6;
} else{
offset = 0;
}
// Get first object index (read pdf documentation)
while(char[xrefstmPositions[int] + offset + length] != ' '){
length++;
end = xrefstmPositions[int] + offset + length;
}
firstObject = string.slice(end - length, end);
// Get length of objects (read pdf documentation)
length = 0;
while(char[xrefstmPositions[int] + offset + 1 + firstObject.length + length] != '\r'){
length++;
end = xrefstmPositions[int] + offset + 1 + firstObject.length + length;
}
objectLength = string.slice(end - length, end);
// Replace the offset by adding the differences from the content's field
for(var num = 0; num < objectLength; num++){
if(char[xrefstmPositions[int]] == 'x'){
offset = 9;
} else{
offset = 3;
}
// Check if it's an available object
if (char[xrefstmPositions[int] + 17 + offset + firstObject.length + objectLength.length + (num * 20)] == 'n') {
var objectCall = (parseInt(firstObject) + num).toString() + " 0 obj";
var regexp = new RegExp('\\D' + objectCall, "g");
var m;
var lastIndexOf;
// Get the last index in case an object is created more than once. (not very accurate and can be improved)
while (m = regexp.exec(string)) {
lastIndexOf = m.index;
}
string = string.replaceBetween(xrefstmPositions[int] + offset + firstObject.length + objectLength.length + (num * 20), xrefstmPositions[int] + 10 + offset + firstObject.length + objectLength.length + (num * 20), addLeadingZeros(lastIndexOf + 1, 10));
}
if(num == objectLength - 1){
if (char[xrefstmPositions[int] + offset + firstObject.length + objectLength.length + ((num + 1) * 20)] != 't'){
xrefstmPositions.push(xrefstmPositions[int] + offset + firstObject.length + objectLength.length + ((num + 1) * 20));
}
}
}
}
// create a blob from the string
var byteNumbers = new Array(string.length);
for (var int = 0; int < string.length; int++) {
byteNumbers[int] = string.charCodeAt(int);
}
var byteArray = new Uint8Array(byteNumbers);
var blob = new Blob([byteArray], {type : 'application/pdf'});
// Do whatever you want with the blob here
};
reader.readAsBinaryString(certificate);
}
So the code is not clean at all but it works :)
Let me know if you have any question
pdf-lib was the best choice for me. Look, after trying many random solutions I found this lib that's very very simple to implement and, off-topic, has a great TS support (nowadays it means a lot 😬).
Fill form official example: https://pdf-lib.js.org/#fill-form
As far as I can see, there is no client-side application on tablets which would do that.
That means you will need server-side support, and iText is indeed one of the products out there. Another one is FDFMerge by Appligent, which does fill and can be set to flattening.

Randomly generate objects in canvas without duplicate or overlap

How do I generate objects on a map, without them occupying the same space or overlapping on a HTML5 Canvas?
X coordinate is randomly generated, to an extent. I thought checking inside the array to see if it's there already, and the next 20 values after that (to account for the width), with no luck.
var nrOfPlatforms = 14,
platforms = [],
platformWidth = 20,
platformHeight = 20;
var generatePlatforms = function(){
var positiony = 0, type;
for (var i = 0; i < nrOfPlatforms; i++) {
type = ~~(Math.random()*5);
if (type == 0) type = 1;
else type = 0;
var positionx = (Math.random() * 4000) + 500 - (points/100);
var duplicatetest = 21;
for (var d = 0; d < duplicatetest; d++) {
var duplicate = $(jQuery.inArray((positionx + d), platforms));
if (duplicate > 0) {
var duplicateconfirmed = true;
}
}
if (duplicateconfirmed) {
var positionx = positionx + 20;
}
var duplicateconfirmed = false;
platforms[i] = new Platform(positionx,positiony,type);
}
}();
I originally made a cheat fix by having them generate in an area roughly 4000 big, decreasing the odds, but I want to increase the difficulty as the game progresses, by making them appear more together, to make it harder. But then they overlap.
In crude picture form, I want this
....[]....[].....[]..[]..[][]...
not this
......[]...[[]]...[[]]....[]....
I hope that makes sense.
For reference, here is the code before the array check and difficulty, just the cheap distance hack.
var nrOfPlatforms = 14,
platforms = [],
platformWidth = 20,
platformHeight = 20;
var generatePlatforms = function(){
var position = 0, type;
for (var i = 0; i < nrOfPlatforms; i++) {
type = ~~(Math.random()*5);
if (type == 0) type = 1;
else type = 0;
platforms[i] = new Platform((Math.random() * 4000) + 500,position,type);
}
}();
EDIT 1
after some debugging, duplicate is returning as [object Object] instead of the index number, not sure why though
EDIT 2
the problem is the objects are in the array platforms, and x is in the array object, so how can I search inside again ? , that's why it was failing before.
Thanks to firebug and console.log(platforms);
platforms = [Object { image=img, x=1128, y=260, more...}, Object { image=img, x=1640, y=260, more...} etc
You could implement a while loop that tries to insert an object and silently fails if it collides. Then add a counter and exit the while loop after a desired number of successful objects have been placed. If the objects are close together this loop might run longer so you might also want to give it a maximum life span. Or you could implement a 'is it even possible to place z objects on a map of x and y' to prevent it from running forever.
Here is an example of this (demo):
//Fill an array with 20x20 points at random locations without overlap
var platforms = [],
platformSize = 20,
platformWidth = 200,
platformHeight = 200;
function generatePlatforms(k) {
var placed = 0,
maxAttempts = k*10;
while(placed < k && maxAttempts > 0) {
var x = Math.floor(Math.random()*platformWidth),
y = Math.floor(Math.random()*platformHeight),
available = true;
for(var point in platforms) {
if(Math.abs(point.x-x) < platformSize && Math.abs(point.y-y) < platformSize) {
available = false;
break;
}
}
if(available) {
platforms.push({
x: x,
y: y
});
placed += 1;
}
maxAttempts -= 1;
}
}
generatePlatforms(14);
console.log(platforms);
Here's how you would implement a grid-snapped hash: http://jsfiddle.net/tqFuy/1/
var can = document.getElementById("can"),
ctx = can.getContext('2d'),
wid = can.width,
hei = can.height,
numPlatforms = 14,
platWid = 20,
platHei = 20,
platforms = [],
hash = {};
for(var i = 0; i < numPlatforms; i++){
// get x/y values snapped to platform width/height increments
var posX = Math.floor(Math.random()*(wid-platWid)/platWid)*platWid,
posY = Math.floor(Math.random()*(hei-platHei)/platHei)*platHei;
while (hash[posX + 'x' + posY]){
posX = Math.floor(Math.random()*wid/platWid)*platWid;
posY = Math.floor(Math.random()*hei/platHei)*platHei;
}
hash[posX + 'x' + posY] = 1;
platforms.push(new Platform(/* your arguments */));
}
Note that I'm concatenating the x and y values and using that as the hash key. This is to simplify the check, and is only a feasible solution because we are snapping the x/y coordinates to specific increments. The collision check would be more complicated if we weren't snapping.
For large sets (seems unlikely from your criteria), it'd probably be better to use an exclusion method: Generate an array of all possible positions, then for each "platform", pick an item from the array at random, then remove it from the array. This is similar to how you might go about shuffling a deck of cards.
Edit — One thing to note is that numPlatforms <= (wid*hei)/(platWid*platHei) must evaluate to true, otherwise the while loop will never end.
I found the answer on another question ( Searching for objects in JavaScript arrays ) using this bit of code to search the objects in the array
function search(array, value){
var j, k;
for (j = 0; j < array.length; j++) {
for (k in array[j]) {
if (array[j][k] === value) return j;
}
}
}
I also ended up rewriting a bunch of the code to speed it up elsewhere and recycle platforms better.
it works, but downside is I have fewer platforms, as it really starts to slow down. In the end this is what I wanted, but its no longer feasible to do it this way.
var platforms = new Array();
var nrOfPlatforms = 7;
platformWidth = 20,
platformHeight = 20;
var positionx = 0;
var positiony = 0;
var arrayneedle = 0;
var duplicatetest = 21;
function search(array, value){
var j, k;
for (j = 0; j < array.length; j++) {
for (k in array[j]) {
if (array[j][k] === value) return j;
}
}
}
function generatePlatforms(ind){
roughx = Math.round((Math.random() * 2000) + 500);
type = ~~(Math.random()*5);
if (type == 0) type = 1;
else type = 0;
var duplicate = false;
for (var d = 0; d < duplicatetest; d++) {
arrayneedle = roughx + d;
var result = search(platforms, arrayneedle);
if (result >= 0) {
duplicate = true;
}
}
if (duplicate = true) {
positionx = roughx + 20;
}
if (duplicate = false) {
positionx = roughx;
}
platforms[ind] = new Platform(positionx,positiony,type);
}
var generatedplatforms = function(){
for (var i = 0; i < nrOfPlatforms; i++) {
generatePlatforms(i);
};
}();
you go big data, generate all possibilities, store each in an array, shuffle the array,
trim the first X items, this is your non heuristic algorithm.

How can I convert a Guid to a Byte array in Javascript?

I have a service bus, and the only way to transform data is via JavaScript. I need to convert a Guid to a byte array so I can then convert it to Ascii85 and shrink it into a 20 character string for the receiving customer endpoint.
Any thoughts would be appreciated.
Try this (needs LOTS of tests):
var guid = "{12345678-90ab-cdef-fedc-ba0987654321}";
window.alert(guid + " = " + toAscii85(guid))
function toAscii85(guid)
{
var ascii85 = ""
var chars = guid.replace(/\{?(?:(\w+)-?)\}?/g, "$1");
var patterns = ["$4$3$2$1", "$2$1$4$3", "$1$2$3$4", "$1$2$3$4"];
for(var i=0; i < 32; i+=8)
{
var block = chars.substr(i, 8)
.replace(/(..)(..)(..)(..)/, patterns[i / 8]) //poorman shift
var decValue = parseInt(block, 16);
var segment = ""
if(decValue == 0)
{
segment = "z"
}
else
{
for(var n = 4; n >= 0; n--)
{
segment = String.fromCharCode((decValue % 85) + 33) + segment;
decValue /= 85;
}
}
ascii85 += segment
}
return "<~" + ascii85 + "~>";
}
Check the unparse() method in node-uuid package and its example here:
https://www.npmjs.com/package/node-uuid#uuid-unparse-buffer-offset

Categories