mirror of
https://github.com/chartjs/Chart.js.git
synced 2025-12-08 20:36:08 +00:00
Implement layers (z-index) for layout items (#6241)
This commit is contained in:
parent
95b9953922
commit
2a96d83c2c
@ -23,6 +23,7 @@ The grid line configuration is nested under the scale configuration in the `grid
|
||||
| `zeroLineBorderDash` | `number[]` | `[]` | Length and spacing of dashes of the grid line for the first index (index 0). See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash).
|
||||
| `zeroLineBorderDashOffset` | `number` | `0.0` | Offset for line dashes of the grid line for the first index (index 0). See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset).
|
||||
| `offsetGridLines` | `boolean` | `false` | If true, grid lines will be shifted to be between labels. This is set to `true` for a category scale in a bar chart by default.
|
||||
| `z` | `number` | `0` | z-index of gridline layer. Values <= 0 are drawn under datasets, > 0 on top.
|
||||
|
||||
## Tick Configuration
|
||||
The tick configuration is nested under the scale configuration in the `ticks` key. It defines options for the tick marks that are generated by the axis.
|
||||
@ -40,6 +41,7 @@ The tick configuration is nested under the scale configuration in the `ticks` ke
|
||||
| `minor` | `object` | `{}` | Minor ticks configuration. Omitted options are inherited from options above.
|
||||
| `major` | `object` | `{}` | Major ticks configuration. Omitted options are inherited from options above.
|
||||
| `padding` | `number` | `0` | Sets the offset of the tick labels from the axis
|
||||
| `z` | `number` | `0` | z-index of tick layer. Useful when ticks are drawn on chart area. Values <= 0 are drawn under datasets, > 0 on top.
|
||||
|
||||
## Minor Tick Configuration
|
||||
The minorTick configuration is nested under the ticks configuration in the `minor` key. It defines options for the minor tick marks that are generated by the axis. Omitted options are inherited from `ticks` configuration.
|
||||
|
||||
@ -169,6 +169,7 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
me.aspectRatio = height ? width / height : null;
|
||||
me.options = config.options;
|
||||
me._bufferedRender = false;
|
||||
me._layers = [];
|
||||
|
||||
/**
|
||||
* Provided for backward compatibility, Chart and Chart.Controller have been merged,
|
||||
@ -495,6 +496,12 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
// Do this before render so that any plugins that need final scale updates can use it
|
||||
plugins.notify(me, 'afterUpdate');
|
||||
|
||||
me._layers.sort(function(a, b) {
|
||||
return a.z === b.z
|
||||
? a._idx - b._idx
|
||||
: a.z - b.z;
|
||||
});
|
||||
|
||||
if (me._bufferedRender) {
|
||||
me._bufferedRequest = {
|
||||
duration: config.duration,
|
||||
@ -520,6 +527,15 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
|
||||
layouts.update(this, this.width, this.height);
|
||||
|
||||
me._layers = [];
|
||||
helpers.each(me.boxes, function(box) {
|
||||
me._layers.push.apply(me._layers, box._layers());
|
||||
}, me);
|
||||
|
||||
me._layers.forEach(function(item, index) {
|
||||
item._idx = index;
|
||||
});
|
||||
|
||||
/**
|
||||
* Provided for backward compatibility, use `afterLayout` instead.
|
||||
* @method IPlugin#afterScaleUpdate
|
||||
@ -626,6 +642,7 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
|
||||
draw: function(easingValue) {
|
||||
var me = this;
|
||||
var i, layers;
|
||||
|
||||
me.clear();
|
||||
|
||||
@ -643,12 +660,21 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw all the scales
|
||||
helpers.each(me.boxes, function(box) {
|
||||
box.draw(me.chartArea);
|
||||
}, me);
|
||||
// Because of plugin hooks (before/afterDatasetsDraw), datasets can't
|
||||
// currently be part of layers. Instead, we draw
|
||||
// layers <= 0 before(default, backward compat), and the rest after
|
||||
layers = me._layers;
|
||||
for (i = 0; i < layers.length && layers[i].z <= 0; ++i) {
|
||||
layers[i].draw(me.chartArea);
|
||||
}
|
||||
|
||||
me.drawDatasets(easingValue);
|
||||
|
||||
// Rest of layers
|
||||
for (; i < layers.length; ++i) {
|
||||
layers[i].draw(me.chartArea);
|
||||
}
|
||||
|
||||
me._drawTooltip(easingValue);
|
||||
|
||||
plugins.notify(me, 'afterDraw', [easingValue]);
|
||||
|
||||
@ -103,6 +103,14 @@ module.exports = {
|
||||
item.fullWidth = item.fullWidth || false;
|
||||
item.position = item.position || 'top';
|
||||
item.weight = item.weight || 0;
|
||||
item._layers = item._layers || function() {
|
||||
return [{
|
||||
z: 0,
|
||||
draw: function() {
|
||||
item.draw.apply(item, arguments);
|
||||
}
|
||||
}];
|
||||
};
|
||||
|
||||
chart.boxes.push(item);
|
||||
},
|
||||
|
||||
@ -189,7 +189,7 @@ function parseTickFontOptions(options) {
|
||||
return {minor: minor, major: major};
|
||||
}
|
||||
|
||||
module.exports = Element.extend({
|
||||
var Scale = Element.extend({
|
||||
/**
|
||||
* Get the padding needed for the scale
|
||||
* @method getPadding
|
||||
@ -252,6 +252,7 @@ module.exports = Element.extend({
|
||||
me._maxLabelLines = 0;
|
||||
me.longestLabelWidth = 0;
|
||||
me.longestTextCache = me.longestTextCache || {};
|
||||
me._itemsToDraw = null;
|
||||
|
||||
// Dimensions
|
||||
me.beforeSetDimensions();
|
||||
@ -780,22 +781,14 @@ module.exports = Element.extend({
|
||||
},
|
||||
|
||||
/**
|
||||
* Actually draw the scale on the canvas
|
||||
* @param {object} chartArea - the area of the chart to draw full grid lines on
|
||||
* @private
|
||||
*/
|
||||
draw: function(chartArea) {
|
||||
_computeItemsToDraw: function(chartArea) {
|
||||
var me = this;
|
||||
var options = me.options;
|
||||
|
||||
if (!me._isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var chart = me.chart;
|
||||
var context = me.ctx;
|
||||
var options = me.options;
|
||||
var optionTicks = options.ticks;
|
||||
var gridLines = options.gridLines;
|
||||
var scaleLabel = options.scaleLabel;
|
||||
var position = options.position;
|
||||
|
||||
var isRotated = me.labelRotation !== 0;
|
||||
@ -809,12 +802,11 @@ module.exports = Element.extend({
|
||||
|
||||
var tl = getTickMarkLength(gridLines);
|
||||
|
||||
var scaleLabelFontColor = valueOrDefault(scaleLabel.fontColor, defaults.global.defaultFontColor);
|
||||
var scaleLabelFont = helpers.options._parseFont(scaleLabel);
|
||||
var scaleLabelPadding = helpers.options.toPadding(scaleLabel.padding);
|
||||
var labelRotationRadians = helpers.toRadians(me.labelRotation);
|
||||
|
||||
var itemsToDraw = [];
|
||||
var items = [];
|
||||
|
||||
var epsilon = 0.0000001; // 0.0000001 is margin in pixels for Accumulated error.
|
||||
|
||||
var axisWidth = gridLines.drawBorder ? valueAtIndexOrDefault(gridLines.lineWidth, 0, 0) : 0;
|
||||
var alignPixel = helpers._alignPixel;
|
||||
@ -838,8 +830,6 @@ module.exports = Element.extend({
|
||||
tickEnd = me.left + tl;
|
||||
}
|
||||
|
||||
var epsilon = 0.0000001; // 0.0000001 is margin in pixels for Accumulated error.
|
||||
|
||||
helpers.each(ticks, function(tick, index) {
|
||||
// autoskipper skipped this tick (#4635)
|
||||
if (helpers.isNullOrUndef(tick.label)) {
|
||||
@ -919,7 +909,7 @@ module.exports = Element.extend({
|
||||
}
|
||||
}
|
||||
|
||||
itemsToDraw.push({
|
||||
items.push({
|
||||
tx1: tx1,
|
||||
ty1: ty1,
|
||||
tx2: tx2,
|
||||
@ -937,76 +927,156 @@ module.exports = Element.extend({
|
||||
rotation: -1 * labelRotationRadians,
|
||||
label: label,
|
||||
major: tick.major,
|
||||
font: tick.major ? tickFonts.major : tickFonts.minor,
|
||||
textOffset: textOffset,
|
||||
textAlign: textAlign
|
||||
});
|
||||
});
|
||||
|
||||
// Draw all of the tick labels, tick marks, and grid lines at the correct places
|
||||
helpers.each(itemsToDraw, function(itemToDraw) {
|
||||
var glWidth = itemToDraw.glWidth;
|
||||
var glColor = itemToDraw.glColor;
|
||||
items.ticksLength = ticks.length;
|
||||
items.borderValue = borderValue;
|
||||
|
||||
if (gridLines.display && glWidth && glColor) {
|
||||
context.save();
|
||||
context.lineWidth = glWidth;
|
||||
context.strokeStyle = glColor;
|
||||
if (context.setLineDash) {
|
||||
context.setLineDash(itemToDraw.glBorderDash);
|
||||
context.lineDashOffset = itemToDraw.glBorderDashOffset;
|
||||
return items;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_drawGrid: function(chartArea) {
|
||||
var me = this;
|
||||
var ctx = me.ctx;
|
||||
var chart = me.chart;
|
||||
var gridLines = me.options.gridLines;
|
||||
|
||||
if (!gridLines.display) {
|
||||
return;
|
||||
}
|
||||
|
||||
context.beginPath();
|
||||
var alignPixel = helpers._alignPixel;
|
||||
var axisWidth = gridLines.drawBorder ? valueAtIndexOrDefault(gridLines.lineWidth, 0, 0) : 0;
|
||||
var items = me._itemsToDraw || (me._itemsToDraw = me._computeItemsToDraw(chartArea));
|
||||
var glWidth, glColor;
|
||||
|
||||
helpers.each(items, function(item) {
|
||||
glWidth = item.glWidth;
|
||||
glColor = item.glColor;
|
||||
|
||||
if (glWidth && glColor) {
|
||||
ctx.save();
|
||||
ctx.lineWidth = glWidth;
|
||||
ctx.strokeStyle = glColor;
|
||||
if (ctx.setLineDash) {
|
||||
ctx.setLineDash(item.glBorderDash);
|
||||
ctx.lineDashOffset = item.glBorderDashOffset;
|
||||
}
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
if (gridLines.drawTicks) {
|
||||
context.moveTo(itemToDraw.tx1, itemToDraw.ty1);
|
||||
context.lineTo(itemToDraw.tx2, itemToDraw.ty2);
|
||||
ctx.moveTo(item.tx1, item.ty1);
|
||||
ctx.lineTo(item.tx2, item.ty2);
|
||||
}
|
||||
|
||||
if (gridLines.drawOnChartArea) {
|
||||
context.moveTo(itemToDraw.x1, itemToDraw.y1);
|
||||
context.lineTo(itemToDraw.x2, itemToDraw.y2);
|
||||
ctx.moveTo(item.x1, item.y1);
|
||||
ctx.lineTo(item.x2, item.y2);
|
||||
}
|
||||
|
||||
context.stroke();
|
||||
context.restore();
|
||||
}
|
||||
|
||||
if (optionTicks.display) {
|
||||
var tickFont = itemToDraw.major ? tickFonts.major : tickFonts.minor;
|
||||
|
||||
// Make sure we draw text in the correct color and font
|
||||
context.save();
|
||||
context.translate(itemToDraw.labelX, itemToDraw.labelY);
|
||||
context.rotate(itemToDraw.rotation);
|
||||
context.font = tickFont.string;
|
||||
context.fillStyle = tickFont.color;
|
||||
context.textBaseline = 'middle';
|
||||
context.textAlign = itemToDraw.textAlign;
|
||||
|
||||
var label = itemToDraw.label;
|
||||
var y = itemToDraw.textOffset;
|
||||
if (helpers.isArray(label)) {
|
||||
for (var i = 0; i < label.length; ++i) {
|
||||
// We just make sure the multiline element is a string here..
|
||||
context.fillText('' + label[i], 0, y);
|
||||
y += tickFont.lineHeight;
|
||||
}
|
||||
} else {
|
||||
context.fillText(label, 0, y);
|
||||
}
|
||||
context.restore();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
}
|
||||
});
|
||||
|
||||
if (scaleLabel.display) {
|
||||
// Draw the scale label
|
||||
var scaleLabelX;
|
||||
var scaleLabelY;
|
||||
var rotation = 0;
|
||||
var halfLineHeight = scaleLabelFont.lineHeight / 2;
|
||||
if (axisWidth) {
|
||||
// Draw the line at the edge of the axis
|
||||
var firstLineWidth = axisWidth;
|
||||
var lastLineWidth = valueAtIndexOrDefault(gridLines.lineWidth, items.ticksLength - 1, 0);
|
||||
var borderValue = items.borderValue;
|
||||
var x1, x2, y1, y2;
|
||||
|
||||
if (isHorizontal) {
|
||||
if (me.isHorizontal()) {
|
||||
x1 = alignPixel(chart, me.left, firstLineWidth) - firstLineWidth / 2;
|
||||
x2 = alignPixel(chart, me.right, lastLineWidth) + lastLineWidth / 2;
|
||||
y1 = y2 = borderValue;
|
||||
} else {
|
||||
y1 = alignPixel(chart, me.top, firstLineWidth) - firstLineWidth / 2;
|
||||
y2 = alignPixel(chart, me.bottom, lastLineWidth) + lastLineWidth / 2;
|
||||
x1 = x2 = borderValue;
|
||||
}
|
||||
|
||||
ctx.lineWidth = axisWidth;
|
||||
ctx.strokeStyle = valueAtIndexOrDefault(gridLines.color, 0);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x1, y1);
|
||||
ctx.lineTo(x2, y2);
|
||||
ctx.stroke();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_drawLabels: function(chartArea) {
|
||||
var me = this;
|
||||
var ctx = me.ctx;
|
||||
var optionTicks = me.options.ticks;
|
||||
|
||||
if (!optionTicks.display) {
|
||||
return;
|
||||
}
|
||||
|
||||
var items = me._itemsToDraw || (me._itemsToDraw = me._computeItemsToDraw(chartArea));
|
||||
var tickFont;
|
||||
|
||||
helpers.each(items, function(item) {
|
||||
tickFont = item.font;
|
||||
|
||||
// Make sure we draw text in the correct color and font
|
||||
ctx.save();
|
||||
ctx.translate(item.labelX, item.labelY);
|
||||
ctx.rotate(item.rotation);
|
||||
ctx.font = tickFont.string;
|
||||
ctx.fillStyle = tickFont.color;
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.textAlign = item.textAlign;
|
||||
|
||||
var label = item.label;
|
||||
var y = item.textOffset;
|
||||
if (helpers.isArray(label)) {
|
||||
for (var i = 0; i < label.length; ++i) {
|
||||
// We just make sure the multiline element is a string here..
|
||||
ctx.fillText('' + label[i], 0, y);
|
||||
y += tickFont.lineHeight;
|
||||
}
|
||||
} else {
|
||||
ctx.fillText(label, 0, y);
|
||||
}
|
||||
ctx.restore();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_drawTitle: function() {
|
||||
var me = this;
|
||||
var ctx = me.ctx;
|
||||
var options = me.options;
|
||||
var scaleLabel = options.scaleLabel;
|
||||
|
||||
if (!scaleLabel.display) {
|
||||
return;
|
||||
}
|
||||
|
||||
var scaleLabelFontColor = valueOrDefault(scaleLabel.fontColor, defaults.global.defaultFontColor);
|
||||
var scaleLabelFont = helpers.options._parseFont(scaleLabel);
|
||||
var scaleLabelPadding = helpers.options.toPadding(scaleLabel.padding);
|
||||
var halfLineHeight = scaleLabelFont.lineHeight / 2;
|
||||
var position = options.position;
|
||||
var rotation = 0;
|
||||
var scaleLabelX, scaleLabelY;
|
||||
|
||||
if (me.isHorizontal()) {
|
||||
scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
|
||||
scaleLabelY = position === 'bottom'
|
||||
? me.bottom - halfLineHeight - scaleLabelPadding.bottom
|
||||
@ -1020,39 +1090,63 @@ module.exports = Element.extend({
|
||||
rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
|
||||
}
|
||||
|
||||
context.save();
|
||||
context.translate(scaleLabelX, scaleLabelY);
|
||||
context.rotate(rotation);
|
||||
context.textAlign = 'center';
|
||||
context.textBaseline = 'middle';
|
||||
context.fillStyle = scaleLabelFontColor; // render in correct colour
|
||||
context.font = scaleLabelFont.string;
|
||||
context.fillText(scaleLabel.labelString, 0, 0);
|
||||
context.restore();
|
||||
ctx.save();
|
||||
ctx.translate(scaleLabelX, scaleLabelY);
|
||||
ctx.rotate(rotation);
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillStyle = scaleLabelFontColor; // render in correct colour
|
||||
ctx.font = scaleLabelFont.string;
|
||||
ctx.fillText(scaleLabel.labelString, 0, 0);
|
||||
ctx.restore();
|
||||
},
|
||||
|
||||
draw: function(chartArea) {
|
||||
var me = this;
|
||||
|
||||
if (!me._isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (axisWidth) {
|
||||
// Draw the line at the edge of the axis
|
||||
var firstLineWidth = axisWidth;
|
||||
var lastLineWidth = valueAtIndexOrDefault(gridLines.lineWidth, ticks.length - 1, 0);
|
||||
var x1, x2, y1, y2;
|
||||
me._drawGrid(chartArea);
|
||||
me._drawTitle(chartArea);
|
||||
me._drawLabels(chartArea);
|
||||
},
|
||||
|
||||
if (isHorizontal) {
|
||||
x1 = alignPixel(chart, me.left, firstLineWidth) - firstLineWidth / 2;
|
||||
x2 = alignPixel(chart, me.right, lastLineWidth) + lastLineWidth / 2;
|
||||
y1 = y2 = borderValue;
|
||||
} else {
|
||||
y1 = alignPixel(chart, me.top, firstLineWidth) - firstLineWidth / 2;
|
||||
y2 = alignPixel(chart, me.bottom, lastLineWidth) + lastLineWidth / 2;
|
||||
x1 = x2 = borderValue;
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_layers: function() {
|
||||
var me = this;
|
||||
var opts = me.options;
|
||||
var tz = opts.ticks && opts.ticks.z || 0;
|
||||
var gz = opts.gridLines && opts.gridLines.z || 0;
|
||||
|
||||
if (!me._isVisible() || tz === gz || me.draw !== me._draw) {
|
||||
// backward compatibility: draw has been overridden by custom scale
|
||||
return [{
|
||||
z: tz,
|
||||
draw: function() {
|
||||
me.draw.apply(me, arguments);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
context.lineWidth = axisWidth;
|
||||
context.strokeStyle = valueAtIndexOrDefault(gridLines.color, 0);
|
||||
context.beginPath();
|
||||
context.moveTo(x1, y1);
|
||||
context.lineTo(x2, y2);
|
||||
context.stroke();
|
||||
return [{
|
||||
z: gz,
|
||||
draw: function() {
|
||||
me._drawGrid.apply(me, arguments);
|
||||
me._drawTitle.apply(me, arguments);
|
||||
}
|
||||
}, {
|
||||
z: tz,
|
||||
draw: function() {
|
||||
me._drawLabels.apply(me, arguments);
|
||||
}
|
||||
}];
|
||||
}
|
||||
});
|
||||
|
||||
Scale.prototype._draw = Scale.prototype.draw;
|
||||
|
||||
module.exports = Scale;
|
||||
|
||||
@ -224,39 +224,17 @@ function adjustPointPositionForLabelHeight(angle, textSize, position) {
|
||||
function drawPointLabels(scale) {
|
||||
var ctx = scale.ctx;
|
||||
var opts = scale.options;
|
||||
var angleLineOpts = opts.angleLines;
|
||||
var gridLineOpts = opts.gridLines;
|
||||
var pointLabelOpts = opts.pointLabels;
|
||||
var lineWidth = valueOrDefault(angleLineOpts.lineWidth, gridLineOpts.lineWidth);
|
||||
var lineColor = valueOrDefault(angleLineOpts.color, gridLineOpts.color);
|
||||
var tickBackdropHeight = getTickBackdropHeight(opts);
|
||||
var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
|
||||
var plFont = helpers.options._parseFont(pointLabelOpts);
|
||||
|
||||
ctx.save();
|
||||
ctx.lineWidth = lineWidth;
|
||||
ctx.strokeStyle = lineColor;
|
||||
if (ctx.setLineDash) {
|
||||
ctx.setLineDash(resolve([angleLineOpts.borderDash, gridLineOpts.borderDash, []]));
|
||||
ctx.lineDashOffset = resolve([angleLineOpts.borderDashOffset, gridLineOpts.borderDashOffset, 0.0]);
|
||||
}
|
||||
|
||||
var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
|
||||
|
||||
// Point Label Font
|
||||
var plFont = helpers.options._parseFont(pointLabelOpts);
|
||||
|
||||
ctx.font = plFont.string;
|
||||
ctx.textBaseline = 'middle';
|
||||
|
||||
for (var i = getValueCount(scale) - 1; i >= 0; i--) {
|
||||
if (angleLineOpts.display && lineWidth && lineColor) {
|
||||
var outerPosition = scale.getPointPosition(i, outerDistance);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(scale.xCenter, scale.yCenter);
|
||||
ctx.lineTo(outerPosition.x, outerPosition.y);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
if (pointLabelOpts.display) {
|
||||
// Extra pixels out for some label spacing
|
||||
var extra = (i === 0 ? tickBackdropHeight / 2 : 0);
|
||||
var pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + 5);
|
||||
@ -271,7 +249,6 @@ function drawPointLabels(scale) {
|
||||
adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
|
||||
fillText(ctx, scale.pointLabels[i] || '', pointLabelPosition, plFont.lineHeight);
|
||||
}
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
@ -473,60 +450,109 @@ module.exports = LinearScaleBase.extend({
|
||||
0);
|
||||
},
|
||||
|
||||
draw: function() {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_drawGrid: function() {
|
||||
var me = this;
|
||||
var ctx = me.ctx;
|
||||
var opts = me.options;
|
||||
var gridLineOpts = opts.gridLines;
|
||||
var tickOpts = opts.ticks;
|
||||
var angleLineOpts = opts.angleLines;
|
||||
var lineWidth = valueOrDefault(angleLineOpts.lineWidth, gridLineOpts.lineWidth);
|
||||
var lineColor = valueOrDefault(angleLineOpts.color, gridLineOpts.color);
|
||||
var i, offset, position;
|
||||
|
||||
if (opts.display) {
|
||||
var ctx = me.ctx;
|
||||
var startAngle = this.getIndexAngle(0);
|
||||
var tickFont = helpers.options._parseFont(tickOpts);
|
||||
|
||||
if (opts.angleLines.display || opts.pointLabels.display) {
|
||||
if (opts.pointLabels.display) {
|
||||
drawPointLabels(me);
|
||||
}
|
||||
|
||||
if (gridLineOpts.display) {
|
||||
helpers.each(me.ticks, function(label, index) {
|
||||
// Don't draw a centre value (if it is minimum)
|
||||
if (index > 0 || tickOpts.reverse) {
|
||||
var yCenterOffset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
|
||||
|
||||
// Draw circular lines around the scale
|
||||
if (gridLineOpts.display && index !== 0) {
|
||||
drawRadiusLine(me, gridLineOpts, yCenterOffset, index);
|
||||
if (index !== 0) {
|
||||
offset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
|
||||
drawRadiusLine(me, gridLineOpts, offset, index);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (tickOpts.display) {
|
||||
if (angleLineOpts.display && lineWidth && lineColor) {
|
||||
ctx.save();
|
||||
ctx.lineWidth = lineWidth;
|
||||
ctx.strokeStyle = lineColor;
|
||||
if (ctx.setLineDash) {
|
||||
ctx.setLineDash(resolve([angleLineOpts.borderDash, gridLineOpts.borderDash, []]));
|
||||
ctx.lineDashOffset = resolve([angleLineOpts.borderDashOffset, gridLineOpts.borderDashOffset, 0.0]);
|
||||
}
|
||||
|
||||
for (i = getValueCount(me) - 1; i >= 0; i--) {
|
||||
offset = me.getDistanceFromCenterForValue(opts.ticks.reverse ? me.min : me.max);
|
||||
position = me.getPointPosition(i, offset);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(me.xCenter, me.yCenter);
|
||||
ctx.lineTo(position.x, position.y);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_drawLabels: function() {
|
||||
var me = this;
|
||||
var ctx = me.ctx;
|
||||
var opts = me.options;
|
||||
var tickOpts = opts.ticks;
|
||||
|
||||
if (!tickOpts.display) {
|
||||
return;
|
||||
}
|
||||
|
||||
var startAngle = me.getIndexAngle(0);
|
||||
var tickFont = helpers.options._parseFont(tickOpts);
|
||||
var tickFontColor = valueOrDefault(tickOpts.fontColor, defaults.global.defaultFontColor);
|
||||
ctx.font = tickFont.string;
|
||||
var offset, width;
|
||||
|
||||
ctx.save();
|
||||
ctx.font = tickFont.string;
|
||||
ctx.translate(me.xCenter, me.yCenter);
|
||||
ctx.rotate(startAngle);
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
|
||||
helpers.each(me.ticks, function(label, index) {
|
||||
if (index === 0 && !tickOpts.reverse) {
|
||||
return;
|
||||
}
|
||||
|
||||
offset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
|
||||
|
||||
if (tickOpts.showLabelBackdrop) {
|
||||
var labelWidth = ctx.measureText(label).width;
|
||||
width = ctx.measureText(label).width;
|
||||
ctx.fillStyle = tickOpts.backdropColor;
|
||||
|
||||
ctx.fillRect(
|
||||
-labelWidth / 2 - tickOpts.backdropPaddingX,
|
||||
-yCenterOffset - tickFont.size / 2 - tickOpts.backdropPaddingY,
|
||||
labelWidth + tickOpts.backdropPaddingX * 2,
|
||||
-width / 2 - tickOpts.backdropPaddingX,
|
||||
-offset - tickFont.size / 2 - tickOpts.backdropPaddingY,
|
||||
width + tickOpts.backdropPaddingX * 2,
|
||||
tickFont.size + tickOpts.backdropPaddingY * 2
|
||||
);
|
||||
}
|
||||
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillStyle = tickFontColor;
|
||||
ctx.fillText(label, 0, -yCenterOffset);
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
ctx.fillText(label, 0, -offset);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_drawTitle: helpers.noop
|
||||
});
|
||||
|
||||
// INTERNAL: static default options, registered in src/index.js
|
||||
|
||||
33
test/fixtures/scale.radialLinear/gridlines-no-z.json
vendored
Normal file
33
test/fixtures/scale.radialLinear/gridlines-no-z.json
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"config": {
|
||||
"type": "radar",
|
||||
"data": {
|
||||
"labels": ["A", "B", "C", "D", "E"],
|
||||
"datasets": [{
|
||||
"backgroundColor": "rgba(255, 0, 0, 1)",
|
||||
"data": [1,2,3,3,3]
|
||||
}]
|
||||
},
|
||||
"options": {
|
||||
"responsive": false,
|
||||
"legend": false,
|
||||
"title": false,
|
||||
"scale": {
|
||||
"gridLines": {
|
||||
"color": "rgba(0, 0, 0, 1)",
|
||||
"lineWidth": 1
|
||||
},
|
||||
"angleLines": {
|
||||
"color": "rgba(0, 0, 255, 1)",
|
||||
"lineWidth": 1
|
||||
},
|
||||
"pointLabels": {
|
||||
"display": false
|
||||
},
|
||||
"ticks": {
|
||||
"display": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
test/fixtures/scale.radialLinear/gridlines-no-z.png
vendored
Normal file
BIN
test/fixtures/scale.radialLinear/gridlines-no-z.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
34
test/fixtures/scale.radialLinear/gridlines-z.json
vendored
Normal file
34
test/fixtures/scale.radialLinear/gridlines-z.json
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"config": {
|
||||
"type": "radar",
|
||||
"data": {
|
||||
"labels": ["A", "B", "C", "D", "E"],
|
||||
"datasets": [{
|
||||
"backgroundColor": "rgba(255, 0, 0, 1)",
|
||||
"data": [1,2,3,3,3]
|
||||
}]
|
||||
},
|
||||
"options": {
|
||||
"responsive": false,
|
||||
"legend": false,
|
||||
"title": false,
|
||||
"scale": {
|
||||
"gridLines": {
|
||||
"color": "rgba(0, 0, 0, 1)",
|
||||
"lineWidth": 1,
|
||||
"z": 1
|
||||
},
|
||||
"angleLines": {
|
||||
"color": "rgba(0, 0, 255, 1)",
|
||||
"lineWidth": 1
|
||||
},
|
||||
"pointLabels": {
|
||||
"display": false
|
||||
},
|
||||
"ticks": {
|
||||
"display": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
test/fixtures/scale.radialLinear/gridlines-z.png
vendored
Normal file
BIN
test/fixtures/scale.radialLinear/gridlines-z.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
@ -473,4 +473,137 @@ describe('Core.scale', function() {
|
||||
expect(scale.ticks.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_layers', function() {
|
||||
it('should default to one layer', function() {
|
||||
var chart = window.acquireChart({
|
||||
type: 'line',
|
||||
options: {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'x',
|
||||
type: 'linear',
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var scale = chart.scales.x;
|
||||
expect(scale._layers().length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should default to one layer for custom scales', function() {
|
||||
var customScale = Chart.Scale.extend({
|
||||
draw: function() {},
|
||||
convertTicksToLabels: function() {
|
||||
return ['tick'];
|
||||
}
|
||||
});
|
||||
Chart.scaleService.registerScaleType('customScale', customScale, {});
|
||||
|
||||
var chart = window.acquireChart({
|
||||
type: 'line',
|
||||
options: {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'x',
|
||||
type: 'customScale',
|
||||
gridLines: {
|
||||
z: 10
|
||||
},
|
||||
ticks: {
|
||||
z: 20
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var scale = chart.scales.x;
|
||||
expect(scale._layers().length).toEqual(1);
|
||||
expect(scale._layers()[0].z).toEqual(20);
|
||||
});
|
||||
|
||||
it('should default to one layer when z is equal between ticks and grid', function() {
|
||||
var chart = window.acquireChart({
|
||||
type: 'line',
|
||||
options: {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'x',
|
||||
type: 'linear',
|
||||
ticks: {
|
||||
z: 10
|
||||
},
|
||||
gridLines: {
|
||||
z: 10
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var scale = chart.scales.x;
|
||||
expect(scale._layers().length).toEqual(1);
|
||||
});
|
||||
|
||||
|
||||
it('should return 2 layers when z is not equal between ticks and grid', function() {
|
||||
var chart = window.acquireChart({
|
||||
type: 'line',
|
||||
options: {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'x',
|
||||
type: 'linear',
|
||||
ticks: {
|
||||
z: 10
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(chart.scales.x._layers().length).toEqual(2);
|
||||
|
||||
chart = window.acquireChart({
|
||||
type: 'line',
|
||||
options: {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'x',
|
||||
type: 'linear',
|
||||
gridLines: {
|
||||
z: 11
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(chart.scales.x._layers().length).toEqual(2);
|
||||
|
||||
chart = window.acquireChart({
|
||||
type: 'line',
|
||||
options: {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'x',
|
||||
type: 'linear',
|
||||
ticks: {
|
||||
z: 10
|
||||
},
|
||||
gridLines: {
|
||||
z: 11
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(chart.scales.x._layers().length).toEqual(2);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user