How to print array value to variable? - javascript

Here, i have used chartist js for area chart. Each currency having the different value. I have stored each currency value in each variable. After ajax call i added value like that var arrVal = $('#changeCurrency a').attr('id',' ');. But its not pointing currectly. When i given like that var arrVal = dataCur11 means it coming fine. What is the solution for this problem?
HTML
<div id="changeCurrency">
UAE
USD
SGD
INR
POUND
</div>
<div id="graphContainer"></div>
JS
$(document).on('click', '#changeCurrency a', function(){
$.ajax({
url: 'partials/graph.html',
method: 'GET',
success: function (data, supportsForeignObject) {
$('#graphContainer').html('');
$('#graphContainer').append(data);
$('#chart-loader').fadeOut();
var dataCur11 = [50, 53, 54, 52, 56, 55, 53, 50],
dataCur21 = [20, 53, 34, 42, 26, 55, 53, 50],
dataCur31 = [40, 53, 24, 32, 56, 35, 53, 56],
dataCur41 = [50, 33, 54, 30, 22, 20, 30, 52],
dataCur51 = [20, 33, 54, 30, 22, 20, 30, 52];
var arrVal = $('#changeCurrency a').attr('id','');
// Support
var supportsForeignObject = document.implementation.hasFeature("www.http://w3.org/TR/SVG11/feature#Extensibility","1.1");
if(supportsForeignObject) {
var labelsVal = [22+" <span>Dec'14</span>", 24+" <span>Dec'14</span>", 26+" <span>Dec'14</span>", 28+" <span>Dec'14</span>", 30+" <span>Dec'14</span>", 1+" <span>Jan'15</span>", 3+" <span>Jan'15</span>", 5+" <span>Jan'15</span>"]
} else {
var labelsVal = [22+" Dec'14", 24+" Dec'14", 26+" Dec'14", 28+" Dec'14", 30+" Dec'14", 1+" Jan'15", 3+" Jan'15", 5+" Jan'15"];
}
setTimeout(function(){
$('.val-pos').addClass('current-pos');
new Chartist.Line('.ct-chart', {
labels: labelsVal,
series:[arrVal]
}, {
axisY: {
offset: 35,
scaleMinSpace: 60
},
low: 0,
showArea: true
});
}, 1000);
}
});
});

please check the below code ,hope this will help you
$(document).on('click', '#changeCurrency a', function () {
var dataCur11 = [50, 53, 54, 52, 56, 55, 53, 50],
dataCur21 = [20, 53, 34, 42, 26, 55, 53, 50],
dataCur31 = [40, 53, 24, 32, 56, 35, 53, 56],
dataCur41 = [50, 33, 54, 30, 22, 20, 30, 52],
dataCur51 = [20, 33, 54, 30, 22, 20, 30, 52];
var arrVal = eval($(this).attr('id'));
console.log(arrVal);
});
fiddle :http://jsfiddle.net/cdq95qLt/
so your code will be like this
$(document).on('click', '#changeCurrency a', function(){
$.ajax({
url: 'partials/graph.html',
method: 'GET',
success: function (data, supportsForeignObject) {
$('#graphContainer').html('');
$('#graphContainer').append(data);
$('#chart-loader').fadeOut();
var dataCur11 = [50, 53, 54, 52, 56, 55, 53, 50],
dataCur21 = [20, 53, 34, 42, 26, 55, 53, 50],
dataCur31 = [40, 53, 24, 32, 56, 35, 53, 56],
dataCur41 = [50, 33, 54, 30, 22, 20, 30, 52],
dataCur51 = [20, 33, 54, 30, 22, 20, 30, 52];
var arrVal = eval($(this).attr('id'));
// Support
var supportsForeignObject = document.implementation.hasFeature("www.http://w3.org/TR/SVG11/feature#Extensibility","1.1");
if(supportsForeignObject) {
var labelsVal = [22+" <span>Dec'14</span>", 24+" <span>Dec'14</span>", 26+" <span>Dec'14</span>", 28+" <span>Dec'14</span>", 30+" <span>Dec'14</span>", 1+" <span>Jan'15</span>", 3+" <span>Jan'15</span>", 5+" <span>Jan'15</span>"]
} else {
var labelsVal = [22+" Dec'14", 24+" Dec'14", 26+" Dec'14", 28+" Dec'14", 30+" Dec'14", 1+" Jan'15", 3+" Jan'15", 5+" Jan'15"];
}
setTimeout(function(){
$('.val-pos').addClass('current-pos');
new Chartist.Line('.ct-chart', {
labels: labelsVal,
series:arrVal
}, {
axisY: {
offset: 35,
scaleMinSpace: 60
},
low: 0,
showArea: true
});
}, 1000);
}
});
});

Related

How to make dynamic variable to check array with .every

For a project we need to check if all numbers in a card, match another card with drawn numbers.
When hardcoded with a const checkCard = card001 it goes well with .every.
When trying to choose the card a dynamic way, pulling the number from a localStorage (e.g. const card = 'card'+cardNumber), an error pops up with t.every is not a function.
The question: how to make this dynamic. We hope someone is able to help to overcome this issue.
checkCard = () => {
var cardNumber = localStorage.cardNumber;
const card001 = [14, 4, 10, 8, 12, 30, 28, 23, 16, 27, 41, 35, 43, 39, 53, 57, 46, 48, 56, 74, 68, 75, 70, 66]
const card002 = [15, 13, 8, 1, 12, 26, 20, 19, 28, 24, 38, 42, 33, 41, 59, 53, 60, 55, 51, 68, 62, 71, 70, 65]
const card003 = [11, 5, 4, 13, 9, 23, 27, 16, 18, 26, 44, 38, 40, 36, 53, 47, 56, 55, 50, 69, 65, 63, 61, 74]
const previousCallList = JSON.parse(JSON.stringify(this.previousCallList));
console.log('previousCallList: ', previousCallList)
const previousCallListNumber = JSON.parse(JSON.stringify(this.previousCallListNumber));
console.log('previousCallListNumber: ', previousCallListNumber)
//const card = 'card'+cardNumber;
const checkCard = card001
const checkDrawn = previousCallListNumber ;
const containsAll = checkCard .every(element => {
return checkDrawn.includes(element);
});
console.log(containsAll); // 👉️ true
}
}
There's a difference between these two lines:
// Point `checkCard` to the current array stored in `card001`
const checkCard = card001
// Point `checkCard` to a string "card001"
const checkCard = "card001"
When you write 'card'+cardNumber, you're creating a new string, not a reference to another variable.
If you want to dynamically pick a variable based on its name, you can define named properties on an object. For example:
const myObject = {
a: 1,
b: 2,
c: 3
};
console.log(
myObject["a"],
myObject["b"],
myObject["c"]
)
Or, with your data:
const cardNumber = "001";
const card001 = [14, 4, 10, 8, 12, 30, 28, 23, 16, 27, 41, 35, 43, 39, 53, 57, 46, 48, 56, 74, 68, 75, 70, 66]
const card002 = [15, 13, 8, 1, 12, 26, 20, 19, 28, 24, 38, 42, 33, 41, 59, 53, 60, 55, 51, 68, 62, 71, 70, 65]
const card003 = [11, 5, 4, 13, 9, 23, 27, 16, 18, 26, 44, 38, 40, 36, 53, 47, 56, 55, 50, 69, 65, 63, 61, 74]
const cardVarName = "card" + cardNumber;
log(cardVarName); // This is now the string "card001", not a reference to the card001 variable
// Store the cards in an object
const cards = { card001, card002, card003 };
// Reference a card using obj[propertyName]
log(cards[cardVarName])
function log(x) { console.log(JSON.stringify(x)); }
If you intend to use localStorage you need to familiarize yourself with the syntax, what you have now...
localStorage.cardNumber;
...should've given you an error. The following are two functions that get and set data to and from localStorage:
/*
>key< is a string assigned as an id to stored data.
If there isn't anything stored an empty array is returned/
*/
const getLS = key => JSON.parse(localStorage.getItem(key)) || [];
/*
>key< is same as above. >data< is the value that needs to
be stored.
*/
const setLS = (key, data) => localStorage.setItem(key, JSON.stringify(data));
Note that LS only stores strings which is why JSON.parse() and JSON.stringify() are used on the data. In the example the
lines concerning LS are commented out because SO snippets prohibit them -- just uncomment them when you test them in a normal environment.
Details are commented in example below
// Utility function
const log = data => console.log(JSON.stringify(data));
//const getLS = key => JSON.parse(localStorage.getItem(key)) || [];
//const setLS = (key, data) => localStorage.setItem(key, JSON.stringify(data));
/*
All arrays as parameters so function can be reusable
*/
const deckA = [14, 4, 10, 8, 12, 30, 28, 23, 16, 27, 41, 35, 43, 39, 53, 57, 46, 48, 56, 74, 68, 75, 70, 66];
const deckB = [15, 13, 8, 1, 12, 26, 20, 19, 28, 24, 38, 42, 33, 41, 59, 53, 60, 55, 51, 68, 62, 71, 70, 65];
const deckC = [11, 5, 4, 13, 9, 23, 27, 16, 18, 26, 44, 38, 40, 36, 53, 47, 56, 55, 50, 69, 65, 63, 61, 74];
/**
* find match between a given number and a
* number from one or more given arrays
* #param {number} card = Number to find
* #param {arrays} cards = One or more arrays
* #returns {array<object>} Each object is
* created like this:
* {card: 55, row: 2, col: 17}
* "card 55 is in the 3rd array index 17"
*/
const findMatch = (card, ...cards) => {
//const data = getLS('cards');
//data.push(card);
//setLS('cards', data);
// Gather ...cards into an array:
// [ [deckA], [deckB], [deckC] ]
const decks = [...cards];
/*
First, .map() runs through each sub-array and
.flatMap() compares each number of each sub-
array vs. card. If there's a match, return
a new object (see above) otherwise an empty
array is returned
*/
return decks.map((sub, row) => sub.flatMap((num, col) => num === card ? {card: card, row: row, col: col} : [])).flat();
};
log(findMatch(55, deckA, deckB, deckC));
log(findMatch(3, deckA, deckB, deckC));
log(findMatch(25, deckA, deckB, deckC));
log(findMatch(13, deckA, deckB, deckC));

Print all even values in all object key end with odd value

I want to print all even values in all object key end with odd value but the coding I made just now is only specified for arr1, arr3, and arr5. Can anyone suggest me how to fix 'let oddArr' method (maybe in loop) so that when I changed arr1 into arr7, the result would be the same.
var num = {
arr1 : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
arr2 : [11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
arr3 : [21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
arr4 : [31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
arr5 : [41, 42, 43, 44, 45, 46, 47, 48, 49, 50],
};
let oddArr = [...num.arr1, ...num.arr3, ...num.arr5] //need some correction here
let evenNum = oddArr.filter(number => number % 2 == 0);
console.log(evenNum.toString());
//help me fix 'let oddArr' (maybe in loop method) so that when I changed the object of the array (e.g: arr1 -> arr7) it would come out with the same result
//the result/output should be 2,4,6,8,10,22,24,26,28,30,42,44,46,48,50 based on var num
You can try like below using for in loop and it works with any last character as odd.
var num = {
arr1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
arr2: [11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
arr3: [21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
arr4: [31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
arr7: [41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
};
let oddArr = [];
for (let key in num) {
if (key.charAt(key.length - 1) % 2 !== 0) {
oddArr = [...oddArr, ...num[key]];
}
}
let evenNum = oddArr.filter((number) => number % 2 === 0);
console.log(evenNum.toString());
You might want to use
let oddArr = Object.entries(num).filter( // filter key names
e => +e[0].replace("arr", '') % 2 !== 0 // replace "arr" and check if X in arrX is odd
).map(e => e[1]).flat() // merge values and flattern array
You can also make use of regex if the "arrX"-naming is not consistent:
+e[0].match(/\d+/) % 2 !== 0
See a working snippet below:
var num = {
arr1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
arr2: [11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
arr3: [21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
arr4: [31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
arr5: [41, 42, 43, 44, 45, 46, 47, 48, 49, 50],
};
let oddArr = Object.entries(num).filter(
e => +e[0].replace("arr", '') % 2 !== 0
).map(e => e[1]).flat()
let evenNum = oddArr.filter(number => number % 2 == 0);
console.log(evenNum.toString());
This also works.
var num = {
arr1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
arr2: [11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
arr3: [21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
arr4: [31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
arr5: [41, 42, 43, 44, 45, 46, 47, 48, 49, 50],
arr6: [51, 52, 53, 55, 55, 56, 57, 58, 59, 60],
arr7: [61, 62, 63, 66, 65, 66, 67, 68, 69, 70],
};
var evenNums = Object.keys(num).filter((item) => {
itemNum = item.replace("arr", "");
return itemNum % 2 !== 0;
}).map((o) => num[o]).flat().filter((x) => x % 2 == 0);
console.log(evenNums);

reduce the size of a javascript array while keeping members that are evenly distributed in the original

Hard to put into words but I am looking for a function that takes an array and reduces it down to a given size. The use case is specifying ticks for graph in d3.
const availableDatetimes: Date[] = [...]
const numberOfXTicks = chartWidth / 80
const tickValues = reduceArrSize(availableDatetimes, numberOfXTicks)
the result should have evenly distributed dates
I called it shrinkArray(), because reducing an array is the name of a different well-defined operation. Here it is:
const shrinkArray = (array, size) => {
const step = array.length / size
return array.filter((v, i) => Math.floor(i % step) == 0)
}
Let's shrink an array of size 100 to size 33:
const originalArray = (new Array(100).fill(0)).map((v, i) => i)
const shrunkenArray = shrinkArray(originalArray, 33)
console.log(shrunkenArray);
console.log(shrunkenArray.length == 33);
So:
[
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, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99
]
is shrunken to:
[
0, 4, 7, 10, 13, 16, 19, 22, 25,
28, 31, 34, 37, 40, 43, 46, 49, 53,
56, 59, 62, 65, 68, 71, 74, 77, 80,
83, 86, 89, 92, 95, 98
]
that is of size 33.
In this example the array is integers from 0 to 99, but obviously the function works for any data type.

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?

setInterval inside setTimeout not working... why?

I'm trying to make an element change opacity based on a series of values pre-set on an array. That action should begin after the user clicks a button AND the system waits for a second.
Here's what I got:
<script>
$(function() {
$("#Listening").click(function() {
setTimeout(triggerListening, 1000);
function triggerListening()
{
document.getElementById("listening").className = "listeningIn";
}
setTimeout(triggerUserTalking, 2000);
function triggerUserTalking()
{
var audioSim = [3, 2, 7, 15, 15, 16, 15, 7, 7, 3, 8, 8, 17, 17, 20, 20, 21, 21, 17, 17, 13, 13, 12, 12, 13, 13, 16, 16, 18, 18, 17, 17, 16, 16, 14, 10, 11, 11, 15, 15, 16, 16, 15, 15, 14, 14, 13, 13, 13, 13, 15, 15, 23, 44, 55, 55, 56, 55, 44, 44, 33, 29, 31, 31, 42, 50, 60, 63, 60, 54, 39, 39, 30, 28, 30, 30, 33, 33, 36, 39, 38, 38, 33, 16, 6, 6, 5, 7, 18, 18, 28, 31, 28, 28, 26, 26, 23, 22, 23, 23, 25, 28, 28, 28, 27, 27, 28, 28, 28, 28, 28, 28, 27, 27, 28, 28, 35, 35, 43, 43, 49, 54, 56, 55, 43, 36, 26, 28, 31, 52, 65, 70, 68, 68, 51, 45, 41, 41, 38, 40, 49, 49, 57, 58, 58, 31, 42, 42, 46, 51, 55, 55, 54, 42, 33, 31, 37, 37, 45, 46, 42, 42, 37, 38, 38, 41, 41, 44, 44, 46, 48, 47, 47, 43, 44, 44, 47, 47, 49, 49, 48, 45, 44, 44, 44, 44, 45, 45, 44, 44, 43, 39, 36, 34, 35, 59, 59, 85, 93, 98, 98, 100, 95, 67, 67, 43, 36, 34, 34, 39, 51, 62, 62, 68, 76, 75, 75, 50, 36, 27, 20, 18, 36, 57, 57, 52, 48, 43, 44, 49, 50, 50, 49];
var i = 0;
window.setInterval('step()', 20)
function step() {
var element = document.getElementById("listening");
element.style.opacity = "0." + audioSim[i];
i++;
if (i == audioSim.length) i = triggerStopTalking;
}
function triggerStopTalking()
{
document.getElementById("listening").className = "listeningOut";
}
}
});
});
</script>
This works fine expect the changing opacity part...
User clicks Listening and after 1 second the listening object appears on the screen by toggling the "listeningIn" class... after another second that element should change opacity a bunch of times based on the values inside "audioSim"... but it doesn't...
I've tested the setInterval code in a separate html file and it works fine... so I'm thinking I can't have a setInterval inside a setTimeout function? Help?
You're passing a string to setInverval.
Don't do that.
setInterval is evaling your string in the global scope; step() is a local variable. Therefore, it doesn't find anything.
Instead, you need to pass the function itself:
setInterval(step);
Instead of
window.setInterval('step()', 20);
try
window.setInterval(step, 20);
I believe the text version will be evaluated on the global scope where step may not exist.
In the line:
> window.setInterval('step()', 20)
setInterval is executed in a global context, but step is declared inside another context that window can't access. Change it to:
setInterval(step, 20)
so that you pass a reference to the function instead.

Categories