mirror of
https://github.com/chartjs/Chart.js.git
synced 2026-03-07 16:56:50 +01:00
Replace horizontalBar with indexAxis: 'y' (#7514)
* Replace horizontalBar with indexAxis: 'y' * Fix drawing of line for last x-position * Consistently determine axis of scale * Add test
This commit is contained in:
committed by
Evert Timberg
parent
c12b33160c
commit
fabcdfec55
@@ -80,13 +80,14 @@ the color of the bars is generally set this way.
|
||||
| ---- | ---- | :----: | :----: | ----
|
||||
| [`backgroundColor`](#styling) | [`Color`](../general/colors.md) | Yes | Yes | `'rgba(0, 0, 0, 0.1)'`
|
||||
| [`borderColor`](#styling) | [`Color`](../general/colors.md) | Yes | Yes | `'rgba(0, 0, 0, 0.1)'`
|
||||
| [`borderSkipped`](#borderskipped) | `string` | Yes | Yes | `'bottom'`
|
||||
| [`borderSkipped`](#borderskipped) | `string` | Yes | Yes | `'start'`
|
||||
| [`borderWidth`](#borderwidth) | <code>number|object</code> | Yes | Yes | `0`
|
||||
| [`clip`](#general) | <code>number|object</code> | - | - | `undefined`
|
||||
| [`data`](#data-structure) | `object[]` | - | - | **required**
|
||||
| [`hoverBackgroundColor`](#interactions) | [`Color`](../general/colors.md) | - | Yes | `undefined`
|
||||
| [`hoverBorderColor`](#interactions) | [`Color`](../general/colors.md) | - | Yes | `undefined`
|
||||
| [`hoverBorderWidth`](#interactions) | `number` | - | Yes | `1`
|
||||
| [`indexAxis`](#general) | `string` | `'x'` | The base axis for the dataset. Use `'y'` for horizontal bar.
|
||||
| [`label`](#general) | `string` | - | - | `''`
|
||||
| [`order`](#general) | `number` | - | - | `0`
|
||||
| [`xAxisID`](#general) | `string` | - | - | first x axis
|
||||
@@ -97,6 +98,7 @@ the color of the bars is generally set this way.
|
||||
| Name | Description
|
||||
| ---- | ----
|
||||
| `clip` | How to clip relative to chartArea. Positive value allows overflow, negative value clips that many pixels inside chartArea. `0` = clip at chartArea. Clipping can also be configured per side: `clip: {left: 5, top: false, right: -2, bottom: 0}`
|
||||
| `indexAxis` | The base axis of the dataset. `'x'` for vertical bars and `'y'` for horizontal bars.
|
||||
| `label` | The label for the dataset which appears in the legend and tooltips.
|
||||
| `order` | The drawing order of dataset. Also affects order for stacking, tooltip and legend.
|
||||
| `xAxisID` | The ID of the x axis to plot this dataset on.
|
||||
@@ -126,6 +128,8 @@ that derive from a bar chart.
|
||||
|
||||
Options are:
|
||||
|
||||
* `'start'`
|
||||
* `'end'`
|
||||
* `'bottom'`
|
||||
* `'left'`
|
||||
* `'top'`
|
||||
@@ -275,10 +279,11 @@ A horizontal bar chart is a variation on a vertical bar chart. It is sometimes u
|
||||
export const ExampleChart1 = () => {
|
||||
useEffect(() => {
|
||||
const cfg = {
|
||||
type: 'horizontalBar',
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
|
||||
datasets: [{
|
||||
axis: 'y',
|
||||
label: 'My First Dataset',
|
||||
data: [65, 59, 80, 81, 56, 55, 40],
|
||||
fill: false,
|
||||
@@ -322,7 +327,7 @@ export const ExampleChart1 = () => {
|
||||
|
||||
```javascript
|
||||
var myBarChart = new Chart(ctx, {
|
||||
type: 'horizontalBar',
|
||||
type: 'bar',
|
||||
data: data,
|
||||
options: options
|
||||
});
|
||||
@@ -332,8 +337,6 @@ var myBarChart = new Chart(ctx, {
|
||||
|
||||
The configuration options for the horizontal bar chart are the same as for the [bar chart](#scale-configuration). However, any options specified on the x axis in a bar chart, are applied to the y axis in a horizontal bar chart.
|
||||
|
||||
The default horizontal bar configuration is specified in `Chart.defaults.horizontalBar`.
|
||||
|
||||
## Internal data format
|
||||
|
||||
`{x, y, _custom}` where `_custom` is optional object defining stacked bar properties: `{start, end, barStart, barEnd, min, max}`. `start` and `end` are the input values. Those two are repeated in `barStart` (closer to origin), `barEnd` (further from origin), `min` and `max`.
|
||||
|
||||
@@ -79,7 +79,7 @@ Global rectangle options: `Chart.defaults.elements.rectangle`.
|
||||
| `backgroundColor` | `Color` | `Chart.defaults.color` | Bar fill color.
|
||||
| `borderWidth` | `number` | `0` | Bar stroke width.
|
||||
| `borderColor` | `Color` | `Chart.defaults.color` | Bar stroke color.
|
||||
| `borderSkipped` | `string` | `'bottom'` | Skipped (excluded) border: `'bottom'`, `'left'`, `'top'` or `'right'`.
|
||||
| `borderSkipped` | `string` | `'start'` | Skipped (excluded) border: `'start'`, `'end'`, `'bottom'`, `'left'`, `'top'` or `'right'`.
|
||||
|
||||
## Arc Configuration
|
||||
|
||||
|
||||
@@ -71,7 +71,6 @@ The built in controller types are:
|
||||
|
||||
* `Chart.controllers.line`
|
||||
* `Chart.controllers.bar`
|
||||
* `Chart.controllers.horizontalBar`
|
||||
* `Chart.controllers.radar`
|
||||
* `Chart.controllers.doughnut`
|
||||
* `Chart.controllers.polarArea`
|
||||
|
||||
@@ -7,6 +7,7 @@ When configuring interaction with the graph via hover or tooltips, a number of d
|
||||
The modes are detailed below and how they behave in conjunction with the `intersect` setting.
|
||||
|
||||
## point
|
||||
|
||||
Finds all of the items that intersect the point.
|
||||
|
||||
```javascript
|
||||
@@ -22,6 +23,7 @@ var chart = new Chart(ctx, {
|
||||
```
|
||||
|
||||
## nearest
|
||||
|
||||
Gets the items that are at the nearest distance to the point. The nearest item is determined based on the distance to the center of the chart item (point, bar). You can use the `axis` setting to define which directions are used in distance calculation. If `intersect` is true, this is only triggered when the mouse position intersects an item in the graph. This is very useful for combo charts where points are hidden behind bars.
|
||||
|
||||
```javascript
|
||||
@@ -37,6 +39,7 @@ var chart = new Chart(ctx, {
|
||||
```
|
||||
|
||||
## index
|
||||
|
||||
Finds item at the same index. If the `intersect` setting is true, the first intersecting item is used to determine the index in the data. If `intersect` false the nearest item, in the x direction, is used to determine the index.
|
||||
|
||||
```javascript
|
||||
@@ -55,7 +58,7 @@ To use index mode in a chart like the horizontal bar chart, where we search alon
|
||||
|
||||
```javascript
|
||||
var chart = new Chart(ctx, {
|
||||
type: 'horizontalBar',
|
||||
type: 'bar',
|
||||
data: data,
|
||||
options: {
|
||||
tooltips: {
|
||||
|
||||
@@ -21,6 +21,10 @@ Chart.js 3.0 introduces a number of breaking changes. Chart.js 2.0 was released
|
||||
* Chart.js is no longer providing the `Chart.bundle.js` and `Chart.bundle.min.js`. Please see the [installation](installation.md) and [integration](integration.md) docs for details on the recommended way to setup Chart.js if you were using these builds.
|
||||
* `moment` is no longer specified as an npm dependency. If you are using the time scale, you must include one of [the available adapters](https://github.com/chartjs/awesome#adapters) and corresponding date library. You no longer need to exclude moment from your build.
|
||||
|
||||
### Chart types
|
||||
|
||||
* `horizontalBar` chart type was removed. Horizontal bar charts can be configured using the new [`indexAxis`](../charts/bar.md#general) option
|
||||
|
||||
### Options
|
||||
|
||||
A number of changes were made to the configuration options passed to the `Chart` constructor. Those changes are documented below.
|
||||
@@ -304,6 +308,10 @@ The following properties and methods were removed:
|
||||
The following private APIs were removed.
|
||||
|
||||
* `Chart.data.datasets[datasetIndex]._meta`
|
||||
* `DatasetController._getIndexScaleId`
|
||||
* `DatasetController._getIndexScale`
|
||||
* `DatasetController._getValueScaleId`
|
||||
* `DatasetController._getValueScale`
|
||||
* `Element._ctx`
|
||||
* `Element._model`
|
||||
* `Element._view`
|
||||
|
||||
@@ -62,9 +62,10 @@
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById('canvas').getContext('2d');
|
||||
window.myHorizontalBar = new Chart(ctx, {
|
||||
type: 'horizontalBar',
|
||||
type: 'bar',
|
||||
data: horizontalBarChartData,
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
// Elements options apply to all of the options unless overridden in a dataset
|
||||
// In this case, we are setting the border of each horizontal bar to be 2px wide
|
||||
elements: {
|
||||
|
||||
@@ -22,14 +22,14 @@ defaults.set('bar', {
|
||||
},
|
||||
|
||||
scales: {
|
||||
x: {
|
||||
_index_: {
|
||||
type: 'category',
|
||||
offset: true,
|
||||
gridLines: {
|
||||
offsetGridLines: true
|
||||
}
|
||||
},
|
||||
y: {
|
||||
_value_: {
|
||||
type: 'linear',
|
||||
beginAtZero: true,
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
import BarController from './controller.bar';
|
||||
import defaults from '../core/core.defaults';
|
||||
|
||||
defaults.set('horizontalBar', {
|
||||
hover: {
|
||||
mode: 'index',
|
||||
axis: 'y'
|
||||
},
|
||||
|
||||
scales: {
|
||||
x: {
|
||||
type: 'linear',
|
||||
beginAtZero: true
|
||||
},
|
||||
y: {
|
||||
type: 'category',
|
||||
offset: true,
|
||||
gridLines: {
|
||||
offsetGridLines: true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
datasets: {
|
||||
categoryPercentage: 0.8,
|
||||
barPercentage: 0.9
|
||||
},
|
||||
|
||||
elements: {
|
||||
rectangle: {
|
||||
borderSkipped: 'left'
|
||||
}
|
||||
},
|
||||
|
||||
tooltips: {
|
||||
axis: 'y'
|
||||
}
|
||||
});
|
||||
|
||||
export default class HorizontalBarController extends BarController {
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
getValueScaleId() {
|
||||
return this._cachedMeta.xAxisID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
getIndexScaleId() {
|
||||
return this._cachedMeta.yAxisID;
|
||||
}
|
||||
}
|
||||
@@ -14,10 +14,10 @@ defaults.set('line', {
|
||||
},
|
||||
|
||||
scales: {
|
||||
x: {
|
||||
_index_: {
|
||||
type: 'category',
|
||||
},
|
||||
y: {
|
||||
_value_: {
|
||||
type: 'linear',
|
||||
},
|
||||
}
|
||||
|
||||
@@ -14,6 +14,9 @@ defaults.set('polarArea', {
|
||||
animateScale: true
|
||||
},
|
||||
aspectRatio: 1,
|
||||
datasets: {
|
||||
indexAxis: 'r'
|
||||
},
|
||||
scales: {
|
||||
r: {
|
||||
type: 'radialLinear',
|
||||
@@ -90,20 +93,6 @@ export default class PolarAreaController extends DatasetController {
|
||||
this.outerRadius = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
getIndexScaleId() {
|
||||
return this._cachedMeta.rAxisID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
getValueScaleId() {
|
||||
return this._cachedMeta.rAxisID;
|
||||
}
|
||||
|
||||
update(mode) {
|
||||
const arcs = this._cachedMeta.data;
|
||||
|
||||
@@ -136,7 +125,7 @@ export default class PolarAreaController extends DatasetController {
|
||||
const dataset = me.getDataset();
|
||||
const opts = chart.options;
|
||||
const animationOpts = opts.animation;
|
||||
const scale = chart.scales.r;
|
||||
const scale = me._cachedMeta.rScale;
|
||||
const centerX = scale.xCenter;
|
||||
const centerY = scale.yCenter;
|
||||
const datasetStartAngle = getStartAngleRadians(opts.startAngle);
|
||||
|
||||
@@ -11,6 +11,9 @@ defaults.set('radar', {
|
||||
type: 'radialLinear',
|
||||
}
|
||||
},
|
||||
datasets: {
|
||||
indexAxis: 'r'
|
||||
},
|
||||
elements: {
|
||||
line: {
|
||||
fill: 'start',
|
||||
@@ -21,20 +24,6 @@ defaults.set('radar', {
|
||||
|
||||
export default class RadarController extends DatasetController {
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
getIndexScaleId() {
|
||||
return this._cachedMeta.rAxisID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
getValueScaleId() {
|
||||
return this._cachedMeta.rAxisID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
@@ -73,7 +62,7 @@ export default class RadarController extends DatasetController {
|
||||
updateElements(points, start, mode) {
|
||||
const me = this;
|
||||
const dataset = me.getDataset();
|
||||
const scale = me.chart.scales.r;
|
||||
const scale = me._cachedMeta.rScale;
|
||||
const reset = mode === 'reset';
|
||||
let i;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
export {default as bar} from './controller.bar';
|
||||
export {default as bubble} from './controller.bubble';
|
||||
export {default as doughnut} from './controller.doughnut';
|
||||
export {default as horizontalBar} from './controller.horizontalBar';
|
||||
export {default as line} from './controller.line';
|
||||
export {default as polarArea} from './controller.polarArea';
|
||||
export {default as pie} from './controller.pie';
|
||||
|
||||
@@ -18,38 +18,62 @@ import {version} from '../../package.json';
|
||||
*/
|
||||
|
||||
|
||||
function getIndexAxis(type, options) {
|
||||
const typeDefaults = defaults[type] || {};
|
||||
const datasetDefaults = typeDefaults.datasets || {};
|
||||
const typeOptions = options[type] || {};
|
||||
const datasetOptions = typeOptions.datasets || {};
|
||||
return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x';
|
||||
}
|
||||
|
||||
function getAxisFromDefaultScaleID(id, indexAxis) {
|
||||
let axis = id;
|
||||
if (id === '_index_') {
|
||||
axis = indexAxis;
|
||||
} else if (id === '_value_') {
|
||||
axis = indexAxis === 'x' ? 'y' : 'x';
|
||||
}
|
||||
return axis;
|
||||
}
|
||||
|
||||
function getDefaultScaleIDFromAxis(axis, indexAxis) {
|
||||
return axis === indexAxis ? '_index_' : '_value_';
|
||||
}
|
||||
|
||||
function mergeScaleConfig(config, options) {
|
||||
options = options || {};
|
||||
const chartDefaults = defaults[config.type] || {scales: {}};
|
||||
const configScales = options.scales || {};
|
||||
const chartIndexAxis = getIndexAxis(config.type, options);
|
||||
const firstIDs = {};
|
||||
const scales = {};
|
||||
|
||||
// First figure out first scale id's per axis.
|
||||
// Note: for now, axis is determined from first letter of scale id!
|
||||
Object.keys(configScales).forEach(id => {
|
||||
const axis = id[0];
|
||||
const scaleConf = configScales[id];
|
||||
const axis = determineAxis(id, scaleConf);
|
||||
const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis);
|
||||
firstIDs[axis] = firstIDs[axis] || id;
|
||||
scales[id] = mergeIf({}, [configScales[id], chartDefaults.scales[axis]]);
|
||||
scales[id] = mergeIf({axis}, [scaleConf, chartDefaults.scales[axis], chartDefaults.scales[defaultId]]);
|
||||
});
|
||||
|
||||
// Backward compatibility
|
||||
if (options.scale) {
|
||||
scales[options.scale.id || 'r'] = mergeIf({}, [options.scale, chartDefaults.scales.r]);
|
||||
scales[options.scale.id || 'r'] = mergeIf({axis: 'r'}, [options.scale, chartDefaults.scales.r]);
|
||||
firstIDs.r = firstIDs.r || options.scale.id || 'r';
|
||||
}
|
||||
|
||||
// Then merge dataset defaults to scale configs
|
||||
config.data.datasets.forEach(dataset => {
|
||||
const datasetDefaults = defaults[dataset.type || config.type] || {scales: {}};
|
||||
const type = dataset.type || config.type;
|
||||
const indexAxis = dataset.indexAxis || getIndexAxis(type, options);
|
||||
const datasetDefaults = defaults[type] || {};
|
||||
const defaultScaleOptions = datasetDefaults.scales || {};
|
||||
Object.keys(defaultScaleOptions).forEach(defaultID => {
|
||||
const id = dataset[defaultID + 'AxisID'] || firstIDs[defaultID] || defaultID;
|
||||
const axis = getAxisFromDefaultScaleID(defaultID, indexAxis);
|
||||
const id = dataset[axis + 'AxisID'] || firstIDs[axis] || axis;
|
||||
scales[id] = scales[id] || {};
|
||||
mergeIf(scales[id], [
|
||||
configScales[id],
|
||||
defaultScaleOptions[defaultID]
|
||||
]);
|
||||
mergeIf(scales[id], [{axis}, configScales[id], defaultScaleOptions[defaultID]]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -127,6 +151,22 @@ function positionIsHorizontal(position, axis) {
|
||||
return position === 'top' || position === 'bottom' || (KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x');
|
||||
}
|
||||
|
||||
function axisFromPosition(position) {
|
||||
if (position === 'top' || position === 'bottom') {
|
||||
return 'x';
|
||||
}
|
||||
if (position === 'left' || position === 'right') {
|
||||
return 'y';
|
||||
}
|
||||
}
|
||||
|
||||
function determineAxis(id, scaleOptions) {
|
||||
if (id === 'x' || id === 'y' || id === 'r') {
|
||||
return id;
|
||||
}
|
||||
return scaleOptions.axis || axisFromPosition(scaleOptions.position) || id.charAt(0).toLowerCase();
|
||||
}
|
||||
|
||||
function compare2Level(l1, l2) {
|
||||
return function(a, b) {
|
||||
return a[l1] === b[l1]
|
||||
@@ -373,12 +413,13 @@ class Chart {
|
||||
|
||||
if (scaleOpts) {
|
||||
items = items.concat(
|
||||
Object.keys(scaleOpts).map((axisID) => {
|
||||
const axisOptions = scaleOpts[axisID];
|
||||
const isRadial = axisID.charAt(0).toLowerCase() === 'r';
|
||||
const isHorizontal = axisID.charAt(0).toLowerCase() === 'x';
|
||||
Object.keys(scaleOpts).map((id) => {
|
||||
const scaleOptions = scaleOpts[id];
|
||||
const axis = determineAxis(id, scaleOptions);
|
||||
const isRadial = axis === 'r';
|
||||
const isHorizontal = axis === 'x';
|
||||
return {
|
||||
options: axisOptions,
|
||||
options: scaleOptions,
|
||||
dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left',
|
||||
dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear'
|
||||
};
|
||||
@@ -389,9 +430,10 @@ class Chart {
|
||||
each(items, (item) => {
|
||||
const scaleOptions = item.options;
|
||||
const id = scaleOptions.id;
|
||||
const axis = determineAxis(id, scaleOptions);
|
||||
const scaleType = valueOrDefault(scaleOptions.type, item.dtype);
|
||||
|
||||
if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, scaleOptions.axis || id[0]) !== positionIsHorizontal(item.dposition)) {
|
||||
if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) {
|
||||
scaleOptions.position = item.dposition;
|
||||
}
|
||||
|
||||
@@ -485,6 +527,7 @@ class Chart {
|
||||
meta = me.getDatasetMeta(i);
|
||||
}
|
||||
meta.type = type;
|
||||
meta.indexAxis = dataset.indexAxis || getIndexAxis(type, me.options);
|
||||
meta.order = dataset.order || 0;
|
||||
me._updateMetasetIndex(meta, i);
|
||||
meta.label = '' + dataset.label;
|
||||
|
||||
@@ -188,14 +188,19 @@ export default class DatasetController {
|
||||
const meta = me._cachedMeta;
|
||||
const dataset = me.getDataset();
|
||||
|
||||
const xid = meta.xAxisID = dataset.xAxisID || getFirstScaleId(chart, 'x');
|
||||
const yid = meta.yAxisID = dataset.yAxisID || getFirstScaleId(chart, 'y');
|
||||
const rid = meta.rAxisID = dataset.rAxisID || getFirstScaleId(chart, 'r');
|
||||
const chooseId = (axis, x, y, r) => axis === 'x' ? x : axis === 'r' ? r : y;
|
||||
|
||||
const xid = meta.xAxisID = valueOrDefault(dataset.xAxisID, getFirstScaleId(chart, 'x'));
|
||||
const yid = meta.yAxisID = valueOrDefault(dataset.yAxisID, getFirstScaleId(chart, 'y'));
|
||||
const rid = meta.rAxisID = valueOrDefault(dataset.rAxisID, getFirstScaleId(chart, 'r'));
|
||||
const indexAxis = meta.indexAxis;
|
||||
const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid);
|
||||
const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid);
|
||||
meta.xScale = me.getScaleForId(xid);
|
||||
meta.yScale = me.getScaleForId(yid);
|
||||
meta.rScale = me.getScaleForId(rid);
|
||||
meta.iScale = me._getIndexScale();
|
||||
meta.vScale = me._getValueScale();
|
||||
meta.iScale = me.getScaleForId(iid);
|
||||
meta.vScale = me.getScaleForId(vid);
|
||||
}
|
||||
|
||||
getDataset() {
|
||||
@@ -214,34 +219,6 @@ export default class DatasetController {
|
||||
return this.chart.scales[scaleID];
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
getValueScaleId() {
|
||||
return this._cachedMeta.yAxisID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
getIndexScaleId() {
|
||||
return this._cachedMeta.xAxisID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_getValueScale() {
|
||||
return this.getScaleForId(this.getValueScaleId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_getIndexScale() {
|
||||
return this.getScaleForId(this.getIndexScaleId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
||||
@@ -118,13 +118,25 @@ function fastPathSegment(ctx, line, segment, params) {
|
||||
let countX = 0;
|
||||
let i, point, prevX, minY, maxY, lastY;
|
||||
|
||||
const pointIndex = (index) => (start + (reverse ? ilen - index : index)) % count;
|
||||
const drawX = () => {
|
||||
if (minY !== maxY) {
|
||||
// Draw line to maxY and minY, using the average x-coordinate
|
||||
ctx.lineTo(avgX, maxY);
|
||||
ctx.lineTo(avgX, minY);
|
||||
// Line to y-value of last point in group. So the line continues
|
||||
// from correct position. Not using move, to have solid path.
|
||||
ctx.lineTo(avgX, lastY);
|
||||
}
|
||||
};
|
||||
|
||||
if (move) {
|
||||
point = points[(start + (reverse ? ilen : 0)) % count];
|
||||
point = points[pointIndex(0)];
|
||||
ctx.moveTo(point.x, point.y);
|
||||
}
|
||||
|
||||
for (i = 0; i <= ilen; ++i) {
|
||||
point = points[(start + (reverse ? ilen - i : i)) % count];
|
||||
point = points[pointIndex(i)];
|
||||
|
||||
if (point.skip) {
|
||||
// If there is a skipped point inside a segment, spanGaps must be true
|
||||
@@ -145,14 +157,7 @@ function fastPathSegment(ctx, line, segment, params) {
|
||||
// For first point in group, countX is `0`, so average will be `x` / 1.
|
||||
avgX = (countX * avgX + x) / ++countX;
|
||||
} else {
|
||||
if (minY !== maxY) {
|
||||
// Draw line to maxY and minY, using the average x-coordinate
|
||||
ctx.lineTo(avgX, maxY);
|
||||
ctx.lineTo(avgX, minY);
|
||||
// Line to y-value of last point in group. So the line continues
|
||||
// from correct position. Not using move, to have solid path.
|
||||
ctx.lineTo(avgX, lastY);
|
||||
}
|
||||
drawX();
|
||||
// Draw line to next x-position, using the first (or only)
|
||||
// y-value in that group
|
||||
ctx.lineTo(x, y);
|
||||
@@ -164,6 +169,7 @@ function fastPathSegment(ctx, line, segment, params) {
|
||||
// Keep track of the last y-value in group
|
||||
lastY = y;
|
||||
}
|
||||
drawX();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@ import {isObject} from '../helpers/helpers.core';
|
||||
|
||||
const scope = 'elements.rectangle';
|
||||
defaults.set(scope, {
|
||||
borderSkipped: 'bottom',
|
||||
borderSkipped: 'start',
|
||||
borderWidth: 0
|
||||
});
|
||||
|
||||
@@ -39,10 +39,6 @@ function getBarBounds(bar, useFinalPosition) {
|
||||
return {left, top, right, bottom};
|
||||
}
|
||||
|
||||
function swap(orig, v1, v2) {
|
||||
return orig === v1 ? v2 : orig === v2 ? v1 : orig;
|
||||
}
|
||||
|
||||
function parseBorderSkipped(bar) {
|
||||
let edge = bar.options.borderSkipped;
|
||||
const res = {};
|
||||
@@ -51,18 +47,32 @@ function parseBorderSkipped(bar) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (bar.horizontal) {
|
||||
if (bar.base > bar.x) {
|
||||
edge = swap(edge, 'left', 'right');
|
||||
}
|
||||
} else if (bar.base < bar.y) {
|
||||
edge = swap(edge, 'bottom', 'top');
|
||||
}
|
||||
edge = bar.horizontal
|
||||
? parseEdge(edge, 'left', 'right', bar.base > bar.x)
|
||||
: parseEdge(edge, 'bottom', 'top', bar.base < bar.y);
|
||||
|
||||
res[edge] = true;
|
||||
return res;
|
||||
}
|
||||
|
||||
function parseEdge(edge, a, b, reverse) {
|
||||
if (reverse) {
|
||||
edge = swap(edge, a, b);
|
||||
edge = startEnd(edge, b, a);
|
||||
} else {
|
||||
edge = startEnd(edge, a, b);
|
||||
}
|
||||
return edge;
|
||||
}
|
||||
|
||||
function swap(orig, v1, v2) {
|
||||
return orig === v1 ? v2 : orig === v2 ? v1 : orig;
|
||||
}
|
||||
|
||||
function startEnd(v, start, end) {
|
||||
return v === 'start' ? start : v === 'end' ? end : v;
|
||||
}
|
||||
|
||||
function skipOrLimit(skip, value, min, max) {
|
||||
return skip ? 0 : Math.max(Math.min(value, max), min);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module.exports = {
|
||||
config: {
|
||||
type: 'horizontalBar',
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ['a', 'b', 'c'],
|
||||
datasets: [
|
||||
@@ -17,6 +17,7 @@ module.exports = {
|
||||
options: {
|
||||
legend: false,
|
||||
title: false,
|
||||
indexAxis: 'y',
|
||||
scales: {
|
||||
x: {display: false, min: 0},
|
||||
y: {display: false, stacked: true}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"config": {
|
||||
"type": "horizontalBar",
|
||||
"type": "bar",
|
||||
"data": {
|
||||
"labels": ["2030", "2034", "2038", "2042"],
|
||||
"datasets": [{
|
||||
@@ -17,6 +17,7 @@
|
||||
"options": {
|
||||
"title": false,
|
||||
"legend": false,
|
||||
"indexAxis": "y",
|
||||
"scales": {
|
||||
"x": {
|
||||
"display": false,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"config": {
|
||||
"type": "horizontalBar",
|
||||
"type": "bar",
|
||||
"data": {
|
||||
"labels": ["2030", "2034", "2038", "2042"],
|
||||
"datasets": [{
|
||||
@@ -17,6 +17,7 @@
|
||||
"options": {
|
||||
"title": false,
|
||||
"legend": false,
|
||||
"indexAxis": "y",
|
||||
"scales": {
|
||||
"x": {
|
||||
"display": false,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module.exports = {
|
||||
threshold: 0.01,
|
||||
config: {
|
||||
type: 'horizontalBar',
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: [0, 1, 2, 3, 4, 5],
|
||||
datasets: [
|
||||
@@ -13,13 +13,14 @@ module.exports = {
|
||||
{
|
||||
// option in element (fallback)
|
||||
data: [0, 5, 10, null, -10, -5],
|
||||
borderSkipped: false,
|
||||
borderSkipped: false
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
legend: false,
|
||||
title: false,
|
||||
indexAxis: 'y',
|
||||
elements: {
|
||||
rectangle: {
|
||||
backgroundColor: '#AAAAAA80',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"config": {
|
||||
"type": "horizontalBar",
|
||||
"type": "bar",
|
||||
"data": {
|
||||
"labels": ["\u25C0", "\u25A0", "\u25C6", "\u25CF"],
|
||||
"datasets": [{
|
||||
@@ -10,6 +10,7 @@
|
||||
"options": {
|
||||
"legend": false,
|
||||
"title": false,
|
||||
"indexAxis": "y",
|
||||
"scales": {
|
||||
"x": {
|
||||
"ticks": {
|
||||
|
||||
3
test/fixtures/core.scale/tick-drawing.json
vendored
3
test/fixtures/core.scale/tick-drawing.json
vendored
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"config": {
|
||||
"type": "horizontalBar",
|
||||
"type": "bar",
|
||||
"data": {
|
||||
"labels": ["January", "February", "March", "April", "May", "June", "July"],
|
||||
"datasets": []
|
||||
@@ -8,6 +8,7 @@
|
||||
"options": {
|
||||
"legend": false,
|
||||
"title": false,
|
||||
"indexAxis": "y",
|
||||
"scales": {
|
||||
"x": {
|
||||
"type": "category",
|
||||
|
||||
41
test/fixtures/mixed/bar+line.js
vendored
Normal file
41
test/fixtures/mixed/bar+line.js
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
module.exports = {
|
||||
config: {
|
||||
data: {
|
||||
datasets: [
|
||||
{
|
||||
type: 'line',
|
||||
data: [6, 16, 3, 19],
|
||||
borderColor: '#0000ff',
|
||||
fill: false
|
||||
},
|
||||
{
|
||||
type: 'bar',
|
||||
data: [5, 20, 1, 10],
|
||||
backgroundColor: '#00ff00',
|
||||
borderColor: '#ff0000'
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
legend: false,
|
||||
title: false,
|
||||
scales: {
|
||||
horz: {
|
||||
position: 'top'
|
||||
},
|
||||
vert: {
|
||||
axis: 'y',
|
||||
labels: ['a', 'b', 'c', 'd']
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
options: {
|
||||
spriteText: true,
|
||||
canvas: {
|
||||
height: 256,
|
||||
width: 512
|
||||
}
|
||||
}
|
||||
};
|
||||
BIN
test/fixtures/mixed/bar+line.png
vendored
Normal file
BIN
test/fixtures/mixed/bar+line.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -1,7 +1,7 @@
|
||||
module.exports = {
|
||||
threshold: 0.01,
|
||||
config: {
|
||||
type: 'horizontalBar',
|
||||
type: 'bar',
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [10, 5, 0, 25, 78]
|
||||
@@ -9,6 +9,7 @@ module.exports = {
|
||||
labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5']
|
||||
},
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
legend: false,
|
||||
title: false,
|
||||
elements: {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -395,7 +395,7 @@ describe('Chart.controllers.radar', function() {
|
||||
}
|
||||
});
|
||||
|
||||
var controller = chart.getDatasetMeta(0).controller;
|
||||
expect(controller.getValueScaleId()).toBe('test');
|
||||
var meta = chart.getDatasetMeta(0);
|
||||
expect(meta.vScale.id).toBe('test');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -153,8 +153,11 @@ describe('Core.Interaction', function() {
|
||||
|
||||
it ('axis: y gets correct items', function() {
|
||||
var chart = window.acquireChart({
|
||||
type: 'horizontalBar',
|
||||
data: data
|
||||
type: 'bar',
|
||||
data: data,
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
}
|
||||
});
|
||||
|
||||
var meta0 = chart.getDatasetMeta(0);
|
||||
@@ -271,8 +274,11 @@ describe('Core.Interaction', function() {
|
||||
|
||||
it ('axis: x gets correct items', function() {
|
||||
var chart = window.acquireChart({
|
||||
type: 'horizontalBar',
|
||||
data: data
|
||||
type: 'bar',
|
||||
data: data,
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
}
|
||||
});
|
||||
|
||||
var evt = {
|
||||
|
||||
3
test/specs/mixed.tests.js
Normal file
3
test/specs/mixed.tests.js
Normal file
@@ -0,0 +1,3 @@
|
||||
describe('Mixed charts', function() {
|
||||
describe('auto', jasmine.fixture.specs('mixed'));
|
||||
});
|
||||
@@ -794,7 +794,7 @@ describe('Core.Tooltip', function() {
|
||||
jasmine.triggerMouseEvent(chart, 'mousemove', point0);
|
||||
});
|
||||
|
||||
['line', 'bar', 'horizontalBar'].forEach(function(type) {
|
||||
['line', 'bar'].forEach(function(type) {
|
||||
it('Should have dataPoints in a ' + type + ' chart', function(done) {
|
||||
var chart = window.acquireChart({
|
||||
type: type,
|
||||
|
||||
@@ -466,11 +466,9 @@ describe('Category scale tests', function() {
|
||||
|
||||
it('Should get the correct pixel for an object value in a horizontal bar chart', function() {
|
||||
var chart = window.acquireChart({
|
||||
type: 'horizontalBar',
|
||||
type: 'bar',
|
||||
data: {
|
||||
datasets: [{
|
||||
xAxisID: 'x',
|
||||
yAxisID: 'y',
|
||||
data: [
|
||||
{x: 10, y: 0},
|
||||
{x: 5, y: 1},
|
||||
@@ -482,6 +480,7 @@ describe('Category scale tests', function() {
|
||||
labels: [0, 1, 2, 3]
|
||||
},
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
scales: {
|
||||
x: {
|
||||
type: 'linear',
|
||||
|
||||
@@ -1005,9 +1005,10 @@ describe('Linear Scale', function() {
|
||||
};
|
||||
|
||||
var chart = window.acquireChart({
|
||||
type: 'horizontalBar',
|
||||
type: 'bar',
|
||||
data: barData,
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
scales: {
|
||||
x: {
|
||||
stacked: true
|
||||
@@ -1041,9 +1042,10 @@ describe('Linear Scale', function() {
|
||||
};
|
||||
|
||||
var chart = window.acquireChart({
|
||||
type: 'horizontalBar',
|
||||
type: 'bar',
|
||||
data: barData,
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
scales: {
|
||||
x: {
|
||||
min: 20
|
||||
@@ -1067,9 +1069,10 @@ describe('Linear Scale', function() {
|
||||
};
|
||||
|
||||
var chart = window.acquireChart({
|
||||
type: 'horizontalBar',
|
||||
type: 'bar',
|
||||
data: barData,
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
scales: {
|
||||
x: {
|
||||
min: 0,
|
||||
@@ -1093,9 +1096,10 @@ describe('Linear Scale', function() {
|
||||
};
|
||||
|
||||
var chart = window.acquireChart({
|
||||
type: 'horizontalBar',
|
||||
type: 'bar',
|
||||
data: barData,
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
scales: {
|
||||
x: {
|
||||
min: -3000,
|
||||
@@ -1110,13 +1114,14 @@ describe('Linear Scale', function() {
|
||||
|
||||
it('Should get correct pixel values when horizontal', function() {
|
||||
var chart = window.acquireChart({
|
||||
type: 'horizontalBar',
|
||||
type: 'bar',
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [0.05, -25, 10, 15, 20, 25, 30, 35]
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
scales: {
|
||||
x: {
|
||||
type: 'linear',
|
||||
|
||||
@@ -828,14 +828,14 @@ describe('Logarithmic Scale tests', function() {
|
||||
];
|
||||
config.forEach(function(setup) {
|
||||
var scaleConfig = {};
|
||||
var type, chartStart, chartEnd;
|
||||
var indexAxis, chartStart, chartEnd;
|
||||
|
||||
if (setup.axis === 'x') {
|
||||
type = 'horizontalBar';
|
||||
indexAxis = 'y';
|
||||
chartStart = 'left';
|
||||
chartEnd = 'right';
|
||||
} else {
|
||||
type = 'bar';
|
||||
indexAxis = 'x';
|
||||
chartStart = 'bottom';
|
||||
chartEnd = 'top';
|
||||
}
|
||||
@@ -850,12 +850,13 @@ describe('Logarithmic Scale tests', function() {
|
||||
describe(description, function() {
|
||||
it('should define the correct axis limits', function() {
|
||||
var chart = window.acquireChart({
|
||||
type: type,
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ['category 1', 'category 2'],
|
||||
datasets: setup.data || data,
|
||||
},
|
||||
options: {
|
||||
indexAxis,
|
||||
scales: scaleConfig
|
||||
}
|
||||
});
|
||||
@@ -917,18 +918,6 @@ describe('Logarithmic Scale tests', function() {
|
||||
lastTick: 10,
|
||||
describe: 'empty dataset with stack option, without min/max'
|
||||
},
|
||||
{
|
||||
data: {
|
||||
datasets: [
|
||||
{data: [], stack: 'stack'},
|
||||
{data: [], stack: 'stack'},
|
||||
],
|
||||
},
|
||||
type: 'horizontalBar',
|
||||
firstTick: 1,
|
||||
lastTick: 10,
|
||||
describe: 'empty dataset with stack option, without min/max'
|
||||
},
|
||||
{
|
||||
dataset: [],
|
||||
scale: {min: 1},
|
||||
|
||||
Reference in New Issue
Block a user