Commit 43e7cde5 authored by Andrew Fontaine's avatar Andrew Fontaine Committed by Phil Hughes

Update `chart.js` to 2.7.2

parent f0fcec4f
const commonTooltips = () => ({
mode: 'x',
intersect: false,
});
const adjustedFontScale = () => ({
fontSize: 8,
});
const yAxesConfig = (shouldAdjustFontSize = false) => ({
yAxes: [
{
ticks: {
beginAtZero: true,
...(shouldAdjustFontSize ? adjustedFontScale() : {}),
},
},
],
});
const xAxesConfig = (shouldAdjustFontSize = false) => ({
xAxes: [
{
ticks: {
...(shouldAdjustFontSize ? adjustedFontScale() : {}),
},
},
],
});
const commonChartOptions = () => ({
responsive: true,
maintainAspectRatio: false,
legend: false,
});
export const barChartOptions = shouldAdjustFontSize => ({
...commonChartOptions(),
scales: {
...yAxesConfig(shouldAdjustFontSize),
...xAxesConfig(shouldAdjustFontSize),
},
tooltips: {
...commonTooltips(),
displayColors: false,
callbacks: {
title() {
return '';
},
label({ xLabel, yLabel }) {
return `${xLabel}: ${yLabel}`;
},
},
},
});
export const pieChartOptions = commonChartOptions;
export const lineChartOptions = ({ width, numberOfPoints, shouldAdjustFontSize }) => ({
...commonChartOptions(),
scales: {
...yAxesConfig(shouldAdjustFontSize),
...xAxesConfig(shouldAdjustFontSize),
},
elements: {
point: {
hitRadius: width / (numberOfPoints * 2),
},
},
tooltips: {
...commonTooltips(),
caretSize: 0,
multiKeyBackground: 'rgba(0,0,0,0)',
callbacks: {
labelColor({ datasetIndex }, { config }) {
return {
backgroundColor: config.data.datasets[datasetIndex].backgroundColor,
borderColor: 'rgba(0,0,0,0)',
};
},
},
},
});
...@@ -2,42 +2,44 @@ import $ from 'jquery'; ...@@ -2,42 +2,44 @@ import $ from 'jquery';
import Chart from 'chart.js'; import Chart from 'chart.js';
import _ from 'underscore'; import _ from 'underscore';
import { barChartOptions, pieChartOptions } from '~/lib/utils/chart_utils';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const projectChartData = JSON.parse(document.getElementById('projectChartData').innerHTML); const projectChartData = JSON.parse(document.getElementById('projectChartData').innerHTML);
const responsiveChart = (selector, data) => { const barChart = (selector, data) => {
const options = {
scaleOverlay: true,
responsive: true,
pointHitDetectionRadius: 2,
maintainAspectRatio: false,
};
// get selector by context // get selector by context
const ctx = selector.get(0).getContext('2d'); const ctx = selector.get(0).getContext('2d');
// pointing parent container to make chart.js inherit its width // pointing parent container to make chart.js inherit its width
const container = $(selector).parent(); const container = $(selector).parent();
const generateChart = () => {
selector.attr('width', $(container).width()); selector.attr('width', $(container).width());
if (window.innerWidth < 768) {
// Scale fonts if window width lower than 768px (iPad portrait) // Scale fonts if window width lower than 768px (iPad portrait)
options.scaleFontSize = 8; const shouldAdjustFontSize = window.innerWidth < 768;
} return new Chart(ctx, {
return new Chart(ctx).Bar(data, options); type: 'bar',
data,
options: barChartOptions(shouldAdjustFontSize),
});
}; };
// enabling auto-resizing
$(window).resize(generateChart); const pieChart = (context, data) => {
return generateChart(); const options = pieChartOptions();
return new Chart(context, {
type: 'pie',
data,
options,
});
}; };
const chartData = data => ({ const chartData = data => ({
labels: Object.keys(data), labels: Object.keys(data),
datasets: [ datasets: [
{ {
fillColor: 'rgba(220,220,220,0.5)', backgroundColor: 'rgba(220,220,220,0.5)',
strokeColor: 'rgba(220,220,220,1)', borderColor: 'rgba(220,220,220,1)',
barStrokeWidth: 1, borderWidth: 1,
barValueSpacing: 1,
barDatasetSpacing: 1,
data: _.values(data), data: _.values(data),
}, },
], ],
...@@ -59,24 +61,27 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -59,24 +61,27 @@ document.addEventListener('DOMContentLoaded', () => {
}; };
const hourData = chartData(projectChartData.hour); const hourData = chartData(projectChartData.hour);
responsiveChart($('#hour-chart'), hourData); barChart($('#hour-chart'), hourData);
const weekDays = reorderWeekDays(projectChartData.weekDays, gon.first_day_of_week); const weekDays = reorderWeekDays(projectChartData.weekDays, gon.first_day_of_week);
const dayData = chartData(weekDays); const dayData = chartData(weekDays);
responsiveChart($('#weekday-chart'), dayData); barChart($('#weekday-chart'), dayData);
const monthData = chartData(projectChartData.month); const monthData = chartData(projectChartData.month);
responsiveChart($('#month-chart'), monthData); barChart($('#month-chart'), monthData);
const data = projectChartData.languages; const data = {
datasets: [
{
data: projectChartData.languages.map(x => x.value),
backgroundColor: projectChartData.languages.map(x => x.color),
hoverBackgroundColor: projectChartData.languages.map(x => x.highlight),
},
],
labels: projectChartData.languages.map(x => x.label),
};
const ctx = $('#languages-chart') const ctx = $('#languages-chart')
.get(0) .get(0)
.getContext('2d'); .getContext('2d');
const options = { pieChart(ctx, data);
scaleOverlay: true,
responsive: true,
maintainAspectRatio: false,
};
new Chart(ctx).Pie(data, options);
}); });
import $ from 'jquery'; import $ from 'jquery';
import Chart from 'chart.js'; import Chart from 'chart.js';
const options = { import { barChartOptions, lineChartOptions } from '~/lib/utils/chart_utils';
scaleOverlay: true,
responsive: true, const SUCCESS_LINE_COLOR = '#1aaa55';
maintainAspectRatio: false,
}; const TOTAL_LINE_COLOR = '#707070';
const buildChart = chartScope => { const buildChart = (chartScope, shouldAdjustFontSize) => {
const data = { const data = {
labels: chartScope.labels, labels: chartScope.labels,
datasets: [ datasets: [
{ {
fillColor: '#707070', backgroundColor: SUCCESS_LINE_COLOR,
strokeColor: '#707070', borderColor: SUCCESS_LINE_COLOR,
pointColor: '#707070', pointBackgroundColor: SUCCESS_LINE_COLOR,
pointStrokeColor: '#EEE', pointBorderColor: '#fff',
data: chartScope.totalValues, data: chartScope.successValues,
fill: 'origin',
}, },
{ {
fillColor: '#1aaa55', backgroundColor: TOTAL_LINE_COLOR,
strokeColor: '#1aaa55', borderColor: TOTAL_LINE_COLOR,
pointColor: '#1aaa55', pointBackgroundColor: TOTAL_LINE_COLOR,
pointStrokeColor: '#fff', pointBorderColor: '#EEE',
data: chartScope.successValues, data: chartScope.totalValues,
fill: '-1',
}, },
], ],
}; };
...@@ -31,36 +33,51 @@ const buildChart = chartScope => { ...@@ -31,36 +33,51 @@ const buildChart = chartScope => {
.get(0) .get(0)
.getContext('2d'); .getContext('2d');
new Chart(ctx).Line(data, options); return new Chart(ctx, {
type: 'line',
data,
options: lineChartOptions({
width: ctx.canvas.width,
numberOfPoints: chartScope.totalValues.length,
shouldAdjustFontSize,
}),
});
}; };
document.addEventListener('DOMContentLoaded', () => { const buildBarChart = (chartTimesData, shouldAdjustFontSize) => {
const chartTimesData = JSON.parse(document.getElementById('pipelinesTimesChartsData').innerHTML);
const chartsData = JSON.parse(document.getElementById('pipelinesChartsData').innerHTML);
const data = { const data = {
labels: chartTimesData.labels, labels: chartTimesData.labels,
datasets: [ datasets: [
{ {
fillColor: 'rgba(220,220,220,0.5)', backgroundColor: 'rgba(220,220,220,0.5)',
strokeColor: 'rgba(220,220,220,1)', borderColor: 'rgba(220,220,220,1)',
barStrokeWidth: 1, borderWidth: 1,
barValueSpacing: 1, barValueSpacing: 1,
barDatasetSpacing: 1, barDatasetSpacing: 1,
data: chartTimesData.values, data: chartTimesData.values,
}, },
], ],
}; };
return new Chart(
if (window.innerWidth < 768) {
// Scale fonts if window width lower than 768px (iPad portrait)
options.scaleFontSize = 8;
}
new Chart(
$('#build_timesChart') $('#build_timesChart')
.get(0) .get(0)
.getContext('2d'), .getContext('2d'),
).Bar(data, options); {
type: 'bar',
data,
options: barChartOptions(shouldAdjustFontSize),
},
);
};
document.addEventListener('DOMContentLoaded', () => {
const chartTimesData = JSON.parse(document.getElementById('pipelinesTimesChartsData').innerHTML);
const chartsData = JSON.parse(document.getElementById('pipelinesChartsData').innerHTML);
// Scale fonts if window width lower than 768px (iPad portrait)
const shouldAdjustFontSize = window.innerWidth < 768;
buildBarChart(chartTimesData, shouldAdjustFontSize);
chartsData.forEach(scope => buildChart(scope)); chartsData.forEach(scope => buildChart(scope, shouldAdjustFontSize));
}); });
...@@ -55,23 +55,23 @@ ...@@ -55,23 +55,23 @@
#{@commits_graph.authors} #{@commits_graph.authors}
= (_("Authors: %{authors}") % { authors: "<strong>#{authors}</strong>" }).html_safe = (_("Authors: %{authors}") % { authors: "<strong>#{authors}</strong>" }).html_safe
.col-md-6 .col-md-6
%div
%p.slead %p.slead
= _("Commits per day of month") = _("Commits per day of month")
%div
%canvas#month-chart %canvas#month-chart
.row .row
.col-md-6 .col-md-6
.col-md-6 .col-md-6
%div
%p.slead %p.slead
= _("Commits per weekday") = _("Commits per weekday")
%div
%canvas#weekday-chart %canvas#weekday-chart
.row .row
.col-md-6 .col-md-6
.col-md-6 .col-md-6
%div
%p.slead %p.slead
= _("Commits per day hour (UTC)") = _("Commits per day hour (UTC)")
%div
%canvas#hour-chart %canvas#hour-chart
-# haml-lint:disable InlineJavaScript -# haml-lint:disable InlineJavaScript
......
%div %p.light
%p.light
= _("Commit duration in minutes for last 30 commits") = _("Commit duration in minutes for last 30 commits")
%div
%canvas#build_timesChart{ height: 200 } %canvas#build_timesChart{ height: 200 }
-# haml-lint:disable InlineJavaScript -# haml-lint:disable InlineJavaScript
......
...@@ -13,17 +13,20 @@ ...@@ -13,17 +13,20 @@
%p.light %p.light
= _("Pipelines for last week") = _("Pipelines for last week")
(#{date_from_to(Date.today - 7.days, Date.today)}) (#{date_from_to(Date.today - 7.days, Date.today)})
%div
%canvas#weekChart{ height: 200 } %canvas#weekChart{ height: 200 }
.prepend-top-default .prepend-top-default
%p.light %p.light
= _("Pipelines for last month") = _("Pipelines for last month")
(#{date_from_to(Date.today - 30.days, Date.today)}) (#{date_from_to(Date.today - 30.days, Date.today)})
%div
%canvas#monthChart{ height: 200 } %canvas#monthChart{ height: 200 }
.prepend-top-default .prepend-top-default
%p.light %p.light
= _("Pipelines for last year") = _("Pipelines for last year")
%div
%canvas#yearChart.padded{ height: 250 } %canvas#yearChart.padded{ height: 250 }
-# haml-lint:disable InlineJavaScript -# haml-lint:disable InlineJavaScript
......
...@@ -27,7 +27,6 @@ export default { ...@@ -27,7 +27,6 @@ export default {
drawChart: true, drawChart: true,
chartOptions: { chartOptions: {
...CHART_OPTNS, ...CHART_OPTNS,
customTooltips: this.generateCustomTooltip,
}, },
showPopover: false, showPopover: false,
popoverTitle: '', popoverTitle: '',
...@@ -105,8 +104,11 @@ export default { ...@@ -105,8 +104,11 @@ export default {
// Render chart when DOM has been updated // Render chart when DOM has been updated
this.$nextTick(() => { this.$nextTick(() => {
const ctx = this.$refs.issuesChart.getContext('2d'); const ctx = this.$refs.issuesChart.getContext('2d');
new Chart(ctx).Bar(
{ this.drawChart = false;
return new Chart(ctx, {
type: 'bar',
data: {
labels: chartLabels, labels: chartLabels,
datasets: [ datasets: [
{ {
...@@ -115,42 +117,48 @@ export default { ...@@ -115,42 +117,48 @@ export default {
}, },
], ],
}, },
chartOptions, options: {
); ...chartOptions,
tooltips: {
this.drawChart = false; enabled: false,
custom: tooltip => this.generateCustomTooltip(tooltip, ctx.canvas),
},
},
});
}); });
}, },
generateCustomTooltip(tooltip) { generateCustomTooltip(tooltip, canvas) {
if (!tooltip) { if (!tooltip.opacity) {
this.showPopover = false; this.showPopover = false;
return; return;
} }
// Find Y Location on page
let top; // Find Y Location on page let top; // Find Y Location on page
if (tooltip.yAlign === 'above') { if (tooltip.yAlign === 'above') {
top = tooltip.y - tooltip.caretHeight - tooltip.caretPadding; top = tooltip.y - tooltip.caretSize - tooltip.caretPadding;
} else { } else {
top = tooltip.y + tooltip.caretHeight + tooltip.caretPadding; top = tooltip.y + tooltip.caretSize + tooltip.caretPadding;
} }
[this.popoverTitle, this.popoverContent] = tooltip.text.split(':'); [this.popoverTitle] = tooltip.title;
[this.popoverContent] = tooltip.body[0].lines;
this.showPopover = true; this.showPopover = true;
this.$nextTick(() => { this.$nextTick(() => {
const tooltipEl = this.$refs.chartTooltip; const tooltipEl = this.$refs.chartTooltip;
const tooltipWidth = tooltipEl.getBoundingClientRect().width; const tooltipWidth = tooltipEl.getBoundingClientRect().width;
const tooltipLeftOffest = window.innerWidth - tooltipWidth; const tooltipLeftOffest = window.innerWidth - tooltipWidth;
const tooltipLeftPosition = tooltip.chart.canvas.offsetLeft + tooltip.x; const tooltipLeftPosition = canvas.offsetLeft + tooltip.caretX;
this.popoverPositionLeft = tooltipLeftPosition < tooltipLeftOffest; this.popoverPositionLeft = tooltipLeftPosition < tooltipLeftOffest;
tooltipEl.style.top = `${tooltip.chart.canvas.offsetTop + top}px`; tooltipEl.style.top = `${canvas.offsetTop + top}px`;
// Move tooltip to the right if too close to the left // Move tooltip to the right if too close to the left
if (tooltipLeftPosition > tooltipLeftOffest) { if (this.popoverPositionLeft) {
tooltipEl.style.left = `${tooltipLeftPosition - tooltipWidth}px`;
} else {
tooltipEl.style.left = `${tooltipLeftPosition}px`; tooltipEl.style.left = `${tooltipLeftPosition}px`;
} else {
tooltipEl.style.left = `${tooltipLeftPosition - tooltipWidth}px`;
} }
}); });
}, },
......
import { barChartOptions } from '~/lib/utils/chart_utils';
const defaultOptions = barChartOptions();
export const CHART_OPTNS = { export const CHART_OPTNS = {
...defaultOptions,
scaleOverlay: true, scaleOverlay: true,
responsive: true,
pointHitDetectionRadius: 2, pointHitDetectionRadius: 2,
maintainAspectRatio: false,
scaleShowVerticalLines: false,
scaleBeginAtZero: true,
barStrokeWidth: 1,
barValueSpacing: 2, barValueSpacing: 2,
scaleGridLineColor: '#DFDFDF', scales: {
scaleLineColor: 'transparent', xAxes: [
{
gridLines: {
display: false,
drawBorder: false,
color: 'transparent',
},
},
],
yAxes: [
{
gridLines: {
color: '#DFDFDF',
drawBorder: false,
drawTicks: false,
},
ticks: {
padding: 10,
},
},
],
},
}; };
export const CHART_COLORS = { export const CHART_COLORS = {
fillColor: 'rgba(31,120,209,0.1)', backgroundColor: 'rgba(31,120,209,0.1)',
strokeColor: 'rgba(31,120,209,1)', borderColor: 'rgba(31,120,209,1)',
highlightFill: 'rgba(31,120,209,0.3)', hoverBackgroundColor: 'rgba(31,120,209,0.3)',
borderWidth: 1,
}; };
...@@ -12,15 +12,20 @@ describe('Issues Analytics component', () => { ...@@ -12,15 +12,20 @@ describe('Issues Analytics component', () => {
const mockTooltipData = { const mockTooltipData = {
y: 1, y: 1,
x: 1, x: 1,
text: 'Jul 2018:1', title: ['Jul 2018'],
opacity: 1,
body: [
{
lines: ['1'],
},
],
caretHeight: 1, caretHeight: 1,
caretPadding: 1, caretPadding: 1,
chart: { };
canvas: {
const mockCanvas = {
offsetLeft: 1, offsetLeft: 1,
offsetTop: 1, offsetTop: 1,
},
},
}; };
beforeEach(() => { beforeEach(() => {
...@@ -68,10 +73,11 @@ describe('Issues Analytics component', () => { ...@@ -68,10 +73,11 @@ describe('Issues Analytics component', () => {
}); });
it('renders chart tooltip with the correct details', done => { it('renders chart tooltip with the correct details', done => {
const [popoverTitle, popoverContent] = mockTooltipData.text.split(':'); const [popoverTitle] = mockTooltipData.title;
const [popoverContent] = mockTooltipData.body[0].lines;
vm.$store.state.issueAnalytics.chartData = mockChartData; vm.$store.state.issueAnalytics.chartData = mockChartData;
vm.generateCustomTooltip(mockTooltipData); vm.generateCustomTooltip(mockTooltipData, mockCanvas);
vm.$nextTick(() => { vm.$nextTick(() => {
expect(vm.showPopover).toBe(true); expect(vm.showPopover).toBe(true);
......
...@@ -2122,10 +2122,28 @@ chardet@^0.5.0: ...@@ -2122,10 +2122,28 @@ chardet@^0.5.0:
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
chart.js@1.0.2: chart.js@2.7.2:
version "1.0.2" version "2.7.2"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-1.0.2.tgz#ad57d2229cfd8ccf5955147e8121b4911e69dfe7" resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.7.2.tgz#3c9fde4dc5b95608211bdefeda7e5d33dffa5714"
integrity sha1-rVfSIpz9jM9ZVRR+gSG0kR5p3+c= integrity sha512-90wl3V9xRZ8tnMvMlpcW+0Yg13BelsGS9P9t0ClaDxv/hdypHDr/YAGf+728m11P5ljwyB0ZHfPKCapZFqSqYA==
dependencies:
chartjs-color "^2.1.0"
moment "^2.10.2"
chartjs-color-string@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/chartjs-color-string/-/chartjs-color-string-0.5.0.tgz#8d3752d8581d86687c35bfe2cb80ac5213ceb8c1"
integrity sha512-amWNvCOXlOUYxZVDSa0YOab5K/lmEhbFNKI55PWc4mlv28BDzA7zaoQTGxSBgJMHIW+hGX8YUrvw/FH4LyhwSQ==
dependencies:
color-name "^1.0.0"
chartjs-color@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/chartjs-color/-/chartjs-color-2.2.0.tgz#84a2fb755787ed85c39dd6dd8c7b1d88429baeae"
integrity sha1-hKL7dVeH7YXDndbdjHsdiEKbrq4=
dependencies:
chartjs-color-string "^0.5.0"
color-convert "^0.5.3"
check-types@^7.3.0: check-types@^7.3.0:
version "7.3.0" version "7.3.0"
...@@ -2296,6 +2314,11 @@ collection-visit@^1.0.0: ...@@ -2296,6 +2314,11 @@ collection-visit@^1.0.0:
map-visit "^1.0.0" map-visit "^1.0.0"
object-visit "^1.0.0" object-visit "^1.0.0"
color-convert@^0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd"
integrity sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=
color-convert@^1.9.0: color-convert@^1.9.0:
version "1.9.3" version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
...@@ -2303,7 +2326,7 @@ color-convert@^1.9.0: ...@@ -2303,7 +2326,7 @@ color-convert@^1.9.0:
dependencies: dependencies:
color-name "1.1.3" color-name "1.1.3"
color-name@1.1.3: color-name@1.1.3, color-name@^1.0.0:
version "1.1.3" version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
...@@ -6985,10 +7008,10 @@ mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: ...@@ -6985,10 +7008,10 @@ mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
dependencies: dependencies:
minimist "0.0.8" minimist "0.0.8"
moment@2.x, moment@^2.21.0: moment@2.x, moment@^2.10.2, moment@^2.21.0:
version "2.22.2" version "2.23.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" resolved "https://registry.yarnpkg.com/moment/-/moment-2.23.0.tgz#759ea491ac97d54bac5ad776996e2a58cc1bc225"
integrity sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y= integrity sha512-3IE39bHVqFbWWaPOMHZF98Q9c3LDKGTmypMiTM2QygGXXElkFWIH7GxfmlwmY2vwa+wmNsoYZmG2iusf1ZjJoA==
monaco-editor-webpack-plugin@^1.7.0: monaco-editor-webpack-plugin@^1.7.0:
version "1.7.0" version "1.7.0"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment