Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for multiple thresholds #21

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 81 additions & 22 deletions src/scripts/chartist-plugin-threshold.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,93 +8,152 @@

var defaultOptions = {
threshold: 0,
maskPadding: 10,
prefix: 'ct-threshold-',
classNames: {
aboveThreshold: 'ct-threshold-above',
belowThreshold: 'ct-threshold-below'
aboveThreshold: 'above',
prefixThreshold: 'area-',
belowThreshold: 'below'
},
maskNames: {
aboveThreshold: 'ct-threshold-mask-above',
belowThreshold: 'ct-threshold-mask-below'
aboveThreshold: 'mask-above',
prefixThreshold: 'mask-area-',
belowThreshold: 'mask-below'
}
};

function createMasks(data, options) {
// Select the defs element within the chart or create a new one
var defs = data.svg.querySelector('defs') || data.svg.elem('defs');
// Project the threshold value on the chart Y axis
var projectedThreshold = data.chartRect.height() - data.axisY.projectValue(options.threshold) + data.chartRect.y2;
var thresholds = options.thresholds;
// Convert threshold values to projected values
function projectedThreshold(threshold) {
return data.chartRect.height() - data.axisY.projectValue(threshold) + data.chartRect.y2;
}
var width = data.svg.width();
var height = data.svg.height();

var aboveThresholdValue = projectedThreshold(thresholds[0]);
var belowThresholdValue = projectedThreshold(thresholds[thresholds.length - 1]);

// Create mask for upper part above threshold
defs
.elem('mask', {
x: 0,
y: 0,
y: -1 * options.maskPadding,
width: width,
height: height,
id: options.maskNames.aboveThreshold
height: height + options.maskPadding,
id: options.prefix + options.maskNames.aboveThreshold
})
.elem('rect', {
x: 0,
y: 0,
y: -1 * options.maskPadding,
width: width,
height: projectedThreshold,
height: aboveThresholdValue + options.maskPadding,
fill: 'white'
});

// Create mask for lower part below threshold
defs
.elem('mask', {
x: 0,
y: 0,
y: -1 * options.maskPadding,
width: width,
height: height,
id: options.maskNames.belowThreshold
height: height + options.maskPadding,
id: options.prefix + options.maskNames.belowThreshold
})
.elem('rect', {
x: 0,
y: projectedThreshold,
y: belowThresholdValue,
width: width,
height: height - projectedThreshold,
height: height - belowThresholdValue + options.maskPadding,
fill: 'white'
});

// Add all other thresholds
for(var i = 1; i <= thresholds.length - 1; ++i) {
var currThreshold = projectedThreshold(thresholds[i]);
var prevThreshold = projectedThreshold(thresholds[i - 1]);
defs
.elem('mask', {
x: 0,
y: 0,
width: width,
height: height,
id: options.prefix + options.maskNames.prefixThreshold + (i - 1)
})
.elem('rect', {
x: 0,
y: prevThreshold,
width: width,
height: currThreshold - prevThreshold,
fill: 'white'
});
}

return defs;
}

Chartist.plugins = Chartist.plugins || {};
Chartist.plugins.ctThreshold = function (options) {

options = Chartist.extend({}, defaultOptions, options);
// Single threshold should be converted
if (!options.thresholds) {
options.thresholds = [options.threshold];
}

return function ctThreshold(chart) {
if (chart instanceof Chartist.Line || chart instanceof Chartist.Bar) {
chart.on('draw', function (data) {
if (data.type === 'point') {
// For points we can just use the data value and compare against the threshold in order to determine
// the appropriate class
data.element.addClass(
data.value.y >= options.threshold ? options.classNames.aboveThreshold : options.classNames.belowThreshold
);

if (data.value.y >= options.thresholds[0]){
data.element.addClass(options.prefix + options.classNames.aboveThreshold);
} else if (data.value.y < options.thresholds[options.thresholds.length - 1]) {
data.element.addClass(options.prefix + options.classNames.belowThreshold);
// Multiple thresholds
} else {
for(var i = 1; i <= options.thresholds.length - 1; ++i) {
// if value is larger that threshold we are done
if (data.value.y >= options.thresholds[i]){
data.element.addClass(options.prefix + options.classNames.prefixThreshold + (i - 1));
break;
}
}
}
} else if (data.type === 'line' || data.type === 'bar' || data.type === 'area') {
// Cloning the original line path, mask it with the upper mask rect above the threshold and add the
// class for above threshold
data.element
.parent()
.elem(data.element._node.cloneNode(true))
.attr({
mask: 'url(#' + options.maskNames.aboveThreshold + ')'
mask: 'url(#' + options.prefix + options.maskNames.aboveThreshold + ')'
})
.addClass(options.classNames.aboveThreshold);
.addClass(options.prefix + options.classNames.aboveThreshold);

// Add class for other thresholds
for(var j = 1; j <= options.thresholds.length - 1; ++j) {
data.element
.parent()
.elem(data.element._node.cloneNode(true))
.attr({
mask: 'url(#' + options.prefix + options.maskNames.prefixThreshold + (j-1) + ')'
})
.addClass(options.prefix + options.classNames.prefixThreshold + (j-1));
}

// Use the original line path, mask it with the lower mask rect below the threshold and add the class
// for blow threshold
data.element
.attr({
mask: 'url(#' + options.maskNames.belowThreshold + ')'
mask: 'url(#' + options.prefix + options.maskNames.belowThreshold + ')'
})
.addClass(options.classNames.belowThreshold);
.addClass(options.prefix + options.classNames.belowThreshold);
}
});

Expand Down