From 30d09f47015e536d91dbb5dd606c2e1a3f38ac75 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sat, 17 Oct 2020 16:15:40 -0400 Subject: [PATCH] Bar chart base value overrides (#7904) * Bar chart base value overrides * Ensure that `base` is marked as indexable and scriptable in the docs --- docs/docs/charts/bar.mdx | 3 ++ src/controllers/controller.bar.js | 9 +++-- .../fixtures/controller.bar/bar-base-value.js | 31 ++++++++++++++++++ .../controller.bar/bar-base-value.png | Bin 0 -> 4536 bytes types/elements/index.d.ts | 5 +++ 5 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 test/fixtures/controller.bar/bar-base-value.js create mode 100644 test/fixtures/controller.bar/bar-base-value.png diff --git a/docs/docs/charts/bar.mdx b/docs/docs/charts/bar.mdx index 7d0bbbcaa..6fefb7f84 100644 --- a/docs/docs/charts/bar.mdx +++ b/docs/docs/charts/bar.mdx @@ -79,6 +79,7 @@ the color of the bars is generally set this way. | Name | Type | [Scriptable](../general/options.md#scriptable-options) | [Indexable](../general/options.md#indexable-options) | Default | ---- | ---- | :----: | :----: | ---- | [`backgroundColor`](#styling) | [`Color`](../general/colors.md) | Yes | Yes | `'rgba(0, 0, 0, 0.1)'` +| [`base`](#general) | `number` | Yes | Yes | | [`borderColor`](#styling) | [`Color`](../general/colors.md) | Yes | Yes | `'rgba(0, 0, 0, 0.1)'` | [`borderSkipped`](#borderskipped) | `string` | Yes | Yes | `'start'` | [`borderWidth`](#borderwidth) | number|object | Yes | Yes | `0` @@ -97,6 +98,7 @@ the color of the bars is generally set this way. | Name | Description | ---- | ---- +| `base` | Base value for the bar in data units along the value axis. If not set, defaults to the value axis base value. | `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. @@ -161,6 +163,7 @@ The bar chart accepts the following configuration from the associated dataset op | `barPercentage` | `number` | `0.9` | Percent (0-1) of the available width each bar should be within the category width. 1.0 will take the whole category width and put the bars right next to each other. [more...](#barpercentage-vs-categorypercentage) | `categoryPercentage` | `number` | `0.8` | Percent (0-1) of the available width each category should be within the sample width. [more...](#barpercentage-vs-categorypercentage) | `barThickness` | number|string | | Manually set width of each bar in pixels. If set to `'flex'`, it computes "optimal" sample widths that globally arrange bars side by side. If not set (default), bars are equally sized based on the smallest interval. [more...](#barthickness) +| `base` | `number` | | Base value for the bar in data units along the value axis. If not set, defaults to the value axis base value. | `maxBarThickness` | `number` | | Set this to ensure that bars are not sized thicker than this. | `minBarLength` | `number` | | Set this to ensure that bars have a minimum length in pixels. diff --git a/src/controllers/controller.bar.js b/src/controllers/controller.bar.js index aafe80856..173c649cb 100644 --- a/src/controllers/controller.bar.js +++ b/src/controllers/controller.bar.js @@ -404,9 +404,10 @@ export default class BarController extends DatasetController { const me = this; const meta = me._cachedMeta; const vScale = meta.vScale; - const minBarLength = options.minBarLength; + const {base: baseValue, minBarLength} = options; const parsed = me.getParsed(index); const custom = parsed._custom; + const floating = isFloatBar(custom); let value = parsed[vScale.axis]; let start = 0; let length = meta._stacked ? me.applyStack(vScale, parsed) : value; @@ -417,7 +418,7 @@ export default class BarController extends DatasetController { length = value; } - if (isFloatBar(custom)) { + if (floating) { value = custom.barStart; length = custom.barEnd - custom.barStart; // bars crossing origin are not stacked @@ -431,7 +432,8 @@ export default class BarController extends DatasetController { // So we don't try to draw so huge rectangles. // https://github.com/chartjs/Chart.js/issues/5247 // TODO: use borderWidth instead (need to move the parsing from rectangle) - let base = _limitValue(vScale.getPixelForValue(start), + const startValue = !isNullOrUndef(baseValue) && !floating ? baseValue : start; + let base = _limitValue(vScale.getPixelForValue(startValue), vScale._startPixel - 10, vScale._endPixel + 10); @@ -521,6 +523,7 @@ BarController.defaults = { 'borderWidth', 'barPercentage', 'barThickness', + 'base', 'categoryPercentage', 'maxBarThickness', 'minBarLength', diff --git a/test/fixtures/controller.bar/bar-base-value.js b/test/fixtures/controller.bar/bar-base-value.js new file mode 100644 index 000000000..0bb96dc6e --- /dev/null +++ b/test/fixtures/controller.bar/bar-base-value.js @@ -0,0 +1,31 @@ +module.exports = { + config: { + type: 'bar', + data: { + labels: [0, 1, 3, 4], + datasets: [ + { + data: [5, 20, 10, 11], + base: 10, + backgroundColor: '#00ff00', + borderColor: '#ff0000', + borderWidth: 2, + } + ] + }, + options: { + legend: false, + title: false, + scales: { + x: {display: false}, + y: {display: false} + } + } + }, + options: { + canvas: { + height: 256, + width: 512 + } + } +}; diff --git a/test/fixtures/controller.bar/bar-base-value.png b/test/fixtures/controller.bar/bar-base-value.png new file mode 100644 index 0000000000000000000000000000000000000000..5d5986bdf86a3398271f10de14c81fd10b4b07bf GIT binary patch literal 4536 zc-rljT~t$77RS%MBs5%$CYV&E7J?K>LX`|wkwt-vD5z5)6);j(NL+^Mj23kiuqblT z0(C|zodR058kRGNfQBMcph}{S4kKOaEY~t1NI;erC&;IP$mi_jZO(m}hd%Uyyd?W( z?|t^!=l9?D98<(Zxl-;FLdbQ)`n8)7BH<^2c+T*3r||xEgap|e)`rI)NPgAv^y~MO z0&Z7&eH0Zwn&$D1Z?~YKZrxW0kbGn0qJq51vqM4GYFjKlB|$2c`H$Uyf4ZzwH677K zkmvQ55vS!nZh_SGpRQyCPG1W1rWvE2vUv*T-HqS~nS6QYA;|ohEPFj;+|839kAi&O zWIPJJVK{6X92)QUTCo2cwa8}c9yd+In$$uxk4KPWlmv}Y<5LevihdEUKmqs5_&fLt zMfgC&qU1IHB!z-So5#Ci>7!~mV5rn07u-ji^_2(xH_-r#;++FB@)fz zGi!8fX+q+XnHkO1eA?1pb z{y46t$OKM$DW?LQD(ZhJNkA`lsgv6R(W32fybodXuF|*C;}O~1#I6FIw#M;ZgHuT2 ziPQ>oe0bbhe0wLABZC@b{S7H1CMd~_w7a6c9xm0PTA$EbJt^l*{HG?A{CPDb3#W-4 z>w~H&mtl#%jfeH^hjY}*5t^tJpuTEu+P`O9Apa`C`E5sl|hCbVBdW!^gUS{u@MiIm^7 zi0C|%kW2ulgpPeJGPJMGU*GpGbNs55;|>kVD{=~!Awp|rR{>7dQcfl~ovVrpOhA!e zWH}Xfugs;38B!q{>!_iOXD{zY0d+vYd(GaPTip5y z!4psLmoh%f)bN?~GlN86Rb&;UYkIj2kiQc~1)L3-_ zt-vIb#W@uYTRH|^bbI~!G-a$Ed}RF|X|b01p+(v_UJ;<^6CSI-gg%}F{lZ8ed-DvA z918?eu>93Z7S@?u{3u_w_)R#o^cKjf0-P{9lL4Ls0FRFj#or0}v5J&$w*WksrJN@K zPu)NAM-xzt+0MHwCJAb}nf%aq6lS2zx9fKL>b{o<&T^P(-zUxy9RvOAu6p zNpNz1mM?2+Q7qNRut?8ps#mfCffQWgA{N%*gdOF?@VzFMP(cuQ6-_KUO#n}F94{UO zk+Ao{vP$%G8%)z}Ai-4t&$6M?ED__?syt~GXmAOFYA^{NZfu&*np#|z>U~+HhpIdL zSb=)B#3>fmde%{9eUV~j2^9o^S7Bz+34*}iNdV6eAi*;LPl@ee6J_N0Rkn=t(s7)C4og|_yeEaQ{8hOFuD$USh#Qr{Tu*)Ku7&*q3jjN2Z6StljON z`Y^T0dNIRfH6P5#aAXfAc%e=d&2KM1!#ONP=R4IilW;e(M28JWsox(Qx^2A;ccTnb zS`cAd5+3F**h9*1jb|@Nuy>(jxej%trVXfNjw{nw4E$Gtv|FMZB50!CX`mo10d?|T zJXisnzT0L$y`pxmkZHf%KlOWVS8}+)6B-n`<@?`KNXxc4Og8E-7_Bo;yw$bJH+vm} z2-4s`SUuyX;fhDfrH&cH7Y|;WBS9^0n^6h(MY;=Lyr-NY_w0}x(vm1+jj>}nL2~Ab z6lkt%B(de4~{6XG`OCc&!prus7MZPu}p^+yB`PpX1(41 z04^L5%7GlIC!wf(xT@wm_kb;T*ew8kN=}eHhhw=?prZ8V>e=OIm!Dn!f0s8#%rTY* zA1?mU+TZ9=@>J=fmBKQ7n<^)N%6s@tW9ZfUF!h6Werp%{O6sF3bf{o;`V!hc3)Gbi zIe2a9PJerZcrcixn13FH=Nz68%E~QG`p#iU&^f~4p^)g1FfTR5Vd&5SXZWHSx)fd) z3mc1F>;^-2EfPDD=fXtV+PitF!=RY$%xvP>#J_f8;|wZ}*pw8vLjMth&xUm|Yp<-) G9QiM~Q5ItW literal 0 Hc-jL100001 diff --git a/types/elements/index.d.ts b/types/elements/index.d.ts index c58795cc2..7ca94de02 100644 --- a/types/elements/index.d.ts +++ b/types/elements/index.d.ts @@ -253,6 +253,11 @@ export interface IRectangleProps { } export interface IRectangleOptions extends ICommonOptions { + /** + * The base value for the bar in data units along the value axis. + */ + base: number; + /** * Skipped (excluded) border: 'start', 'end', 'bottom', 'left', 'top' or 'right'. * @default 'start' -- 2.47.2