mirror of
https://github.com/chartjs/Chart.js.git
synced 2024-10-06 12:19:08 +02:00
Title plugin cleanup (#8104)
* Title plugin cleanup * more cleanup * cc * center formula * Fix / update sample * Restore functionality on RTL page
This commit is contained in:
parent
913a01a3a6
commit
5faffae81b
@ -15,6 +15,10 @@
|
|||||||
width: 500px;
|
width: 500px;
|
||||||
margin-left: 40px;
|
margin-left: 40px;
|
||||||
margin-right: 40px;
|
margin-right: 40px;
|
||||||
|
box-sizing: content-box;
|
||||||
|
border: 1px solid rgb(240, 240, 240);
|
||||||
|
border-radius: 4px;
|
||||||
|
margin: 4px;
|
||||||
}
|
}
|
||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -45,6 +49,24 @@
|
|||||||
<div class="chart-container">
|
<div class="chart-container">
|
||||||
<canvas id="chart-title-left-end"></canvas>
|
<canvas id="chart-title-left-end"></canvas>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="chart-container">
|
||||||
|
<canvas id="chart-title-bottom-start"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="chart-container">
|
||||||
|
<canvas id="chart-title-bottom-center"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="chart-container">
|
||||||
|
<canvas id="chart-title-bottom-end"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="chart-container">
|
||||||
|
<canvas id="chart-title-right-start"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="chart-container">
|
||||||
|
<canvas id="chart-title-right-center"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="chart-container">
|
||||||
|
<canvas id="chart-title-right-end"></canvas>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
var color = Chart.helpers.color;
|
var color = Chart.helpers.color;
|
||||||
@ -75,6 +97,12 @@
|
|||||||
legend: {
|
legend: {
|
||||||
display: false
|
display: false
|
||||||
},
|
},
|
||||||
|
title: {
|
||||||
|
align: titleAlignment,
|
||||||
|
display: true,
|
||||||
|
position: titlePosition,
|
||||||
|
text: 'Title Position: ' + titlePosition + ', Align: ' + titleAlignment
|
||||||
|
}
|
||||||
},
|
},
|
||||||
scales: {
|
scales: {
|
||||||
x: {
|
x: {
|
||||||
@ -91,12 +119,6 @@
|
|||||||
labelString: 'Value'
|
labelString: 'Value'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
title: {
|
|
||||||
align: titleAlignment,
|
|
||||||
display: true,
|
|
||||||
position: titlePosition,
|
|
||||||
text: 'Title Position: ' + titlePosition + ', Align: ' + titleAlignment
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -133,6 +155,36 @@
|
|||||||
titleAlignment: 'end',
|
titleAlignment: 'end',
|
||||||
titlePosition: 'left',
|
titlePosition: 'left',
|
||||||
color: 'purple'
|
color: 'purple'
|
||||||
|
}, {
|
||||||
|
id: 'chart-title-bottom-start',
|
||||||
|
titleAlignment: 'start',
|
||||||
|
titlePosition: 'bottom',
|
||||||
|
color: 'red'
|
||||||
|
}, {
|
||||||
|
id: 'chart-title-bottom-center',
|
||||||
|
titleAlignment: 'center',
|
||||||
|
titlePosition: 'bottom',
|
||||||
|
color: 'orange'
|
||||||
|
}, {
|
||||||
|
id: 'chart-title-bottom-end',
|
||||||
|
titleAlignment: 'end',
|
||||||
|
titlePosition: 'bottom',
|
||||||
|
color: 'yellow'
|
||||||
|
}, {
|
||||||
|
id: 'chart-title-right-start',
|
||||||
|
titleAlignment: 'start',
|
||||||
|
titlePosition: 'right',
|
||||||
|
color: 'green'
|
||||||
|
}, {
|
||||||
|
id: 'chart-title-right-center',
|
||||||
|
titleAlignment: 'center',
|
||||||
|
titlePosition: 'right',
|
||||||
|
color: 'blue'
|
||||||
|
}, {
|
||||||
|
id: 'chart-title-right-end',
|
||||||
|
titleAlignment: 'end',
|
||||||
|
titlePosition: 'right',
|
||||||
|
color: 'purple'
|
||||||
}].forEach(function(details) {
|
}].forEach(function(details) {
|
||||||
var ctx = document.getElementById(details.id).getContext('2d');
|
var ctx = document.getElementById(details.id).getContext('2d');
|
||||||
var config = createConfig(details.titlePosition, details.titleAlignment, details.color);
|
var config = createConfig(details.titlePosition, details.titleAlignment, details.color);
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import defaults from '../core/core.defaults';
|
|
||||||
import Element from '../core/core.element';
|
import Element from '../core/core.element';
|
||||||
import layouts from '../core/core.layouts';
|
import layouts from '../core/core.layouts';
|
||||||
import {PI, isArray, mergeIf, toPadding, toFont} from '../helpers';
|
import {PI, isArray, toPadding, toFont} from '../helpers';
|
||||||
|
|
||||||
|
const toLeftRightCenter = (align) => align === 'start' ? 'left' : align === 'end' ? 'right' : 'center';
|
||||||
|
const alignStartEnd = (align, start, end) => align === 'start' ? start : align === 'end' ? end : (start + end) / 2;
|
||||||
|
|
||||||
export class Title extends Element {
|
export class Title extends Element {
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
@ -27,45 +29,18 @@ export class Title extends Element {
|
|||||||
this.fullWidth = undefined;
|
this.fullWidth = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// These methods are ordered by lifecycle. Utilities then follow.
|
|
||||||
|
|
||||||
|
|
||||||
beforeUpdate() {}
|
|
||||||
|
|
||||||
update(maxWidth, maxHeight, margins) {
|
update(maxWidth, maxHeight, margins) {
|
||||||
const me = this;
|
const me = this;
|
||||||
|
|
||||||
// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
|
|
||||||
me.beforeUpdate();
|
|
||||||
|
|
||||||
// Absorb the master measurements
|
|
||||||
me.maxWidth = maxWidth;
|
me.maxWidth = maxWidth;
|
||||||
me.maxHeight = maxHeight;
|
me.maxHeight = maxHeight;
|
||||||
me._margins = margins;
|
me._margins = margins;
|
||||||
|
|
||||||
// Dimensions
|
|
||||||
me.beforeSetDimensions();
|
|
||||||
me.setDimensions();
|
me.setDimensions();
|
||||||
me.afterSetDimensions();
|
|
||||||
// Labels
|
|
||||||
me.beforeBuildLabels();
|
|
||||||
me.buildLabels();
|
|
||||||
me.afterBuildLabels();
|
|
||||||
|
|
||||||
// Fit
|
|
||||||
me.beforeFit();
|
|
||||||
me.fit();
|
me.fit();
|
||||||
me.afterFit();
|
|
||||||
//
|
|
||||||
me.afterUpdate();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
afterUpdate() {}
|
|
||||||
|
|
||||||
|
|
||||||
beforeSetDimensions() {}
|
|
||||||
|
|
||||||
setDimensions() {
|
setDimensions() {
|
||||||
const me = this;
|
const me = this;
|
||||||
// Set the unconstrained dimension before label rotation
|
// Set the unconstrained dimension before label rotation
|
||||||
@ -83,16 +58,6 @@ export class Title extends Element {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
afterSetDimensions() {}
|
|
||||||
|
|
||||||
beforeBuildLabels() {}
|
|
||||||
|
|
||||||
buildLabels() {}
|
|
||||||
|
|
||||||
afterBuildLabels() {}
|
|
||||||
|
|
||||||
beforeFit() {}
|
|
||||||
|
|
||||||
fit() {
|
fit() {
|
||||||
const me = this;
|
const me = this;
|
||||||
const opts = me.options;
|
const opts = me.options;
|
||||||
@ -111,15 +76,36 @@ export class Title extends Element {
|
|||||||
me.height = minSize.height = isHorizontal ? textSize : me.maxHeight;
|
me.height = minSize.height = isHorizontal ? textSize : me.maxHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
afterFit() {}
|
|
||||||
|
|
||||||
// Shared Methods
|
|
||||||
isHorizontal() {
|
isHorizontal() {
|
||||||
const pos = this.options.position;
|
const pos = this.options.position;
|
||||||
return pos === 'top' || pos === 'bottom';
|
return pos === 'top' || pos === 'bottom';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actually draw the title block on the canvas
|
_drawArgs(offset) {
|
||||||
|
const {top, left, bottom, right, options} = this;
|
||||||
|
const align = options.align;
|
||||||
|
let rotation = 0;
|
||||||
|
let maxWidth, titleX, titleY;
|
||||||
|
|
||||||
|
if (this.isHorizontal()) {
|
||||||
|
titleX = alignStartEnd(align, left, right);
|
||||||
|
titleY = top + offset;
|
||||||
|
maxWidth = right - left;
|
||||||
|
} else {
|
||||||
|
if (options.position === 'left') {
|
||||||
|
titleX = left + offset;
|
||||||
|
titleY = alignStartEnd(align, bottom, top);
|
||||||
|
rotation = PI * -0.5;
|
||||||
|
} else {
|
||||||
|
titleX = right - offset;
|
||||||
|
titleY = alignStartEnd(align, top, bottom);
|
||||||
|
rotation = PI * 0.5;
|
||||||
|
}
|
||||||
|
maxWidth = bottom - top;
|
||||||
|
}
|
||||||
|
return {titleX, titleY, maxWidth, rotation};
|
||||||
|
}
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
const me = this;
|
const me = this;
|
||||||
const ctx = me.ctx;
|
const ctx = me.ctx;
|
||||||
@ -132,53 +118,7 @@ export class Title extends Element {
|
|||||||
const fontOpts = toFont(opts.font, me.chart.options.font);
|
const fontOpts = toFont(opts.font, me.chart.options.font);
|
||||||
const lineHeight = fontOpts.lineHeight;
|
const lineHeight = fontOpts.lineHeight;
|
||||||
const offset = lineHeight / 2 + me._padding.top;
|
const offset = lineHeight / 2 + me._padding.top;
|
||||||
let rotation = 0;
|
const {titleX, titleY, maxWidth, rotation} = me._drawArgs(offset);
|
||||||
const top = me.top;
|
|
||||||
const left = me.left;
|
|
||||||
const bottom = me.bottom;
|
|
||||||
const right = me.right;
|
|
||||||
let maxWidth, titleX, titleY;
|
|
||||||
let align;
|
|
||||||
|
|
||||||
// Horizontal
|
|
||||||
if (me.isHorizontal()) {
|
|
||||||
switch (opts.align) {
|
|
||||||
case 'start':
|
|
||||||
titleX = left;
|
|
||||||
align = 'left';
|
|
||||||
break;
|
|
||||||
case 'end':
|
|
||||||
titleX = right;
|
|
||||||
align = 'right';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
titleX = left + ((right - left) / 2);
|
|
||||||
align = 'center';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
titleY = top + offset;
|
|
||||||
maxWidth = right - left;
|
|
||||||
} else {
|
|
||||||
titleX = opts.position === 'left' ? left + offset : right - offset;
|
|
||||||
|
|
||||||
switch (opts.align) {
|
|
||||||
case 'start':
|
|
||||||
titleY = opts.position === 'left' ? bottom : top;
|
|
||||||
align = 'left';
|
|
||||||
break;
|
|
||||||
case 'end':
|
|
||||||
titleY = opts.position === 'left' ? top : bottom;
|
|
||||||
align = 'right';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
titleY = top + ((bottom - top) / 2);
|
|
||||||
align = 'center';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
maxWidth = bottom - top;
|
|
||||||
rotation = PI * (opts.position === 'left' ? -0.5 : 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
@ -187,7 +127,7 @@ export class Title extends Element {
|
|||||||
|
|
||||||
ctx.translate(titleX, titleY);
|
ctx.translate(titleX, titleY);
|
||||||
ctx.rotate(rotation);
|
ctx.rotate(rotation);
|
||||||
ctx.textAlign = align;
|
ctx.textAlign = toLeftRightCenter(opts.align);
|
||||||
ctx.textBaseline = 'middle';
|
ctx.textBaseline = 'middle';
|
||||||
|
|
||||||
const text = opts.text;
|
const text = opts.text;
|
||||||
@ -205,7 +145,7 @@ export class Title extends Element {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createNewTitleBlockAndAttach(chart, titleOpts) {
|
function createTitle(chart, titleOpts) {
|
||||||
const title = new Title({
|
const title = new Title({
|
||||||
ctx: chart.ctx,
|
ctx: chart.ctx,
|
||||||
options: titleOpts,
|
options: titleOpts,
|
||||||
@ -217,42 +157,42 @@ function createNewTitleBlockAndAttach(chart, titleOpts) {
|
|||||||
chart.titleBlock = title;
|
chart.titleBlock = title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeTitle(chart) {
|
||||||
|
const title = chart.titleBlock;
|
||||||
|
if (title) {
|
||||||
|
layouts.removeBox(chart, title);
|
||||||
|
delete chart.titleBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createOrUpdateTitle(chart, options) {
|
||||||
|
const title = chart.titleBlock;
|
||||||
|
if (title) {
|
||||||
|
layouts.configure(chart, title, options);
|
||||||
|
title.options = options;
|
||||||
|
} else {
|
||||||
|
createTitle(chart, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
id: 'title',
|
id: 'title',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Backward compatibility: since 2.1.5, the title is registered as a plugin, making
|
* For tests
|
||||||
* Chart.Title obsolete. To avoid a breaking change, we export the Title as part of
|
|
||||||
* the plugin, which one will be re-exposed in the chart.js file.
|
|
||||||
* https://github.com/chartjs/Chart.js/pull/2640
|
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_element: Title,
|
_element: Title,
|
||||||
|
|
||||||
beforeInit(chart) {
|
beforeInit(chart, options) {
|
||||||
const titleOpts = chart.options.plugins.title;
|
createTitle(chart, options);
|
||||||
|
|
||||||
if (titleOpts) {
|
|
||||||
createNewTitleBlockAndAttach(chart, titleOpts);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeUpdate(chart) {
|
beforeUpdate(chart, args, options) {
|
||||||
const titleOpts = chart.options.plugins.title;
|
if (options === false) {
|
||||||
const titleBlock = chart.titleBlock;
|
removeTitle(chart);
|
||||||
|
} else {
|
||||||
if (titleOpts) {
|
createOrUpdateTitle(chart, options);
|
||||||
mergeIf(titleOpts, defaults.plugins.title);
|
|
||||||
|
|
||||||
if (titleBlock) {
|
|
||||||
layouts.configure(chart, titleBlock, titleOpts);
|
|
||||||
titleBlock.options = titleOpts;
|
|
||||||
} else {
|
|
||||||
createNewTitleBlockAndAttach(chart, titleOpts);
|
|
||||||
}
|
|
||||||
} else if (titleBlock) {
|
|
||||||
layouts.removeBox(chart, titleBlock);
|
|
||||||
delete chart.titleBlock;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user