fixed-chartjs-plugin-draggable-selectrange
Version:
A ChartJS select range plugin for Line charts. It select a range of chart from X axis
277 lines (275 loc) • 11.5 kB
JavaScript
;
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); }
function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); }
function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); }
function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; }
function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
var _states = /*#__PURE__*/new WeakMap();
var State = /*#__PURE__*/_createClass(function State() {
var _this = this;
_classCallCheck(this, State);
_classPrivateFieldInitSpec(this, _states, void 0);
_defineProperty(this, "get", function (chart) {
var state = _classPrivateFieldGet(_states, _this).get(chart);
return state || null;
});
_defineProperty(this, "set", function (chart, updatedState) {
var originalState = _this.get(chart);
_classPrivateFieldGet(_states, _this).set(chart, Object.assign({}, originalState, updatedState));
return updatedState;
});
_classPrivateFieldSet(_states, this, new WeakMap());
});
var _states2 = /*#__PURE__*/new WeakMap();
var Graphic = /*#__PURE__*/_createClass(function Graphic(states) {
var _this2 = this;
_classCallCheck(this, Graphic);
_classPrivateFieldInitSpec(this, _states2, void 0);
_defineProperty(this, "draw", function (chart, options) {
var state = _classPrivateFieldGet(_states2, _this2).get(chart);
if (!state || state.selectionXY.drawing === false && !state.selectionXY.end.x || state.selectionXY.end.x === state.selectionXY.start.x) {
options.startDataIndex = undefined;
options.endDataIndex = undefined;
return;
}
var ctx = chart.ctx;
ctx.save();
ctx.globalCompositeOperation = "xor";
ctx.fillStyle = options.unselectColor;
var y = chart.chartArea.top;
var height = chart.chartArea.height;
var x1 = chart.chartArea.left;
var w1 = state.selectionXY.start.x - chart.chartArea.left || 0;
var x2 = state.selectionXY.end.x || 0;
var w2 = chart.chartArea.right - (state.selectionXY.end.x || 0);
//Check Reverse Select Range
if ((state.selectionXY.end.x || 0) < (state.selectionXY.start.x || 0)) {
w1 = state.selectionXY.end.x - chart.chartArea.left || 0;
x2 = state.selectionXY.start.x || 0;
w2 = chart.chartArea.right - (state.selectionXY.start.x || 0);
}
ctx.fillRect(x1, y, w1, height);
ctx.fillRect(x2, y, w2, height);
ctx.globalCompositeOperation = "source-over";
ctx.fillStyle = options.borderColor;
ctx.fillRect(state.selectionXY.start.x, y, options.borderWidth, height);
ctx.fillRect(state.selectionXY.end.x, y, options.borderWidth, height);
if (options.text.enable && (state.selectionXY.drawing || options.startDataIndex && options.endDataIndex)) {
ctx.font = " ".concat(options.text.font.size, "px ").concat(options.text.font.family);
ctx.fillStyle = options.text.color;
var startAxisValue = chart.data.labels[state.selectionXY.start.axisIndex];
var endAxisValue = chart.data.labels[state.selectionXY.end.axisIndex];
var textCallback = chart.config.options.plugins.draggableSelectRange.text.callback;
if (textCallback) {
startAxisValue = textCallback(startAxisValue);
}
ctx.fillText(startAxisValue, state.selectionXY.start.x + options.text.offset, y - options.text.padding);
ctx.fillText(endAxisValue, state.selectionXY.end.x + options.text.offset, y - options.text.padding);
}
ctx.restore();
});
_defineProperty(this, "getLabelXPosition", function (chart, labelIndex) {
if (!chart || !chart.data || !chart.data.labels || labelIndex < 0 || labelIndex >= chart.data.labels.length) {
return null;
}
var xScale = chart.scales['x-axis'] || chart.options.scales.x;
if (!xScale || !xScale.ticks) {
return null;
}
var chartArea = chart.chartArea;
var tickSpacing = (chartArea.right - chartArea.left) / (xScale.ticks.count - 1);
var labelOffset = labelIndex * tickSpacing;
return chartArea.left + labelOffset + tickSpacing / 2;
});
_classPrivateFieldSet(_states2, this, states);
});
/* Plugin */
var states = new State();
var Graphics = new Graphic(states);
var _default = exports["default"] = {
id: "draggableSelectRange",
start: function start(chart, args, options) {
if (!chart?.config?.options?.plugins?.draggableSelectRange?.enable) {
return;
}
var canvasElement = chart.canvas;
canvasElement.addEventListener("mousedown", function (e) {
var axisElements = chart.getElementsAtEventForMode(e, "index", {
intersect: false
});
if (axisElements.length === 0) {
return;
}
var axisIndex = chart.getElementsAtEventForMode(e, "index", {
intersect: false
})[0].index;
var axisValue = chart.data.labels[axisIndex];
states.set(chart, {
selectionXY: {
drawing: true,
start: {
axisValue: axisValue,
axisIndex: axisIndex,
x: e.offsetX,
y: e.offsetY
},
end: {}
}
});
});
window.addEventListener("mouseup", function (e) {
var state = states.get(chart);
if (!state || state.selectionXY.drawing === false) {
return;
}
var axisElements = chart.getElementsAtEventForMode(e, "index", {
intersect: false
});
if (axisElements.length === 0) {
states.set(chart, {
selectionXY: {
drawing: false,
start: {},
end: {}
}
});
return;
}
var axisIndex = axisElements.length > 0 ? axisElements[0].index : chart.data.labels.length - 1;
var axisValue = chart.data.labels[axisIndex];
if (state.selectionXY.start.axisValue > axisValue) {
state.selectionXY.end = JSON.parse(JSON.stringify(state.selectionXY.start));
state.selectionXY.start = {
axisValue: axisValue,
axisIndex: axisIndex,
x: e.offsetX,
y: e.offsetY
};
} else {
state.selectionXY.end = {
axisValue: axisValue,
axisIndex: axisIndex,
x: e.offsetX,
y: e.offsetY
};
}
state.selectionXY.drawing = false;
states.set(chart, state);
chart.update();
var selectCompleteCallback = chart.config.options.plugins.draggableSelectRange.onSelect;
if (chart.config.options.plugins.draggableSelectRange) {
options.startDataIndex = state.selectionXY.start.axisIndex;
options.endDataIndex = state.selectionXY.end.axisIndex;
}
if (selectCompleteCallback) {
selectCompleteCallback({
range: [state.selectionXY.start.axisValue, state.selectionXY.end.axisValue],
boundingBox: [state.selectionXY.start, [state.selectionXY.end.x, state.selectionXY.start.y], state.selectionXY.end, [state.selectionXY.start.x, state.selectionXY.end.y]]
});
}
});
canvasElement.addEventListener("mousemove", function (e) {
var state = states.get(chart);
if (!state || state.selectionXY.drawing === false) {
return;
}
var axisElements = chart.getElementsAtEventForMode(e, "index", {
intersect: false
});
var axisIndex = axisElements.length > 0 ? axisElements[0].index : chart.data.labels.length - 1;
var axisValue = chart.data.labels[axisIndex];
state.selectionXY.end = {
axisValue: axisValue,
axisIndex: axisIndex,
x: e.offsetX,
y: e.offsetY
};
chart.render();
states.set(chart, state);
});
},
afterDraw: function afterDraw(chart, args, options) {
Graphics.draw(chart, options);
},
setRange: function setRange(chart, options, range) {
var startIndex = 0;
var endIndex = 0;
var i = 0;
for (; i < chart.data.labels.length; i++) {
if (range[0] === chart.data.labels[i]) {
startIndex = i;
break;
}
}
for (; i < chart.data.labels.length; i++) {
if (range[1] === chart.data.labels[i]) {
endIndex = i;
break;
}
}
options.startDataIndex = startIndex;
options.endDataIndex = endIndex;
states.set(chart, {
selectionXY: {
drawing: false,
start: {
axisValue: range[0],
axisIndex: startIndex,
x: Graphics.getLabelXPosition(chart, startIndex),
y: 0
},
end: {
axisValue: range[1],
axisIndex: endIndex,
x: Graphics.getLabelXPosition(chart, endIndex),
y: chart.chartArea.height
}
}
});
this.defaults.startDataIndex = range[0];
this.defaults.endDataIndex = range[1];
Graphics.draw(chart, options);
chart.render();
chart.update();
return [startIndex, endIndex];
},
clearDraw: function clearDraw(chart) {
states.set(chart, {
selectionXY: {
drawing: false,
start: {},
end: {}
}
});
chart.render();
},
defaults: {
enable: false,
unselectColor: "rgba(255,255,255,0.65)",
borderColor: "#2388FF",
borderWidth: 2,
startDataIndex: undefined,
endDataIndex: undefined,
text: {
enable: true,
color: "#000",
offset: 0,
padding: 0,
font: {
family: 'Arial',
size: 13
}
}
}
};