Skip to content
Closed
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions docs/charts/bar.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Some properties can be specified as an array. If these are set to an array value
| `hoverBackgroundColor` | `Color/Color[]` | The fill colour of the bars when hovered.
| `hoverBorderColor` | `Color/Color[]` | The stroke colour of the bars when hovered.
| `hoverBorderWidth` | `Number/Number[]` | The stroke width of the bars when hovered.
| `legend` | `object` | Style of the legend if point style is not used. [more...](../configuration/legend.md/#dataset-legend-configuration)

### borderSkipped
This setting is used to avoid drawing the bar stroke at the base of the fill. In general, this does not need to be changed except when creating chart types that derive from a bar chart.
Expand Down
1 change: 1 addition & 0 deletions docs/charts/bubble.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ The bubble chart allows a number of properties to be specified for each dataset.
| [`pointStyle`](#styling) | `String` | Yes | Yes | `circle`
| [`rotation`](#styling) | `Number` | Yes | Yes | `0`
| [`radius`](#styling) | `Number` | Yes | Yes | `3`
| [`legend`](../configuration/legend.md/#dataset-legend-configuration) | `object` | - | - |

### Labeling

Expand Down
1 change: 1 addition & 0 deletions docs/charts/doughnut.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ The doughnut/pie chart allows a number of properties to be specified for each da
| `hoverBackgroundColor` | `Color[]` | The fill colour of the arcs when hovered.
| `hoverBorderColor` | `Color[]` | The stroke colour of the arcs when hovered.
| `hoverBorderWidth` | `Number[]` | The stroke width of the arcs when hovered.
| `legend` | `object` | Style of the legend if point style is not used. [more...](../configuration/legend.md/#dataset-legend-configuration)

## Config Options

Expand Down
1 change: 1 addition & 0 deletions docs/charts/line.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ All point* properties can be specified as an array. If these are set to an array
| `showLine` | `Boolean` | If false, the line is not drawn for this dataset.
| `spanGaps` | `Boolean` | If true, lines will be drawn between points with no or null data. If false, points with `NaN` data will create a break in the line
| `steppedLine` | `Boolean/String` | If the line is shown as a stepped line. [more...](#stepped-line)
| `legend` | `object` | Style of the legend if point style is not used. [more...](../configuration/legend.md/#dataset-legend-configuration)

### cubicInterpolationMode
The following interpolation modes are supported:
Expand Down
1 change: 1 addition & 0 deletions docs/charts/polar.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ The following options can be included in a polar area chart dataset to configure
| `hoverBackgroundColor` | `Color[]` | The fill colour of the arcs when hovered.
| `hoverBorderColor` | `Color[]` | The stroke colour of the arcs when hovered.
| `hoverBorderWidth` | `Number[]` | The stroke width of the arcs when hovered.
| `legend` | `object` | Style of the legend if point style is not used. [more...](../configuration/legend.md/#dataset-legend-configuration)

## Config Options

Expand Down
1 change: 1 addition & 0 deletions docs/charts/radar.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ All point* properties can be specified as an array. If these are set to an array
| `pointHoverBorderColor` | `Color/Color[]` | Point border color when hovered.
| `pointHoverBorderWidth` | `Number/Number[]` | Border width of point when hovered.
| `pointHoverRadius` | `Number/Number[]` | The radius of the point when hovered.
| `legend` | `object` | Style of the legend if point style is not used. [more...](../configuration/legend.md/#dataset-legend-configuration)

### pointStyle
The style of point. Options are:
Expand Down
23 changes: 21 additions & 2 deletions docs/configuration/legend.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ The legend label configuration is nested below the legend configuration using th

| Name | Type | Default | Description
| -----| ---- | --------| -----------
| `boxWidth` | `Number` | `40` | width of coloured box
| `boxWidth` | `Number` | `40` | width of symbol if point style not used
| `fontSize` | `Number` | `12` | font size of text
| `fontStyle` | `String` | `'normal'` | font style of text
| `fontColor` | `Color` | `'#666'` | Color of text
Expand All @@ -37,6 +37,7 @@ The legend label configuration is nested below the legend configuration using th
| `generateLabels` | `Function` | | Generates legend items for each thing in the legend. Default implementation returns the text + styling for the color box. See [Legend Item](#legend-item-interface) for details.
| `filter` | `Function` | `null` | Filters legend items out of the legend. Receives 2 parameters, a [Legend Item](#legend-item-interface) and the chart data.
| `usePointStyle` | `Boolean` | `false` | Label style will match corresponding point style (size is based on fontSize, boxWidth is not used in this case).
| `symbol` | `String` | `rect` | Legend symbol to display if point style is not used. Available values from [PointStyle](./elements.md/#point-styles)

## Legend Item Interface

Expand Down Expand Up @@ -73,6 +74,12 @@ Items passed to the legend `onClick` function are the ones returned from `labels

// Point style of the legend box (only used if usePointStyle is true)
pointStyle: String

// Legend symbol to display if point style is not used.
symbol: String

// Width of legend symbol if point style is not used.
boxWidth: Number
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My only comment here is that I think it would be better to remove legendSymbolLarge and imply it if boxWidth is set. So if boxWidth !== undefined then it will be used, otherwise it will be set to fontSize

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if I'm not wrong, boxWidth is defaulted to 40 so it will be always defined. If we remove default value it may impact current users upgrading to that new version.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahh, I missed that. To make that clearer I would suggest a rename to useFontSize or something. Let's wait to rename it until @simonbrunel gets a chance to review this

}
```

Expand Down Expand Up @@ -164,7 +171,19 @@ var chart = new Chart(ctx, {
}
});
```

Note that legendCallback is not called automatically and you must call `generateLegend()` yourself in code when creating a legend using this method.

### Dataset Legend Configuration

The following legend properties can be defined at dataset level. Array is accepted for
all those properties for doughnut and polar chart types.

| Name | Type | Description
| -----| ---- | -----------
| `symbol` | `String` | Legend symbol to display if point style is not used. Available values from [PointStyle](./elements.md/#point-styles).
| `boxWidth` | `Number` | width of symbol if point style not used
| `borderWidth` | `Number` | width of symbol border or symbol line
| `borderColor` | `Number` | color of symbol border or symbol line



9 changes: 5 additions & 4 deletions src/controllers/controller.doughnut.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ defaults._set('doughnut', {
labels: {
generateLabels: function(chart) {
var data = chart.data;
var opts = chart.options.legend.labels;
if (data.labels.length && data.datasets.length) {
return data.labels.map(function(label, i) {
var meta = chart.getDatasetMeta(0);
Expand All @@ -50,14 +51,14 @@ defaults._set('doughnut', {
var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);

return {
text: label,
fillStyle: fill,
strokeStyle: stroke,
lineWidth: bw,
strokeStyle: helpers.valueOrDefault((ds.legend && ds.legend.borderColor && ds.legend.borderColor[i]), stroke),
lineWidth: helpers.valueOrDefault((ds.legend && ds.legend.borderWidth && ds.legend.borderWidth[i]), bw),
hidden: isNaN(ds.data[i]) || meta.data[i].hidden,

legendSymbol: helpers.valueOrDefault((ds.legend && ds.legend.symbol && ds.legend.symbol[i]), opts.symbol),
boxWidth: helpers.valueOrDefault((ds.legend && ds.legend.boxWidth && ds.legend.boxWidth[i]), opts.boxWidth),
// Extra data used for toggling the correct item
index: i
};
Expand Down
9 changes: 5 additions & 4 deletions src/controllers/controller.polarArea.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ defaults._set('polarArea', {
labels: {
generateLabels: function(chart) {
var data = chart.data;
var opts = chart.options.legend.labels;
if (data.labels.length && data.datasets.length) {
return data.labels.map(function(label, i) {
var meta = chart.getDatasetMeta(0);
Expand All @@ -64,14 +65,14 @@ defaults._set('polarArea', {
var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);

return {
text: label,
fillStyle: fill,
strokeStyle: stroke,
lineWidth: bw,
strokeStyle: helpers.valueOrDefault((ds.legend && ds.legend.borderColor && ds.legend.borderColor[i]), stroke),
lineWidth: helpers.valueOrDefault((ds.legend && ds.legend.borderWidth && ds.legend.borderWidth[i]), bw),
hidden: isNaN(ds.data[i]) || meta.data[i].hidden,

legendSymbol: helpers.valueOrDefault((ds.legend && ds.legend.symbol && ds.legend.symbol[i]), opts.symbol),
boxWidth: helpers.valueOrDefault((ds.legend && ds.legend.boxWidth && ds.legend.boxWidth[i]), opts.boxWidth),
// Extra data used for toggling the correct item
index: i
};
Expand Down
142 changes: 79 additions & 63 deletions src/helpers/helpers.canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,103 +49,119 @@ var exports = module.exports = {
},

drawPoint: function(ctx, style, radius, x, y, rotation) {
var type, edgeLength, xOffset, yOffset, height, size;
rotation = rotation || 0;
// call drawSymbol with converted radius to width and height
// and move x, y to the top left corner
this.drawSymbol(ctx, style, radius * 2, radius * 2, x - radius, y - radius, rotation, true);
},

drawSymbol: function(ctx, style, width, height, x, y, rotation, isPoint) {

if (style && typeof style === 'object') {
type = style.toString();
var type = style.toString();
if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
ctx.drawImage(style, x - style.width / 2, y - style.height / 2, style.width, style.height);
return;
ctx.drawImage(style, x, y, style.width, style.height);
return false;
}
}

if (isNaN(radius) || radius <= 0) {
return;
if (isNaN(width) || width <= 0) {
return false;
}
var vx, vy;
if (rotation) {
ctx.save();
ctx.translate(x + width / 2, y + width / 2);
ctx.rotate(rotation * Math.PI / 180);
ctx.translate(-width / 2, -width / 2);
vx = 0;
vy = 0;
} else {
vx = x;
vy = y;
}
var radius = width / 2;
var yRadius = height / 2;

// some symbols are not using the full width when they're called as a point
// e.g. rect, rectRounded, rectRot, crossRot and star
// Following variables are used to define the pading value for those symbols
// the full width and height is used when symbol is called as legend.
var padLeft = isPoint ? radius - width / 2 / Math.sqrt(2) : 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a comment explaining why padding is necessary and what isPoint is doing? I'm not sure what that part is for

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added comments on that. In the production version some symbols can only be called as point and they are not usign the full width since the size is based on the radius. When is used as a legend, I want to be sure that the symbol width = the width value pass as parameter. So to not impact the current behavior (when symbol is called for a point) I did that logic for the impacted symbols. I.e. Add padding when called as a point (not usign the full width) and use the full width (no padding) when called as a legend symbol.

var padRight = isPoint ? radius + width / 2 / Math.sqrt(2) : width;
var padTop = isPoint ? radius - height / 2 / Math.sqrt(2) : 0;
var padBottom = isPoint ? radius + height / 2 / Math.sqrt(2) : height;

ctx.save();
ctx.translate(x, y);
ctx.rotate(rotation * Math.PI / 180);
ctx.beginPath();

switch (style) {
// Default includes circle
// Default circle
default:
ctx.arc(0, 0, radius, 0, Math.PI * 2);
// display standard circle if height and width are the same otherwise display a RectRounded
if (width === height) {
ctx.arc(vx + radius, vy + radius, radius, 0, Math.PI * 2);
} else {
this.roundedRect(ctx, vx + padLeft, vy + padTop, -padLeft + padRight, -padTop + padBottom, radius * 0.425);
}
ctx.closePath();
break;
case 'triangle':
edgeLength = 3 * radius / Math.sqrt(3);
height = edgeLength * Math.sqrt(3) / 2;
ctx.moveTo(-edgeLength / 2, height / 3);
ctx.lineTo(edgeLength / 2, height / 3);
ctx.lineTo(0, -2 * height / 3);
case 'rect':
ctx.rect(vx + padLeft, vy + padTop, -padLeft + padRight, -padTop + padBottom);
ctx.closePath();
break;
case 'rect':
size = 1 / Math.SQRT2 * radius;
ctx.rect(-size, -size, 2 * size, 2 * size);
case 'triangle':
ctx.moveTo(vx + radius, vy);
ctx.lineTo(vx + radius - (radius * Math.sqrt(3) / 2), vy + height * 0.75);
ctx.lineTo(vx + radius + (radius * Math.sqrt(3) / 2), vy + height * 0.75);
ctx.closePath();
break;
case 'rectRounded':
var offset = radius / Math.SQRT2;
var leftX = -offset;
var topY = -offset;
var sideSize = Math.SQRT2 * radius;

// NOTE(SB) the rounded rect implementation changed to use `arcTo`
// instead of `quadraticCurveTo` since it generates better results
// when rect is almost a circle. 0.425 (instead of 0.5) produces
// results visually closer to the previous impl.
this.roundedRect(ctx, leftX, topY, sideSize, sideSize, radius * 0.425);
this.roundedRect(ctx, vx + padLeft, vy + padTop, -padLeft + padRight, -padTop + padBottom, radius * 0.425);
ctx.closePath();
break;
case 'rectRot':
size = 1 / Math.SQRT2 * radius;
ctx.moveTo(-size, 0);
ctx.lineTo(0, size);
ctx.lineTo(size, 0);
ctx.lineTo(0, -size);
ctx.moveTo(vx + padLeft, vy + yRadius);
ctx.lineTo(vx + radius, vy + padTop);
ctx.lineTo(vx + padRight, vy + yRadius);
ctx.lineTo(vx + radius, vy + padBottom);
ctx.closePath();
break;
case 'cross':
ctx.moveTo(0, radius);
ctx.lineTo(0, -radius);
ctx.moveTo(-radius, 0);
ctx.lineTo(radius, 0);
ctx.moveTo(vx + radius, vy);
ctx.lineTo(vx + radius, vy + height);
ctx.moveTo(vx, vy + yRadius);
ctx.lineTo(vx + width, vy + yRadius);
break;
case 'crossRot':
xOffset = Math.cos(Math.PI / 4) * radius;
yOffset = Math.sin(Math.PI / 4) * radius;
ctx.moveTo(-xOffset, -yOffset);
ctx.lineTo(xOffset, yOffset);
ctx.moveTo(-xOffset, yOffset);
ctx.lineTo(xOffset, -yOffset);
ctx.moveTo(vx + padLeft, vy + padTop);
ctx.lineTo(vx + padRight, vy + padBottom);
ctx.moveTo(vx + padLeft, vy + padBottom);
ctx.lineTo(vx + padRight, vy + padTop);
break;
case 'star':
ctx.moveTo(0, radius);
ctx.lineTo(0, -radius);
ctx.moveTo(-radius, 0);
ctx.lineTo(radius, 0);
xOffset = Math.cos(Math.PI / 4) * radius;
yOffset = Math.sin(Math.PI / 4) * radius;
ctx.moveTo(-xOffset, -yOffset);
ctx.lineTo(xOffset, yOffset);
ctx.moveTo(-xOffset, yOffset);
ctx.lineTo(xOffset, -yOffset);
ctx.moveTo(vx + radius, vy);
ctx.lineTo(vx + radius, vy + height);
ctx.moveTo(vx, vy + yRadius);
ctx.lineTo(vx + width, vy + yRadius);
ctx.moveTo(vx + padLeft, vy + padTop);
ctx.lineTo(vx + padRight, vy + padBottom);
ctx.moveTo(vx + padLeft, vy + padBottom);
ctx.lineTo(vx + padRight, vy + padTop);
break;
case 'line':
ctx.moveTo(-radius, 0);
ctx.lineTo(radius, 0);
ctx.moveTo(vx, vy + yRadius);
ctx.lineTo(vx + width, vy + yRadius);
break;
case 'dash':
ctx.moveTo(0, 0);
ctx.lineTo(radius, 0);
ctx.moveTo(vx + radius, vy + yRadius);
ctx.lineTo(vx + width, vy + yRadius);
break;
}

ctx.fill();
ctx.stroke();
ctx.restore();
if (rotation) {
ctx.restore();
}
return true;

},

clipArea: function(ctx, area) {
Expand Down
Loading