Javascript array/object/hash table to track cart availability - javascript

I don't know if this is possible but it seems there must be a simpler way to do this. I currently have a shopping cart for a t-shirt store. Each t-shirt has 3 drop down boxes to select prior to purchase:
Style:
American Apparel
Gildan
Size:
S
M
L
XL
Colour:
Blue
Black
White
Grey
Not every style is available in every size and colour combination but apart from how the cart is laid out on the page, there is no set way for the user to select style first, then size without forcing it which will be a barrier to making a sale.
Right now, when the user selects anything from any of the drop down boxes, an ajax call is made to the server to calculate what the other drop down boxes should contain, for example if the user selects Size (L) first, the colour may change to just Blue and Black as White and Grey are not available in Large, but worse than that White may be available but only in Gildan style.
Anyway, the ajax call has latency and can be especially slow on mobile devices with a spotty data connection. Is there a way I can achieve this with Javascript instead. I know all the combinations prior to rendering the page, and I can set up an array but get lost due to having more than two drop down boxes and end up with this ugly mess, and even then I don't know how to do the actual function which changes the boxes because multiple boxes may be selected:
<html>
<head>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
var styles = { aa: 'American Apparel', gi: 'Gildan' };
var sizes = { s: 'Small', m: 'Medium', l: 'Large' };
var colours = { blue: 'Blue', black: 'Black', white: 'White', grey: 'Grey' };
var availability = {
aa: { size: ['s', 'm', 'l'], colour: ['blue', 'black', 'white', 'grey'] },
gi: { size: ['s', 'm'], colour: ['blue', 'black', 'white', 'grey'] },
s: { style: ['aa', 'gi'], colour: ['blue', 'black', 'white'] },
m: { style: ['aa', 'gi'], colour: ['black', 'white', 'grey'] },
l: { style: ['aa'], colour: ['blue', 'black', 'white', 'grey'] },
blue: { style: ['aa', 'gi'], size: ['s', 'l'] },
black: { style: ['aa', 'gi'], size: ['s', 'm', 'l'] },
white: { style: ['aa', 'gi'], size: ['s', 'm', 'l'] },
grey: { style: ['aa', 'gi'], size: ['m', 'l'] }
};
$(function()
{
addOptions('style', styles);
addOptions('size', sizes);
addOptions('colour', colours);
});
function addOptions(name, data)
{
$('select[name="' + name + '"]').empty();
$.each(data, function(value, description)
{
$('select[name="' + name + '"]').append('<option value="' + value + '">' + description + '</option>');
});
}
function updateOptions(select)
{
// Work out what has changed, and update select boxes?
}
</script>
</head>
<body>
<select name="style" onchange="updateOptions(this);"></select>
<select name="size" onchange="updateOptions(this);"></select>
<select name="colour" onchange="updateOptions(this);"></select>
</body>
</html>
Is there a more efficient way to do this with a smarter function and/or hash table? These may not be the only three options, for example the store has pillows as well which have style, material, thread count and colour. Each set of options is unique to the product, but I know what they are prior to the page being rendered.
Thanks heaps.

The natural way to structure your data is with a multi-dimensional array (one dimension for each property) in which the values are true or false. I modeled it with that idea in mind, but with associative arrays (aka objects in JavaScript).
Data:
var availability = {
'American Apparel' : {
'S' : {
'black' : true,
'green' : true
},
'M' : {
'black' : true,
'white' : true
}
},
'Gildan' : {
'M' : {
'black' : true
},
'XL' : {
'black' : true,
'white' : true,
'green' : true
}
}
};
Now all you need is a function to return the possible options when some are selected. The first draft is below, but i'm sure it can be improved heavily. If a property is set, pass the value to the function, otherwise pass undefined. The function returns an object with 3 arrays indicating the valid options for the user's selection. Usage example at the end..
function pushIfNotIn(arr, item) {
if (arr.indexOf(item) === -1) arr.push(item);
}
function getAvailability(styleValue, sizeValue, colorValue) {
var av = {
style : [],
size : [],
color : []
};
for (var style in availability) {
if (styleValue === undefined || styleValue === style) {
for (var size in availability[style]) {
if (sizeValue === undefined || sizeValue === size) {
for (var color in availability[style][size]) {
if (colorValue === undefined || colorValue === color) {
if (availability[style][size][color]) {
pushIfNotIn(av.style, style);
pushIfNotIn(av.size, size);
pushIfNotIn(av.color, color);
}
}
}
}
}
}
}
return av;
}
console.log(getAvailability(undefined, 'M', undefined));
console.log(getAvailability('American Apparel', 'S', undefined));
console.log(getAvailability(undefined, 'M', 'black'));
console.log(getAvailability(undefined, 'M', 'green'));
console.log(getAvailability(undefined, undefined, 'green'));
DEMO: http://jsbin.com/uHAyirOX/1/edit
Obviously a more generic solution can be extrapolated from this method, with variable number of arguments and more levels in the availability object. Still, you have something to work it.
UPDATE: Generic solution (called in the same way)
function pushIfNotIn(arr, item) {
if (!arr) arr = [];
if (arr.indexOf(item) === -1) arr.push(item);
return arr;
}
function getAvailability() {
var result = [];
~function getAvailabilityRecursive (level, availability, values) {
if (!values.length) return true;
var isAvailable = false;
var val = values[0];
values = values.slice(1);
for (var key in availability) {
if ((val === undefined || val === key) &&
(getAvailabilityRecursive(level+1, availability[key], values))){
result[level] = pushIfNotIn(result[level], key);
isAvailable = true;
}
}
return isAvailable;
}(0, availability, Array.prototype.slice.call(arguments));
return result;
}
DEMO: http://jsbin.com/uHAyirOX/3/edit

Low-tech approach with the benefit of being immediately obvious for anyone maintaining it.
This could be an Ajax response, plain and simple:
var products = [
{ id: 101, style: 'aa', size: 's', colour: 'grey' },
{ id: 102, style: 'aa', size: 'm', colour: 'grey' },
{ id: 103, style: 'aa', size: 'l', colour: 'black' },
/* ... 500 more ... */
{ id: 604, style: 'gi', size: 'l', colour: 'blue' }
];
Now just filter that array brute-force on the client side:
function Drilldown(items, properties) {
var self = this,
numItems = items.length,
numProps = properties.length;
self.setFilter = function (filterDef) {
var i, item, p, prop, pass, filter = filterDef || {};
self.items = [];
self.properties = {};
for (i = 0; i < numItems; i++) {
item = items[i];
pass = true;
for (p = 0; pass && p < numProps; p++) {
prop = properties[p];
pass = pass && (!filter[prop] || filter[prop] === item[prop]);
if (!self.properties.hasOwnProperty(prop)) {
self.properties[prop] = {};
}
if (!self.properties[prop].hasOwnProperty(item[prop])) {
self.properties[prop][item[prop]] = [];
}
}
if (pass) {
self.items.push(item);
for (p = 0; p < numProps; p++) {
prop = properties[p];
self.properties[prop][item[prop]].push(item);
}
}
}
};
self.setFilter();
}
Usage:
var dd = new Drilldown(products, ['style', 'size', 'colour']);
dd.setFilter({size: 'l'});
/*
dd.items => [ array of size L products ]
dd.properties => {
style: {
aa: [ array of size L products in style 'aa' (1) ],
gi: [ array of size L products in style 'gi' (1) ]
},
size: {
s: [ array of size L products in size S (0) ],
m: [ array of size L products in size M (0) ],
l: [ array of size L products in size L (2) ]
},
colour: {
grey: [ array of size L products in Grey (0) ],
black: [ array of size L products in Black (1) ],
blue: [ array of size L products in Blue (1) ]
}
*/
dd.properties contains the all property combinations. Naturally some of the entries will be empty (array length 0), but all of them will be there. This makes indexing into this object straightforward.

I think I would have done something as:
var items = {
'item1':{
'level1' : {
'level2' : {},
'level2' : {'level3' :{}}
},
'level1' : {
'level2' : {},
'level2' : {'level3' :{}}
}
},
'item2':{
'level1' : {
'level2' : {},
'level2' : {'level3' :{}}
},
'level1' : {
'level2' : {},
'level2' : {'level3' :{}}
}
}
}
That a first selector(Style, for example) can dictates availabilities for next(Colour) and so on.
In any level user can change only levels below.

Related

How do I pick random data from an array and make sure that a minimum of a certain data are selected from that array without effecting probability?

I am selecting randomly 20 bikes from a larger array of bikes, and then creating a new array with those selected bikes. I would like to make sure that at least 2 of the randomly selected bikes in that new array are the color red. More than 2 can be red, but at a minimum 2 should be. How is this achieved while making it fair to all of the randomly selected bikes?
Some example code:
const bikes = [
{ type: 'bmx', color: 'red' },
{ type: 'mountain', color: 'blue' },
{ type: 'bmx', color: 'yellow' },
{ type: 'mountain', color: 'black' },
{ type: 'bmx', color: 'red' },
{ type: 'bmx', color: 'purple' }
...more bikes
]
const getRandomBikes = () => {
const randomBikes = []
//random select 20 bikes
for(let i = 0; i < 20; i++) {
randomBikes.push(bikes[Math.floor(Math.random() * bikes.length)])
}
return randomBikes
}
getRandomBikes()
So pretty simple to return a random array. But now how would I make sure that the random bike array contained at least two bikes with color: 'red' without effecting the probability of every bike being selected? Presumably I would be running getRandomBikes() until the returned array satisfied the requirements, but say my array of bikes is 10000 long, that may take forever before the requirement is met. How do I ensure at least two red bikes end up in the randomly selected bike array?
While iterating, you might count up the number of required bikes of a specific color remaining, and if equal to the number of items that remain to be chosen, pick only from the bikes with the right color.
const bikes = [
{ type: 'bmx', color: 'red' },
{ type: 'mountain', color: 'blue' },
{ type: 'bmx', color: 'yellow' },
{ type: 'mountain', color: 'black' },
{ type: 'bmx', color: 'red' },
{ type: 'bmx', color: 'purple' }
];
const getRandomBikes = (requiredRed, totalPicks) => {
const chosenBikes = [];
const reds = bikes.filter(({ color }) => color === 'red');
for(let i = 0; i < totalPicks; i++) {
const redsSoFar = chosenBikes.reduce((a, b) => a + (b.color === 'red'), 0);
const picksRemaining = totalPicks - i;
const mustChooseRed = requiredRed - redsSoFar === picksRemaining;
chosenBikes.push(
mustChooseRed
? reds[Math.floor(Math.random() * reds.length)]
: bikes[Math.floor(Math.random() * bikes.length)]
);
}
return chosenBikes;
}
console.log(getRandomBikes(2, 3));
Or with less complexity
const bikes = [
{ type: 'bmx', color: 'red' },
{ type: 'mountain', color: 'blue' },
{ type: 'bmx', color: 'yellow' },
{ type: 'mountain', color: 'black' },
{ type: 'bmx', color: 'red' },
{ type: 'bmx', color: 'purple' }
];
const getRandomBikes = (requiredRed, totalPicks) => {
const chosenBikes = [];
const reds = bikes.filter(({ color }) => color === 'red');
let redsSoFar = 0;
for(let i = 0; i < totalPicks; i++) {
const picksRemaining = totalPicks - i;
const mustChooseRed = requiredRed - redsSoFar === picksRemaining;
const chosenBike = mustChooseRed
? reds[Math.floor(Math.random() * reds.length)]
: bikes[Math.floor(Math.random() * bikes.length)]
if (chosenBike.color === 'red') redsSoFar++;
chosenBikes.push(chosenBike);
}
return chosenBikes;
}
console.log(getRandomBikes(2, 3));

How to fix overflow data labels in graph created with Chart.js?

I have a graph created with Chart.js. There are options and one of them 'responsive: true' that provides a responsive view. The problem is when I load a graph with data the first time the y-ax labels overflow border and show as on the screen below. When I change the view y-ax labels show with overflow hidden and elepsis at the end of the label.
Also, I need to add a custom baloon for labels, how can I do it?
Before view change:
After view change:
Here is my chank of code:
drawWordsChart: function(placeholder, data, options = {}) {
console.log('drawWordsChart', data);
var sortable = [];
for (var word in data) {
sortable.push([data[word].text, data[word].weight]);
}
sortable.sort(function(a, b) {
return b[1] - a[1];
});
sortable = sortable.slice(0, 20);
let labels = [];
let values = [];
let colors = [], intense = 1;
angular.forEach(sortable, (elem, key) => {
colors.push('rgb(30, 144, 255,' + (intense - key / 20) + ')');
labels.push(elem[0]);
values.push(elem[1]);
});
var horizontalBarChartData = {
labels: labels,
datasets: [{
label: options.label || 'weight',
backgroundColor: colors,
borderColor: colors,
data: values
}]
};
const ctx = document.getElementById(placeholder).getContext('2d');
const myHorizontalBar = new Chart(ctx, {
type: options.type || 'horizontalBar',
data: horizontalBarChartData,
options: {
elements: {
rectangle: {
borderWidth: 1,
}
},
responsive: true,
legend: {
position: 'right',
display: false
},
scales: {
yAxes: [{
barPercentage: 0.1,
barThickness: 10,
maxBarThickness: 10,
minBarLength: 2,
gridLines: {
offsetGridLines: true
},
ticks: {
callback: function(value, index, values) {
return $filter('limitTo')(value, 8) + (value.length > 8 ? '...' : '');
}
}
}]
},
maintainAspectRatio: false
}
});
return myHorizontalBar;
}
Here I added property 'ticks' in options with callback, which limiting value to 8 letters, and add ellipsis at the end. Also, I added a custom filter.
ticks: {
callback: function(value, index, values) {
return $filter('limitTo')(value, 8) + (value.length > 8 ? '...' : '');
}
}

Chart Js - Globally set bar chart color based on value

I want to generate a page with multiple bar charts and set the color of each globally based on a value in array!
this is the code i have so far..it works in so far as it takes one of the values and assigns it all of the bars! Where I need it to assign RED to FALSE and GREEN to TRUE
var win = simpleData[0].myWin; //array containing either true or false
var myBorderColors = [];
$.each(win, function (index, value) {
if (value == true) {
myBorderColors[index] = "rgba(0, 177, 106, 1)";
} else {
myBorderColors[index] = "rgba(207, 0, 15, 1)";
}
});
Chart.defaults.global.elements.rectangle.backgroundColor = myBorderColors;
Given an array named "win" that contains boolean values, you could create the "myBorderColors" array as follows using Array.map.
var myBorderColors = win.map(b => b ? "rgba(0, 177, 106, 1)" : "rgba(207, 0, 15, 1)");
And then use the following assignment to Chart.defaults.
Chart.defaults.global.datasets.bar.borderColor = myBorderColors;
Please have a look at the runnable code snippet below.
var win = [true, false, false, true];
var myBorderColors = win.map(b => b ? "rgba(0, 177, 106, 1)" : "rgba(207, 0, 15, 1)");
Chart.defaults.global.datasets.bar.borderColor = myBorderColors;
new Chart(document.getElementById('myChart'), {
type: 'bar',
data: {
labels: ['A', 'B', 'C', 'D'],
datasets: [{
label: "My Dataset",
data: [3, 5, 4, 2],
borderWidth: 3
}]
},
options: {
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
canvas {
max-width: 300px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart" height="200"></canvas>

I need help for merging values in object array - Javascript

I am working with one project , I have the data comes to me as Object Array and I need to combine the same keys in one key and make the value as an array of strings.
here is the data I have :
inputArray = [
{
colors: 'Red',
size: 'Small'
},
{
colors: 'Blue',
size: 'Large'
},
{
colors: 'Red',
size: 'Large'
},
{
colors: 'Pink',
size: 'X-Large'
}
]
and here is the required output :
outputArray = {
colors: ['Red','Blue','Pink'],
size: ['Large','X-large','Small']
}
You could use a simple dictionary structure to do this. And verify if every element already exists before adding it to array.
const outputArray = {
colors: [],
size: [],
};
for (elem of inputArray) {
if (!outputArray['colors'].includes(elem.colors)) {
outputArray['colors'].push(elem.colors);
}
if (!outputArray['size'].includes(elem.size)) {
outputArray['size'].push(elem.size);
}
}
which will give
{
colors: [ 'Red', 'Blue', 'Pink' ],
size: [ 'Small', 'Large', 'X-Large' ]
}
it's a basic one...
const inputArray =
[ { colors: 'Red', size: 'Small' }
, { colors: 'Blue', size: 'Large' }
, { colors: 'Red', size: 'Large' }
, { colors: 'Pink', size: 'X-Large'}
];
outputArray = inputArray.reduce((a,c)=>
{
if (!a.colors.includes(c.colors) ) a.colors.push( c.colors);
if (!a.size.includes(c.size) ) a.size.push( c.size);
return a
}
,{ colors:[], size:[]})
;
console.log (outputArray )
[edit] if you do not know the variety of entry keys, you can use:
inputArray =
[ { colors: 'Red', size: 'Small' }
, { colors: 'Blue', size: 'Large' }
, { colors: 'Red', size: 'Large' }
, { colors: 'Pink', size: 'X-Large', truc: 'bidule' }
];
outputArray = inputArray.reduce((a,c)=>
{
for (let key in c)
{
if (!a[key]) a[key] = []
if (!a[key].includes(c.colors) ) a[key].push( c[key])
}
return a
} ,{})
;
console.log (outputArray)
This seems to work...
let inputArray = [
{
colors: 'Red',
size: 'Small'
},
{
colors: 'Blue',
size: 'Large'
},
{
colors: 'Red',
size: 'Large'
},
{
colors: 'Pink',
size: 'X-Large'
}
]
let outputArray = [{colors: [], size: []}]
for (let i = 0; i<inputArray.length; i++){
outputArray[0].colors.push(inputArray[i].colors)
outputArray[0].size.push(inputArray[i].size)
}
console.log(outputArray)
Is this what you were after?
While this is not logically much different from the second part of the answer by Mister Jojo, it does the same thing without any mutations, in perhaps a more functional manner:
const gather = (xs) =>
xs .reduce (
(a, x) => Object .entries (x) .reduce ((a, [k, v]) => ({...a, [k]: (a[k] || []).concat(v)}), a),
{}
)
const inputArray = [{ colors: 'Red', size: 'Small'}, {colors: 'Blue', size: 'Large'}, {colors: 'Red', size: 'Large'}, {colors: 'Pink', size: 'X-Large'}]
console .log (gather (inputArray))
It is likely less performant than that version, for reasons described by Rich Snapp, but in practice I haven't seen this being a real issue.

Jquery - Counting JSON objects

Im building a chart system that will show me all data entries. I retrieve my data using ajax and I loop trough the data and group the results by colors (red, blue and yellow) and then divide them by months.
I setup base objects (dateCounts_Red, dateCounts_Blue and dateCounts_Yellow) so that by default it starts all months at 0. A counter would then add when it finds a match tot he apropriate color and month.
When I output my dateCounts I get:
{"2015":{"2015-12":1,"2015-10":null,"2015-08":null,"2015-11":null}}
{"2015":{"2015-12":0,"2015-10":null}}
{"2015":{"2015-12":0,"2015-10":null}}
Here is the code I have so far:
var dateCounts_Red = {"2015":{"2015-01":0,"2015-02":0,"2015-03":0,"2015-04":0},"2015":{"2015-05":0},"2015":{"2015-06":0},"2015":{"2015-07":0},"2015":{"2015-08":0},"2015":{"2015-09":0},"2015":{"2015-10":0},"2015":{"2015-11":0},"2015":{"2015-12":0}};
var dateCounts_Blue = {"2015":{"2015-01":0,"2015-02":0,"2015-03":0,"2015-04":0},"2015":{"2015-05":0},"2015":{"2015-06":0},"2015":{"2015-07":0},"2015":{"2015-08":0},"2015":{"2015-09":0},"2015":{"2015-10":0},"2015":{"2015-11":0},"2015":{"2015-12":0}};
var dateCounts_Yellow = {"2015":{"2015-01":0,"2015-02":0,"2015-03":0,"2015-04":0},"2015":{"2015-05":0},"2015":{"2015-06":0},"2015":{"2015-07":0},"2015":{"2015-08":0},"2015":{"2015-09":0},"2015":{"2015-10":0},"2015":{"2015-11":0},"2015":{"2015-12":0}};
data.d.results.forEach(function(element) {
var date = element.created_date.slice(0, 7);
var yr = date.slice(0, 4);
var Color = element.colorvalue;
if(Color == "red") {
dateCounts_Red[yr][date]++;
}
if(Color == "blue"){
dateCounts_Blue[yr][date]++;
}
if(Color == "yellow"){
dateCounts_Yellow[yr][date]++;
}
});
Red_yr_2015_data = [dateCounts_Red['2015']['2015-01'], dateCounts_Red['2015']['2015-02'], dateCounts_Red['2015']['2015-03'], dateCounts_Red['2015']['2015-04'], dateCounts_Red['2015']['2015-05'], dateCounts_Red['2015']['2015-06'], dateCounts_Red['2015']['2015-07'], dateCounts_Red['2015']['2015-08'], dateCounts_Red['2015']['2015-09'], dateCounts_Red['2015']['2015-10'], dateCounts_Red['2015']['2015-11'], dateCounts_Red['2015']['2015-12']];
Blue_yr_2015_data = [dateCounts_Blue['2015']['2015-01'], dateCounts_Blue['2015']['2015-02'], dateCounts_Blue['2015']['2015-03'], dateCounts_Blue['2015']['2015-04'], dateCounts_Blue['2015']['2015-05'], dateCounts_Blue['2015']['2015-06'], dateCounts_Blue['2015']['2015-07'], dateCounts_Blue['2015']['2015-08'], dateCounts_Blue['2015']['2015-09'], dateCounts_Blue['2015']['2015-10'], dateCounts_Blue['2015']['2015-11'], dateCounts_Blue['2015']['2015-12']];
Yellow_yr_2015_data = [dateCounts_Yellow['2015']['2015-01'], dateCounts_Yellow['2015']['2015-02'], dateCounts_Yellow['2015']['2015-03'], dateCounts_Yellow['2015']['2015-04'], dateCounts_Yellow['2015']['2015-05'], dateCounts_Yellow['2015']['2015-06'], dateCounts_Yellow['2015']['2015-07'], dateCounts_Yellow['2015']['2015-08'], dateCounts_Yellow['2015']['2015-09'], dateCounts_Yellow['2015']['2015-10'], dateCounts_Yellow['2015']['2015-11'], dateCounts_Yellow['2015']['2015-12']];
Im currently getting the following error from my Highcharts js:
Uncaught TypeError: Cannot set property 'index' of undefined
THis is preventing the chart system to work correctly the data returned is not being returned with it's expected data.
Here a full example to the issue https://jsfiddle.net/awo5aaqb/21/
Would anyone know what im missing?
Your date count objects have major structural flaw.
When you prettify them they look like:
var dateCounts_Blue = {
"2015": {
"2015-01": 0,
"2015-02": 0,
"2015-03": 0,
"2015-04": 0
},
"2015": {
"2015-05": 0
},
"2015": {
"2015-06": 0
},
"2015": {
"2015-07": 0
},
......
Object keys must be unique so these are clearly being repeated and the compiler will over write duplicates.
Fix the pattern that breaks away from the intended pattern grouping at the beginning
var dateCounts_Red = {
"2015":
{
"2015-01":0,
"2015-02":0,
"2015-03":0,
"2015-04":0,
"2015-05":0,
"2015-06":0,
"2015-07":0,
"2015-08":0,
"2015-09":0,
"2015-10":0,
"2015-11":0,
"2015-12":0
},
};
var dateCounts_Blue = {
"2015":{
"2015-01":0,
"2015-02":0,
"2015-03":0,
"2015-04":0,
"2015-05":0,
"2015-06":0,
"2015-07":0,
"2015-08":0,
"2015-09":0,
"2015-10":0,
"2015-11":0,
"2015-12":0
}
};
var dateCounts_Yellow = {
"2015":{
"2015-01":0,
"2015-02":0,
"2015-03":0,
"2015-04":0,
"2015-05":0,
"2015-06":0,
"2015-07":0,
"2015-08":0,
"2015-09":0,
"2015-10":0,
"2015-11":0,
"2015-12":0}
};
Your data structure is flawed and such comparing values when doing the foreach loop becomes inconsistent because it compares it to multiple values, the above JSON is the fix for your problem.
Not quite codereview.stackexchange.com, but I heavily modified your javascript to make it work a bit better
$.ajax({
url: basePath,
dataType: 'json',
cache: false,
success: function(data) {
var counts = {};
data.d.results.forEach(function(element) {
// If you know it's all the same year, you could totally ignore this
var yr = element.created_date.slice(0, 4);
var month = parseInt(element.created_date.slice(5,7));
var color = element.colorvalue;
if (counts[color] === undefined) {
counts[color] = {};
}
if (counts[color][yr] === undefined) {
counts[color][yr] = {};
}
current_value = counts[color][yr][month];
if (current_value === undefined) {
// Doesnt exist yet, so add it
counts[color][yr][month] = 1;
} else {
// Exists, so increment by 1
counts[color][yr][month] = current_value + 1;
}
});
console.log(JSON.stringify(counts));
console.log(transform_series(counts['red']['2015']));
console.log(transform_series(counts['blue']['2015']));
console.log(transform_series(counts['yellow']['2015']));
var Options = {
chart: {
renderTo: 'myfirstchart',
type: 'column',
margin: 75,
options3d: {
enabled: true,
alpha: 25,
beta: 0,
depth: 70
}
},
title: {
text: "Test Highcharts"
},
subtitle: {
text: 'Test charts'
},
plotOptions: {
column: {
depth: 25
}
},
xAxis: {
categories: ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"]
},
yAxis: {
title: {
text: "Number of entries"
}
},
tooltip: {
headerFormat: '<b>{point.key}</b><br>',
pointFormat: '<span style="color:{series.color}">\u25CF</span> {series.name}: {point.y} / {point.stackTotal}'
},
plotOptions: {
column: {
stacking: 'normal',
depth: 40
}
},
series: [{
name: 'Red',
color: 'red',
data: transform_series(counts['red']['2015']),
stack: '2015'
}, {
name: 'Blue',
color: 'blue',
data: transform_series(counts['blue']['2015']),
stack: '2015'
}, {
name: 'Yellow',
color: 'yellow',
data: transform_series(counts['yellow']['2015']),
stack: '2015'
}]
};
return new Highcharts.Chart(Options);
}
});
// this transforms the hash {10: 5, 11:1, 12:1} to get you all 12 months
// and returns an array of values [ 0, 0, 0, 0, 0 ... 5, 1, 1] that
// can be used in high charts
function transform_series(series) {
return Array.apply(null, Array(13)).map(function (_, i) {return (series[i] === undefined) ? 0 : series[i];}).slice(1,13);
}

Categories

Resources