Charts: can I stack one series and not the other?

  • 1
  • Question
  • Updated 2 months ago
  • Answered
Hi! I want to create a column chart with one series being a quarterly target and one series being actual closed-won opportunity amounts. I want the closed-won opportunity column to be split and stacked by opportunity type. 

Is it possible to stack a series and leave the other series as a separate column?
Photo of Kaede Holland

Kaede Holland

  • 2,744 Points 2k badge 2x thumb
  • hopeful!

Posted 2 months ago

  • 1
Photo of mB Pat Vachon

mB Pat Vachon, Champion

  • 42,714 Points 20k badge 2x thumb
I daresay probably. Most likely a before render and a matter of finding what to extend using Highcharts options. I'd take a look if I weren't slammed. ;)
Photo of Kaede Holland

Kaede Holland

  • 2,744 Points 2k badge 2x thumb
Yes - i see how it's done in highcharts - i've just never tried to do before render code things so I don't know where to start! Any good examples you can think of that show other people modifying highcharts in skuid with before render snippets? 
Photo of mB Pat Vachon

mB Pat Vachon, Champion

  • 42,714 Points 20k badge 2x thumb
Oof ... I can copy paste a couple functions I use constantly.

function reverseStacks(chartObj) {
$.extend(true, chartObj.yAxis[0], {
reversedStacks: false
});
}
function reverseLegend(chartObj) {
$.extend(true, chartObj, {
legend: {
reversed: true
}
});
} function enableLegendClick(chartObj) {
$.extend(true, chartObj, {
plotOptions: {
series: {
events: {
legendItemClick: function (clickParams) {

var splitsStack = [],
splits = [],
pathArray = clickParams.browserEvent.path,
chartId,
editorStack = Array.prototype.slice.call($(".nx-editor:visible")),
editors = [],
splitField,
outerHTML,
conditionName;

function addEditorOrNot(editorStackElement) {
if (editorStackElement.className.indexOf('nx-basicfieldeditor') !== -1 || editorStackElement.className.indexOf('nx-skootable') !== -1) {
editors.push(editorStackElement);
}
}

$.each(editorStack, function (es, editorStackElement) {
if (editorStackElement.className.indexOf('mid_level_table') !== -1) {
editors.push(editorStackElement);
}
});

$.each(pathArray, function (p, path) {
$.each(path.classList, function (c, pathClass) {
if (pathClass == 'highcharts-container') {
chartId = (pathArray[p + 3].id);
return false;
}
});
});

outerHTML = skuid.$C(chartId).seriesListNode["0"].outerHTML;

splitField = outerHTML.substring(outerHTML.indexOf('splittemplate="{{') + 17, outerHTML.length - outerHTML.indexOf('splittemplate="{{') + 17);

splitField = splitField.substring(0, splitField.indexOf('}}"'));

conditionName = '_chartClick_'.concat(splitField);

setTimeout(function () {
splitsStack = Array.prototype.slice.call($(".highcharts-legend-item-hidden:visible"));
$.each(splitsStack, function (s, split) {
splits.push(split.textContent);
});

// loop trough stack to update all conditions except chart
$.each(editors, function (e, editor) {
$.each(editor, function (propertyName, property) {
if (propertyName.startsWith("jQuery") && typeof property.editor !== 'undefined') {

$.each(property.component.list.conditions, function (c, condition) {
if (condition.name === conditionName) {
property.component.list.conditions.splice(c, 1);
}
});
if (property.component.list.model.id === "ActivityCategoriesSplits") {
splitField = "split";
}
property.component.list.conditions.push(
{
type: 'multiple',
field: splitField,
operator: 'not in',
values: splits,
inactive: false,
name: conditionName,
encloseValueInQuotes: true,
encloseValueInParens: false
}
);
property.component.list.render();

// update all fields on last editor
if (e + 1 === editors.length) {
$.each(property.component.list.model.registeredFields, function (f, field) {
field.handleChange();
});
}
}
});
});

}, 1);
}
}
}
},
});
}
function setChartSplitColours(chartObj, color_model_or_color_array, color_index, color_field) {
var chartcolors = [],
colorIndex = [],
ind,
series = chartObj.series;


// check to see if color_model_or_color_array is a model or array of colors
if (typeof color_model_or_color_array.fields !== 'undefined') {
$.each(color_model_or_color_array.getRows(), function (r, row) {

index = row[color_index].replace(/[\n\r]+/g, '');

if (typeof row[color_field] !== 'undefined') {
chartcolors.push('#' + row[color_field]);
colorIndex.push({ index: index, color: row[color_field] });
} else {
chartcolors.push('#000000');
colorIndex.push({ index: index, color: '000000' });
}
});

$.each(series, function (i, s_point) {

$.each(colorIndex, function (c, cIndex) {
if (s_point.id.replace(/[\n\r]+/g, '') == cIndex.index) {
ind = c;
return false;
}
});

// update series index number and color index with ind variable.
$.extend(true, series[i], {
index: ind,
_colorIndex: ind
},
{
index: ind,
_colorIndex: ind
});
});

} else {
$.each(color_model_or_color_array, function (c, array_element) {
chartcolors.push(array_element.color);
});

$.each(series, function (i, s_point) {

$.each(color_model_or_color_array, function (c, array_element) {
if (s_point.id.replace(/[\n\r]+/g, '') == array_element.name) {
ind = c;
return false;
}
});

// update series index number and color index with ind variable.
$.extend(true, series[i], {
index: ind,
_colorIndex: ind
},
{
index: ind,
_colorIndex: ind
});
});
}

$.extend(true, chartObj, {
colors: chartcolors
});

}