javascript functions arguments in an array - javascript

what I'm trying to do is this
$.each($(".canvas"), function(n) {
var canvas = $(this)[0].getContext("2d");
canvas.drawImage(options[n]);
});
where options would be an array of arguments, but can't figure out how should the array be formatted for it to work
obviously not
['img, 0, 0, 70, 17, 21, 16, 70, 17', 'img, 0, 0, 80, 12, 21, 16, 70, 17']
this neither
[''+img+', 0, 0, 70, 17, 21, 16, 70, 17', ''+img+', 0, 0, 80, 12, 21, 16, 70, 17']
nor this
{0: [img, 0, 0, 70, 17, 21, 16, 70, 17]}
this would not work either
var options = [[img, 0, 0, 70, 17, 21, 16, 70, 17],
[img, 0, 16, 70, 17, 21, 16, 70, 17],
[img, 0, 32, 70, 17, 21, 16, 70, 17],
[img, 0, 48, 70, 17, 21, 16, 70, 17]];
img.onload = function() {
$.each($(".canvas"), function(n) {
var canvas = $(this)[0].getContext("2d");
canvas.drawImage(options[n].join(', '));
});
};
the error is alway Uncaught TypeError: Type error or Uncaught TypeError: Illegal invocation

Use Function.apply.
canvas.drawImage.apply(canvas, options[n]);
Where options[n] looks something like
[img, 0, 0, 70, 17, 21, 16, 70, 17]
Full example:
var options = [[img, 0, 0, 70, 17, 21, 16, 70, 17],
[img, 0, 16, 70, 17, 21, 16, 70, 17],
[img, 0, 32, 70, 17, 21, 16, 70, 17],
[img, 0, 48, 70, 17, 21, 16, 70, 17]];
$(img).load(function()
{
$(".canvas").each(function(n)
{
var canvas = this.getContext('2d');
canvas.drawImage.apply(canvas, options[n]);
});
});
Demo: http://jsfiddle.net/mattball/5EQbC/

Related

What's faster in JS: Object with keys or array with an if statement?

Which of these structures is generally more performant in JS with the v8 engine?
Example 1:
const obj = {
a: 'hello',
b: 'world',
c: 'etc',
};
function getVal(str) {
return obj[str];
}
getVal('b');
Example 2:
function getVal(str) {
if(str=='a') return 'hello';
if(str=='b') return 'world';
return 'etc';
}
getVal('b');
I would imagine example 2 is faster, but 1 is better code. I ask because I'm looking at chess AI, and can structure the position weights as objects:
const positions_w = {
'p':[
[ 100, 100, 100, 100, 105, 100, 100, 100],
[ 78, 83, 86, 73, 102, 82, 85, 90],
[ 7, 29, 21, 44, 40, 31, 44, 7],
[ -17, 16, -2, 15, 14, 0, 15, -13],
[ -26, 3, 10, 9, 6, 1, 0, -23],
[ -22, 9, 5, -11, -10, -2, 3, -19],
[ -31, 8, -7, -37, -36, -14, 3, -31],
[ 0, 0, 0, 0, 0, 0, 0, 0]
],
'n': // ...
and then get them with positions_w[piece.type][y][x] or structure them in arrays:
const p = [
[ 100, 100, 100, 100, 105, 100, 100, 100],
[ 78, 83, 86, 73, 102, 82, 85, 90],
[ 7, 29, 21, 44, 40, 31, 44, 7],
[ -17, 16, -2, 15, 14, 0, 15, -13],
[ -26, 3, 10, 9, 6, 1, 0, -23],
[ -22, 9, 5, -11, -10, -2, 3, -19],
[ -31, 8, -7, -37, -36, -14, 3, -31],
[ 0, 0, 0, 0, 0, 0, 0, 0]
];
and then get them with if(piece.type=='p')return p[y][x]
If the object is small and was created with all of its keys, the speed of property access should be comparable to a switch statement.
One thing to consider however is that you will be updating your position weights pretty often. For this reason I think one big "3D" Int16Array would make a greater difference overall.
In any case, I would make sure no part of my app is dependant on the concrete data structure so that it is possible to delay this decision until later when you can actually profile your AI speed.

Iterate between specific range of number in a array [duplicate]

This question already has answers here:
Create array of all integers between two numbers, inclusive, in Javascript/jQuery
(21 answers)
Closed 3 years ago.
I have an array with two elements [5, 50]. I want this array iterate as [5, 6, 7,......, 49, 50].
I try below code. But not working as my expectation.
function All(arr) {
let newArry = [];
for(let i = arr[0]; i < arr[1]; i++ ) {
newArry[i] = newArry.push(i);
}
return newArry;
}
console.log(All([5, 50]));
Do like this remove newArry[i] =
function All(arr) {
let newArry = [];
for(let i = arr[0]; i < arr[1]; i++ ) {
newArry.push(i);
}
return newArry;
}
console.log(All([5, 50]));
Get the two values you want to iterate between:
const [start, end] = [5, 50];
Create a new array of length difference between your two points:
Array(end - start + 1) // [undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined]
Since all the values will be undefined, create an iterator object using Array#keys: Array(end - start + 1).keys() // [object Array Iterator]
Spread that into an array:
[...Array(end - start + 1).keys()] // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45]
Map over the values to create your new array:
[...Array(end - start + 1).keys()].map(i => i + start) // [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
...which gives you something like this:
const range = (n, m) => [...Array(m - n + 1).keys()].map(i => i + n);
const [start, end] = [5, 50];
console.log(range(start, end)); // [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
Or, to maintain the API of the function in your question, like this:
const All = (arr) => {
const [n, m] = arr;
return [...Array(m - n + 1).keys()].map(i => i + n);
}
console.log(All([5, 50])); // [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
The Array.prototype.push method mutates the original array, so reassigning doesn't make sense.
Just do:
newArray.push(i);

SVG to Image export performance issues (using canvg / XMLSerializer / getComputedStyle)

I am using canvg to convert a chart svg to an image. We have the issue that by default not all CSS attributes are applied to the image so we ended up using getComputedStyle in a loop.
This is a total mess under performance aspects if we have 10 or even 20 charts to be exported at once.
var labels = ['2018-10-01', '2018-10-02', '2018-10-03', '2018-10-04', '2018-10-05', '2018-10-06', '2018-10-07', '2018-10-08', '2018-10-09', '2018-10-10', '2018-10-11', '2018-10-12', '2018-10-13', '2018-10-14', '2018-10-15', '2018-10-16', '2018-10-17', '2018-10-18', '2018-10-19', '2018-10-20', '2018-10-21', '2018-10-22', '2018-10-23', '2018-10-24', '2018-10-25', '2018-10-26', '2018-10-27', '2018-10-28', '2018-10-29', '2018-10-30', '2018-10-31', '2018-11-01', '2018-11-02', '2018-11-03', '2018-11-04', '2018-11-05', '2018-11-06', '2018-11-07', '2018-11-08', '2018-11-09', '2018-11-10', '2018-11-11', '2018-11-12', '2018-11-13', '2018-11-14', '2018-11-15', '2018-11-16', '2018-11-17', '2018-11-18', '2018-11-19', '2018-11-20', '2018-11-21', '2018-11-22', '2018-11-23', '2018-11-24', '2018-11-25', '2018-11-26', '2018-11-27', '2018-11-28', '2018-11-29', '2018-11-30', '2018-12-01', '2018-12-02', '2018-12-03', '2018-12-04', '2018-12-05', '2018-12-06', '2018-12-07', '2018-12-08', '2018-12-09', '2018-12-10', '2018-12-11', '2018-12-12', '2018-12-13', '2018-12-14', '2018-12-15', '2018-12-16', '2018-12-17', '2018-12-18', '2018-12-19', '2018-12-20', '2018-12-21', '2018-12-22', '2018-12-23', '2018-12-24', '2018-12-25', '2018-12-26', '2018-12-27', '2018-12-28', '2018-12-29', '2018-12-30', '2018-12-31', '2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04', '2019-01-05', '2019-01-06', '2019-01-07', '2019-01-08', '2019-01-09', '2019-01-10', '2019-01-11', '2019-01-12', '2019-01-13', '2019-01-14', '2019-01-15', '2019-01-16', '2019-01-17', '2019-01-18', '2019-01-19', '2019-01-20', '2019-01-21', '2019-01-22', '2019-01-23', '2019-01-24', '2019-01-25', '2019-01-26', '2019-01-27', '2019-01-28', '2019-01-29', '2019-01-30', '2019-01-31', '2019-02-01', '2019-02-02', '2019-02-03', '2019-02-04', '2019-02-05', '2019-02-06', '2019-02-07', '2019-02-08', '2019-02-09', '2019-02-10', '2019-02-11', '2019-02-12', '2019-02-13', '2019-02-14', '2019-02-15', '2019-02-16', '2019-02-17', '2019-02-18', '2019-02-19', '2019-02-20', '2019-02-21', '2019-02-22', '2019-02-23', '2019-02-24', '2019-02-25', '2019-02-26', '2019-02-27', '2019-02-28'];
var columns = ['data101', 'data2', 'data347'];
var data = [
[0, 0, 2, 2, 1, 2, 7, 3, 1, 7, 5, 5, 5, 5, 6, 6, 11, 7, 2, 7, 16, 7, 3, 5, 10, 9, 11, 7, 3, 7, 7, 10, 10, 9, 18, 10, 20, 13, 9, 19, 16, 13, 20, 18, 14, 15, 18, 20, 19, 11, 13, 13, 12, 16, 11, 12, 21, 20, 23, 19, 19, 23, 23, 24, 23, 25, 21, 23, 20, 22, 21, 23, 24, 25, 27, 29, 28, 25, 24, 17, 20, 24, 22, 27, 21, 27, 19, 26, 31, 27, 28, 27, 21, 20, 27, 22, 22, 19, 17, 21, 23, 19, 22, 20, 21, 25, 15, 19, 20, 19, 21, 28, 17, 20, 14, 18, 17, 20, 27, 21, 18, 18, 20, 16, 27, 16, 16, 9, 18, 8, 19, 13, 8, 16, 15, 16, 9, 15, 10, 13, 10, 11, 10, 13, 12, 7, 14, 16, 13, 14, 8],
[0, 0, 338, 1201, 1268, 1371, 1286, 1148, 446, 288, 228, 253, 193, 201, 283, 393, 436, 379, 421, 444, 444, 417, 513, 353, 364, 399, 238, 191, 305, 337, 365, 349, 365, 244, 101, 39, 55, 72, 151, 98, 31, 127, 114, 92, 104, 196, 307, 245, 84, 168, 41, 38, 292, 488, 536, 569, 495, 448, 408, 358, 344, 380, 328, 334, 332, 330, 345, 312, 369, 377, 356, 301, 226, 273, 237, 116, 178, 133, 114, 138, 95, 143, 74, 74, 83, 47, 75, 101, 96, 59, 46, 128, 70, 57, 93, 80, 94, 93, 63, 86, 81, 63, 70, 102, 91, 67, 69, 68, 88, 76, 79, 70, 119, 88, 74, 94, 76, 54, 82, 90, 75, 130, 67, 78, 106, 91, 81, 27, 77, 21, 104, 83, 55, 60, 62, 304, 393, 191, 292, 77, 76, 55, 125, 89, 99, 127, 60, 75, 99, 120, 56],
[0, 0, 0, 1419, 7454, 12638, 10944, 7652, 4272, 11219, 9071, 7207, 7929, 8373, 9566, 6310, 7406, 9286, 8415, 7659, 6457, 3380, 10902, 10952, 10508, 7219, 4625, 4484, 4396, 5178, 5991, 7927, 14132, 14307, 5094, 10011, 6257, 9184, 18574, 12597, 11415, 7118, 9991, 10225, 14337, 4417, 12701, 17833, 23553, 10037, 4833, 5894, 19421, 14735, 12597, 8730, 5888, 11836, 13143, 17219, 10492, 10528, 8649, 11868, 10502, 6758, 7672, 8479, 11142, 22330, 26595, 4423, 17434, 8709, 9657, 7823, 9135, 19765, 18016, 16010, 8419, 7300, 8877, 9611, 9050, 8680, 8211, 6635, 3069, 10739, 6288, 6761, 7807, 16243, 20415, 23051, 19727, 8721, 6445, 8585, 13688, 14728, 17113, 16255, 3898, 4622, 3869, 3774, 4190, 3461, 4824, 4608, 4613, 3677, 3648, 3575, 3556, 4036, 3732, 2517, 4676, 4129, 3250, 4142, 3987, 4396, 3362, 2964, 1849, 2609, 2851, 3003, 3583, 3473, 3190, 2658, 4363, 3959, 4588, 3771, 4315, 3178, 3354, 3159, 2695, 4114, 4292, 3322, 1218, 3526, 3717]
];
var colors = ['#0065A3', '#767670', '#D73648', '#7FB2CE', '#00345B'];
var padding = 5;
//prepare chart data
var columnData = [];
var chartDataColumns = [];
var chartData = [];
chartData.push([columns[0]].concat(data[0]));
chartDataColumns = [
['x'].concat(labels)
].concat(chartData);
var chart1 = c3.generate({
bindto: d3.select('#chart1'),
data: {
x: 'x',
columns: [['x'].concat(labels)].concat(chartData),
type: 'line',
onmouseover: function(d) {
chart1.focus(d.id);
chart2.focus(d.id);
},
onmouseout: function() {
chart1.revert();
chart2.revert();
}
},
legend: {
position: 'right',
show: true,
item: {
onclick: function(id) {
if (chart1) chart1.toggle(id);
if (chart2) chart2.toogle(id);
},
onmouseover: function(id) {
if (chart1) chart1.focus(id);
if (chart2) chart2.focus(id);
},
onmouseout: function(id) {
if (chart1) chart1.revert();
if (chart2) chart2.revert();
}
}
},
tooltip: {
show: true,
format: {
value: function(value) {
return d3.format(",.0f")(value);
}
}
},
zoom: {
enabled: true
},
axis: {
x: {
type: 'timeseries',
tick: {
rotate: 90,
format: '%Y-%m-%d'
}
},
y: {
label: 'sample-data',
tick: {
format: d3.format(",")
}
}
},
color: {
pattern: colors
}
});
var chart2 = c3.generate({
bindto: d3.select('#chart2'),
data: {
columns: [[columns[0]].concat(data[0])],
type: 'pie',
onmouseover: function(id) {
if (chart1) chart1.focus(id);
if (chart2) chart2.focus(id);
},
onmouseout: function(id) {
if (chart1) chart1.revert();
if (chart2) chart2.revert();
}
},
legend: {
position: 'right',
show: true,
item: {
onclick: function(id) {
if (chart1) chart1.toggle(id);
if (chart2) chart2.toogle(id);
},
onmouseover: function(id) {
if (chart1) chart1.focus(id);
if (chart2) chart2.focus(id);
},
onmouseout: function(id) {
if (chart1) chart1.revert();
if (chart2) chart2.revert();
}
}
},
color: {
pattern: colors
},
});
for (var i = 1; i < columns.length; i++) {
setTimeout(function(column) {
chart1.load({
columns: [
[columns[column]].concat(data[column])
]
});
chart2.load({
columns: [[columns[column]].concat(data[column])]
});
}, (i * 5000 / columns.length), i);
}
document.getElementById("exportButton").onclick = function() {
exportChartToImage();
};
function exportChartToImage() {
var createImagePromise = new Promise(function(resolve, reject) {
var images = [];
d3.selectAll('svg').each(function() {
if (this.parentNode) {
images.push(getSvgImage(this.parentNode, true));
}
});
if (images.length > 0)
resolve(images);
else
reject(images);
});
createImagePromise.then(function(images) {
images.forEach(function(img, n) {
img.toBlob(function(blob) {
saveAs(blob, "image_" + (n + 1) + ".png");
});
});
})
.catch(function(error) {
throw error;
});
};
/**
* Converts a SVG-Chart to a canvas and returns it.
*/
function getSvgImage(svgContainer, png) {
var svgEl = d3.select(svgContainer).select('svg').node();
var svgCopyEl = svgEl.cloneNode(true);
if (!svgCopyEl)
return;
//remove elements not for printing
lensObject = d3.selectAll(".hidden-print").remove().exit();
//add temp document objects
var emptySvgEl = d3.select(document.createElementNS("http://www.w3.org/2000/svg", "svg")).attr("id", "emptysvg")
.attr("version", 1.1)
.attr("height", 2)
.node();
var canvasComputed = d3.select(document.createElement("canvas")).attr("id", "canvasComputed").node();
var container = d3.select(document.createElement("div")).attr("style", "display: none;")
.attr("class", "c3").node();
svgContainer.append(container);
container.append(svgCopyEl);
container.append(emptySvgEl);
container.append(canvasComputed);
//apply all CSS styles to SVG
exportStyles(svgCopyEl, emptySvgEl);
// transform SVG to canvas using external canvg
canvg(canvasComputed, new XMLSerializer().serializeToString(svgCopyEl));
//remove temp document objects
canvasComputed.remove();
emptySvgEl.remove();
svgCopyEl.remove();
container.remove();
return canvasComputed;
}
function exportStyles(svg, emptySvg) {
var tree = [];
var emptySvgDeclarationComputed = getComputedStyle(emptySvg);
//d3.select(svg).selectAll().each(function() {
$(svg).find("*").each(function() {
explicitlySetStyle(this, emptySvgDeclarationComputed);
});
}
function traverse(obj, tree) {
tree.push(obj);
if (obj.hasChildNodes()) {
var child = obj.firstChild;
while (child) {
if (child.nodeType === 1 && child.nodeName != 'SCRIPT') {
traverse(child, tree);
}
child = child.nextSibling;
}
}
return tree;
}
function explicitlySetStyle(element, emptySvgDeclarationComputed) {
var cSSStyleDeclarationComputed = getComputedStyle(element);
var i, len, key, value;
var computedStyleStr = "";
for (i = 0, len = cSSStyleDeclarationComputed.length; i < len; i++) {
key = cSSStyleDeclarationComputed[i];
value = cSSStyleDeclarationComputed.getPropertyValue(key);
if (value !== emptySvgDeclarationComputed.getPropertyValue(key)) {
if (key == 'visibility' && value == 'hidden') {
computedStyleStr += 'display: none;';
} else {
computedStyleStr += key + ":" + value + ";";
}
}
}
element.setAttribute('style', computedStyleStr);
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.6.12/c3.min.css" rel="stylesheet" />
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.6.12/c3.min.js"></script>
<!-- Required to convert named colors to RGB -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/canvg/1.4/rgbcolor.min.js"></script>
<!-- Optional if you want blur -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/stackblur-canvas/1.4.1/stackblur.min.js"></script>
<!-- Main canvg code -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/canvg/1.5/canvg.js"></script>
<script src="https://fastcdn.org/FileSaver.js/1.1.20151003/FileSaver.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="chart1" class "c3">
</div>
<div id="chart2" class="c3">
</div>
<button type="button" id="exportButton">
export to SVG
</button>
=> http://jsfiddle.net/gothmogg/jLt3yq75/
This sample shows exemplary how we apply the CSS styles to the SVG. If we use normal canvg without getComputedStyle the x and y axes of the c3 chart look like a total mess...
Do you know faster way to get valid images?
Is there a way to filter the CSS-styles? Maybe use "c3" styles only?
I have managed to solve the performance problems of exporting C3 SVG charts to PNG by avoiding to use getComputedStyle.
Browsing the issues in C3 I found issue #313
https://github.com/c3js/c3/issues/313
For others http://www.nihilogic.dk/labs/canvas2image/ might also be a good place to look at but I found a solution at https://gist.github.com/aendrew/1ad2eed6afa29e30d52e#file-exportchart-js-L29.
I have changed the code from using angular to d3 and now it works (for me).
Hopefully this might help others having the same issue.
Here the working code. Please note: the css styles are only examined and inlined once.
var labels = ['2018-10-01', '2018-10-02', '2018-10-03', '2018-10-04', '2018-10-05', '2018-10-06', '2018-10-07', '2018-10-08', '2018-10-09', '2018-10-10', '2018-10-11', '2018-10-12', '2018-10-13', '2018-10-14', '2018-10-15', '2018-10-16', '2018-10-17', '2018-10-18', '2018-10-19', '2018-10-20', '2018-10-21', '2018-10-22', '2018-10-23', '2018-10-24', '2018-10-25', '2018-10-26', '2018-10-27', '2018-10-28', '2018-10-29', '2018-10-30', '2018-10-31', '2018-11-01', '2018-11-02', '2018-11-03', '2018-11-04', '2018-11-05', '2018-11-06', '2018-11-07', '2018-11-08', '2018-11-09', '2018-11-10', '2018-11-11', '2018-11-12', '2018-11-13', '2018-11-14', '2018-11-15', '2018-11-16', '2018-11-17', '2018-11-18', '2018-11-19', '2018-11-20', '2018-11-21', '2018-11-22', '2018-11-23', '2018-11-24', '2018-11-25', '2018-11-26', '2018-11-27', '2018-11-28', '2018-11-29', '2018-11-30', '2018-12-01', '2018-12-02', '2018-12-03', '2018-12-04', '2018-12-05', '2018-12-06', '2018-12-07', '2018-12-08', '2018-12-09', '2018-12-10', '2018-12-11', '2018-12-12', '2018-12-13', '2018-12-14', '2018-12-15', '2018-12-16', '2018-12-17', '2018-12-18', '2018-12-19', '2018-12-20', '2018-12-21', '2018-12-22', '2018-12-23', '2018-12-24', '2018-12-25', '2018-12-26', '2018-12-27', '2018-12-28', '2018-12-29', '2018-12-30', '2018-12-31', '2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04', '2019-01-05', '2019-01-06', '2019-01-07', '2019-01-08', '2019-01-09', '2019-01-10', '2019-01-11', '2019-01-12', '2019-01-13', '2019-01-14', '2019-01-15', '2019-01-16', '2019-01-17', '2019-01-18', '2019-01-19', '2019-01-20', '2019-01-21', '2019-01-22', '2019-01-23', '2019-01-24', '2019-01-25', '2019-01-26', '2019-01-27', '2019-01-28', '2019-01-29', '2019-01-30', '2019-01-31', '2019-02-01', '2019-02-02', '2019-02-03', '2019-02-04', '2019-02-05', '2019-02-06', '2019-02-07', '2019-02-08', '2019-02-09', '2019-02-10', '2019-02-11', '2019-02-12', '2019-02-13', '2019-02-14', '2019-02-15', '2019-02-16', '2019-02-17', '2019-02-18', '2019-02-19', '2019-02-20', '2019-02-21', '2019-02-22', '2019-02-23', '2019-02-24', '2019-02-25', '2019-02-26', '2019-02-27', '2019-02-28'];
var columns = ['data101', 'data2', 'data347'];
var data = [
[0, 0, 2, 2, 1, 2, 7, 3, 1, 7, 5, 5, 5, 5, 6, 6, 11, 7, 2, 7, 16, 7, 3, 5, 10, 9, 11, 7, 3, 7, 7, 10, 10, 9, 18, 10, 20, 13, 9, 19, 16, 13, 20, 18, 14, 15, 18, 20, 19, 11, 13, 13, 12, 16, 11, 12, 21, 20, 23, 19, 19, 23, 23, 24, 23, 25, 21, 23, 20, 22, 21, 23, 24, 25, 27, 29, 28, 25, 24, 17, 20, 24, 22, 27, 21, 27, 19, 26, 31, 27, 28, 27, 21, 20, 27, 22, 22, 19, 17, 21, 23, 19, 22, 20, 21, 25, 15, 19, 20, 19, 21, 28, 17, 20, 14, 18, 17, 20, 27, 21, 18, 18, 20, 16, 27, 16, 16, 9, 18, 8, 19, 13, 8, 16, 15, 16, 9, 15, 10, 13, 10, 11, 10, 13, 12, 7, 14, 16, 13, 14, 8],
[0, 0, 338, 1201, 1268, 1371, 1286, 1148, 446, 288, 228, 253, 193, 201, 283, 393, 436, 379, 421, 444, 444, 417, 513, 353, 364, 399, 238, 191, 305, 337, 365, 349, 365, 244, 101, 39, 55, 72, 151, 98, 31, 127, 114, 92, 104, 196, 307, 245, 84, 168, 41, 38, 292, 488, 536, 569, 495, 448, 408, 358, 344, 380, 328, 334, 332, 330, 345, 312, 369, 377, 356, 301, 226, 273, 237, 116, 178, 133, 114, 138, 95, 143, 74, 74, 83, 47, 75, 101, 96, 59, 46, 128, 70, 57, 93, 80, 94, 93, 63, 86, 81, 63, 70, 102, 91, 67, 69, 68, 88, 76, 79, 70, 119, 88, 74, 94, 76, 54, 82, 90, 75, 130, 67, 78, 106, 91, 81, 27, 77, 21, 104, 83, 55, 60, 62, 304, 393, 191, 292, 77, 76, 55, 125, 89, 99, 127, 60, 75, 99, 120, 56],
[0, 0, 0, 1419, 7454, 12638, 10944, 7652, 4272, 11219, 9071, 7207, 7929, 8373, 9566, 6310, 7406, 9286, 8415, 7659, 6457, 3380, 10902, 10952, 10508, 7219, 4625, 4484, 4396, 5178, 5991, 7927, 14132, 14307, 5094, 10011, 6257, 9184, 18574, 12597, 11415, 7118, 9991, 10225, 14337, 4417, 12701, 17833, 23553, 10037, 4833, 5894, 19421, 14735, 12597, 8730, 5888, 11836, 13143, 17219, 10492, 10528, 8649, 11868, 10502, 6758, 7672, 8479, 11142, 22330, 26595, 4423, 17434, 8709, 9657, 7823, 9135, 19765, 18016, 16010, 8419, 7300, 8877, 9611, 9050, 8680, 8211, 6635, 3069, 10739, 6288, 6761, 7807, 16243, 20415, 23051, 19727, 8721, 6445, 8585, 13688, 14728, 17113, 16255, 3898, 4622, 3869, 3774, 4190, 3461, 4824, 4608, 4613, 3677, 3648, 3575, 3556, 4036, 3732, 2517, 4676, 4129, 3250, 4142, 3987, 4396, 3362, 2964, 1849, 2609, 2851, 3003, 3583, 3473, 3190, 2658, 4363, 3959, 4588, 3771, 4315, 3178, 3354, 3159, 2695, 4114, 4292, 3322, 1218, 3526, 3717]
];
var colors = ['#0065A3', '#767670', '#D73648', '#7FB2CE', '#00345B'];
var padding = 5;
//prepare chart data
var columnData = [];
var chartDataColumns = [];
var chartData = [];
var C3Styles = null;
chartData.push([columns[0]].concat(data[0]));
chartDataColumns = [
['x'].concat(labels)
].concat(chartData);
var chart1 = c3.generate({
bindto: d3.select('#chart1'),
data: {
x: 'x',
columns: [
['x'].concat(labels)
].concat(chartData),
type: 'line',
onmouseover: function(d) {
chart1.focus(d.id);
chart2.focus(d.id);
},
onmouseout: function() {
chart1.revert();
chart2.revert();
}
},
legend: {
position: 'right',
show: true,
item: {
onclick: function(id) {
if (chart1) chart1.toggle(id);
if (chart2) chart2.toogle(id);
},
onmouseover: function(id) {
if (chart1) chart1.focus(id);
if (chart2) chart2.focus(id);
},
onmouseout: function(id) {
if (chart1) chart1.revert();
if (chart2) chart2.revert();
}
}
},
tooltip: {
show: true,
format: {
value: function(value) {
return d3.format(",.0f")(value);
}
}
},
zoom: {
enabled: true
},
axis: {
x: {
type: 'timeseries',
tick: {
rotate: 90,
format: '%Y-%m-%d'
}
},
y: {
label: 'sample-data',
tick: {
format: d3.format(",")
}
}
},
color: {
pattern: colors
}
});
var chart2 = c3.generate({
bindto: d3.select('#chart2'),
data: {
columns: [
[columns[0]].concat(data[0])
],
type: 'pie',
onmouseover: function(id) {
if (chart1) chart1.focus(id);
if (chart2) chart2.focus(id);
},
onmouseout: function(id) {
if (chart1) chart1.revert();
if (chart2) chart2.revert();
}
},
legend: {
position: 'right',
show: true,
item: {
onclick: function(id) {
if (chart1) chart1.toggle(id);
if (chart2) chart2.toogle(id);
},
onmouseover: function(id) {
if (chart1) chart1.focus(id);
if (chart2) chart2.focus(id);
},
onmouseout: function(id) {
if (chart1) chart1.revert();
if (chart2) chart2.revert();
}
}
},
color: {
pattern: colors
},
});
for (var i = 1; i < columns.length; i++) {
setTimeout(function(column) {
chart1.load({
columns: [
[columns[column]].concat(data[column])
]
});
chart2.load({
columns: [
[columns[column]].concat(data[column])
]
});
}, (i * 5000 / columns.length), i);
}
document.getElementById("exportButton").onclick = function() {
exportChartToImage();
};
function exportChartToImage() {
var createImagePromise = new Promise(function(resolve, reject) {
var images = [];
d3.selectAll('svg').each(function() {
if (this.parentNode) {
images.push(getSvgImage(this.parentNode, true));
}
});
if (images.length > 0)
resolve(images);
else
reject(images);
});
createImagePromise.then(function(images) {
images.forEach(function(img, n) {
img.toBlob(function(blob) {
saveAs(blob, "image_" + (n + 1) + ".png");
});
});
})
.catch(function(error) {
throw error;
});
};
/**
* Converts a SVG-Chart to a canvas and returns it.
*/
function getSvgImage(svgContainer, png) {
var svgEl = d3.select(svgContainer).select('svg').node();
var svgCopyEl = svgEl.cloneNode(true);
if (!svgCopyEl)
return;
//remove elements not for printing
lensObject = d3.selectAll(".hidden-print").remove().exit();
//add temp document objects
var canvasComputed = d3.select(document.createElement("canvas")).attr("id", "canvasComputed").node();
var container = d3.select(document.createElement("div")).attr("style", "display: none;")
.attr("class", "c3").node();
svgContainer.append(container);
container.append(svgCopyEl);
container.append(canvasComputed);
/* taken from https://gist.github.com/aendrew/1ad2eed6afa29e30d52e#file-exportchart-js
and changed from, angular to D3 functions
*/
/* Take styles from CSS and put as inline SVG attributes so that Canvg
can properly parse them. */
var chartStyle;
if (!C3Styles) {
// Get rules from c3.css
var styleSheets = document.styleSheets;
for (var i = 0; i <= styleSheets.length - 1; i++) {
if (styleSheets[i].href && (styleSheets[i].href.indexOf('c3.min.css') !== -1 || styleSheets[i].href.indexOf('c3.css') !== -1)) {
try {
if (styleSheets[i].rules !== undefined) {
chartStyle = styleSheets[i].rules;
} else {
chartStyle = styleSheets[i].cssRules;
}
break;
}
//Note that SecurityError exception is specific to Firefox.
catch (e) {
if (e.name == 'SecurityError') {
console.log("SecurityError. Cant read: " + styleSheets[i].href);
continue;
}
}
}
if (chartStyle !== null && chartStyle !== undefined) {
C3Styles = {};
var selector;
// Inline apply all the CSS rules as inline
for (i = 0; i < chartStyle.length; i++) {
if (chartStyle[i].type === 1) {
selector = chartStyle[i].selectorText;
var styleDec = chartStyle[i].style;
for (var s = 0; s < styleDec.length; s++) {
C3Styles[styleDec[s]] = styleDec[styleDec[s]];
}
}
}
}
}
}
if (C3Styles)
d3.select(svgCopyEl).selectAll('.c3:not(.c3-chart):not(path)').style(C3Styles);
// SVG doesn't use CSS visibility and opacity is an attribute, not a style property. Change hidden stuff to "display: none"
d3.select(svgCopyEl).selectAll('*')
.filter(function(d) {
return d && d.style && (d.style('visibility') === 'hidden' || d.style('opacity') === '0');
})
.style('display', 'none');
//fix weird back fill
d3.select(svgCopyEl).selectAll("path").attr("fill", "none");
//fix no axes
d3.select(svgCopyEl).selectAll("path.domain").attr("stroke", "black");
//fix no tick
d3.select(svgCopyEl).selectAll(".tick line").attr("stroke", "black");
// transform SVG to canvas using external canvg
canvg(canvasComputed, new XMLSerializer().serializeToString(svgCopyEl));
//remove temp document objects
canvasComputed.remove();
svgCopyEl.remove();
container.remove();
return canvasComputed;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.6.12/c3.min.css" rel="stylesheet" />
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.6.12/c3.min.js"></script>
<!-- Required to convert named colors to RGB -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/canvg/1.4/rgbcolor.min.js"></script>
<!-- Optional if you want blur -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/stackblur-canvas/1.4.1/stackblur.min.js"></script>
<!-- Main canvg code -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/canvg/1.5/canvg.js"></script>
<script src="https://fastcdn.org/FileSaver.js/1.1.20151003/FileSaver.min.js"></script>
<div id="chart1" class "c3">
</div>
<div id="chart2" class="c3">
</div>
<button type="button" id="exportButton">
export to SVG
</button>
Unfortunately
document.styleSheets[i].rules
can't be accessed in the script here. It worked in my environment though.
Any idea why this does not work here?

Javascript: Spliting an array into sections

I have an array that can be of any length. and need to split it into sections. The first section will be a length of 14, and there after a length of 16
var size1 = 14;
var size2 = 16;
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40];
var arrays = [];
if (a.length > 14){
for (i = 0; i < 14; i++) {
arrays.push(a.splice(0, size1));
}
for (i = 14 ; i < a.length; i++){
arrays.push(a.splice(0, size2));
}
} else {
arrays.push(a.splice(0, size1));
}
console.log(arrays);
However based on what I am doing my array keeps splitting only at 14. Can you advice on how I can do this?
Thank you
The solution using Array.prototype.slice() function:
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
size1 = 14,
size2 = 16,
arrays = [];
[0, size1, size2].forEach(function (v, i, arr) {
arrays.push((arr[i+1])? a.slice(v, v + arr[i+1]) : a.slice(arr[i-1] + v));
});
console.log(arrays);
You could use an array for the chunk length and a zero for the rest and map the chunks by keeping the length of the previous lengths.
It works for an arbitrary count of chunks.
var chunks = [14, 16, 0],
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
result = chunks.map((last => a => array.slice(last, a ? (last += a) : undefined))(0));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Edit: so, like this then?
var size1 = 14;
var size2 = 16;
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40];
var head = a.slice(0, size1);
var arrays = [head];
while (size1 < a.length){
arrays.push(a.slice(size1, Math.min(size1+size2, a.length)));
size1 += size2;
}
console.log(arrays)
You can try this with all dynamic array sizes, it will get you desired output.
Hope you were looking for this solution.
var size1 = 14;
var size2 = 16;
var flag=0;
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40];
var arrays = [];
var t=a.length/14;
while(a.length>0){
if (flag==0 && a.length > 14){
arrays.push(a.splice(0, size1));
flag=1;
} else if(a.length>=16){
arrays.push(a.splice(0, size2));
}
else{
arrays.push(a.splice(0, a.length));
}
}
console.log(arrays)

Calculate quintiles/deciles from an array of numbers

Given the following array:
[13, 468, 3, 6, 220, 762, 97, 16, 522, 69, 119, 2895, 1255, 49, 19, 261, 9, 140, 55, 20, 6, 22, 6, 17, 115]
I need to calculate the value that is at the 20th, 40th, 60th, and 80th percentile. The steps would be to order the array from low to high, count the total number of values, determine what value is at the 20th percentile, etc. (for example, if there are 10 numbers in order from low to high, the 2nd value would be the 20th percentile).
This is stored in a variable and I know I can sort the numbers like this:
ticks6.sort();
and get the number of values in the array with this:
var newticks=ticks6.length;
I have no idea how to do the next part though where I figure out the percentiles, but looking for a solution in jquery or javascript.
Use like this:
var arr = [13, 468, 3, 6, 220, 762, 97, 16, 522, 69, 119, 2895, 1255, 49, 19, 261, 9, 140, 55, 20, 6, 22, 6, 17, 115];
arr.sort();
var len = arr.length;
var per20 = Math.floor(len*.2) - 1;
console.log(arr[per20]);
//similarly
var per40 = Math.floor(len*.4) - 1;
console.log(arr[per40]);
The Simple Statistics library has a quantile function you can use for this:
ss.quantile([13, 468, 3, 6, 220, 762, 97, 16, 522, 69, 119, 2895, 1255, 49, 19, 261, 9, 140, 55, 20, 6, 22, 6, 17, 115], 0.2)
=> 13
You can easely sort your array :
console.log([13, 468, 3, 6, 220, 762, 97, 16, 522, 69, 119, 2895, 1255, 49, 19, 261, 9, 140, 55, 20, 6, 22, 6, 17, 115].sort(function(a,b){return a-b}))
Get the length of the array : myArray.length.
And the 20th percile parseInt(myArray.length * 0.2) => 2
Something like this:
tricks6.sort();
var length = tricks6.length;
var twentieth = sorted[math.floor((length-1)*.2)] //do for all

Categories