Commit 307b6da8 authored by Mike Greiling's avatar Mike Greiling

Merge branch 'ee-jivl-replace-d3-v3-v4' into 'master'

Update d3 to v4 to enable tree shaking (EE counterpart)

See merge request gitlab-org/gitlab-ee!3564
parents 06248ef7 4fd6ae7c
import d3 from 'd3'; import { select, mouse } from 'd3-selection';
import { bisector, max } from 'd3-array';
import { timeFormat } from 'd3-time-format';
import { scaleTime, scaleLinear } from 'd3-scale';
import { axisBottom, axisLeft } from 'd3-axis';
import { line } from 'd3-shape';
import { transition } from 'd3-transition';
import { easeLinear } from 'd3-ease';
const d3 = {
select,
mouse,
bisector,
max,
timeFormat,
scaleTime,
scaleLinear,
axisBottom,
axisLeft,
line,
transition,
easeLinear };
const margin = { top: 5, right: 65, bottom: 30, left: 50 }; const margin = { top: 5, right: 65, bottom: 30, left: 50 };
const parseDate = d3.time.format('%Y-%m-%d').parse; // const parseDate = d3.timeFormat('%Y-%m-%d');
const bisectDate = d3.bisector(d => d.date).left; const bisectDate = d3.bisector(d => d.date).left;
const tooltipPadding = { x: 8, y: 3 }; const tooltipPadding = { x: 8, y: 3 };
const tooltipDistance = 15; const tooltipDistance = 15;
...@@ -56,8 +76,8 @@ export default class BurndownChart { ...@@ -56,8 +76,8 @@ export default class BurndownChart {
.on('mousemove', () => this.handleMousemove()); .on('mousemove', () => this.handleMousemove());
// parse start and due dates // parse start and due dates
this.startDate = parseDate(startDate); this.startDate = new Date(startDate);
this.dueDate = parseDate(dueDate); this.dueDate = new Date(dueDate);
// get width and height // get width and height
const dimensions = this.canvas.node().getBoundingClientRect(); const dimensions = this.canvas.node().getBoundingClientRect();
...@@ -71,31 +91,29 @@ export default class BurndownChart { ...@@ -71,31 +91,29 @@ export default class BurndownChart {
this.yMax = 1; this.yMax = 1;
// create scales // create scales
this.xScale = d3.time.scale() this.xScale = d3.scaleTime()
.range([0, this.chartWidth]) .range([0, this.chartWidth])
.domain([this.startDate, this.xMax]); .domain([this.startDate, this.xMax]);
this.yScale = d3.scale.linear() this.yScale = d3.scaleLinear()
.range([this.chartHeight, 0]) .range([this.chartHeight, 0])
.domain([0, this.yMax]); .domain([0, this.yMax]);
// create axes // create axes
this.xAxis = d3.svg.axis() this.xAxis = d3.axisBottom()
.scale(this.xScale) .scale(this.xScale)
.orient('bottom') .tickFormat(d3.timeFormat('%b %-d'))
.tickFormat(d3.time.format('%b %-d'))
.tickPadding(6) .tickPadding(6)
.tickSize(4, 0); .tickSize(4, 0);
this.yAxis = d3.svg.axis() this.yAxis = d3.axisLeft()
.scale(this.yScale) .scale(this.yScale)
.orient('left')
.tickPadding(6) .tickPadding(6)
.tickSize(4, 0); .tickSize(4, 0);
// create lines // create lines
this.line = d3.svg.line() this.line = d3.line()
.x(d => this.xScale(d.date)) .x(d => this.xScale(new Date(d.date)))
.y(d => this.yScale(d.value)); .y(d => this.yScale(d.value));
// render the chart // render the chart
...@@ -105,7 +123,7 @@ export default class BurndownChart { ...@@ -105,7 +123,7 @@ export default class BurndownChart {
// set data and force re-render // set data and force re-render
setData(data, { label = 'Remaining', animate } = {}) { setData(data, { label = 'Remaining', animate } = {}) {
this.data = data.map(datum => ({ this.data = data.map(datum => ({
date: parseDate(datum[0]), date: new Date(datum[0]),
value: parseInt(datum[1], 10), value: parseInt(datum[1], 10),
})).sort((a, b) => (a.date - b.date)); })).sort((a, b) => (a.date - b.date));
...@@ -273,7 +291,7 @@ export default class BurndownChart { ...@@ -273,7 +291,7 @@ export default class BurndownChart {
this.renderedTooltipPoint = datum; this.renderedTooltipPoint = datum;
// generate tooltip content // generate tooltip content
const format = d3.time.format('%b %-d, %Y'); const format = d3.timeFormat('%b %-d, %Y');
const tooltip = `${datum.value} ${this.label} / ${format(datum.date)}`; const tooltip = `${datum.value} ${this.label} / ${format(datum.date)}`;
// move the tooltip point of origin to the point on the graph // move the tooltip point of origin to the point on the graph
...@@ -338,28 +356,14 @@ export default class BurndownChart { ...@@ -338,28 +356,14 @@ export default class BurndownChart {
} }
static animateLinePath(path, duration = 1000, cb) { static animateLinePath(path, duration = 1000, cb) {
// hack to run a callback at transition end
function after(transition, callback) {
let i = 0;
transition
.each(() => (i += 1))
.each('end', function end(...args) {
i -= 1;
if (i === 0) {
callback.apply(this, args);
}
});
}
const lineLength = path.node().getTotalLength(); const lineLength = path.node().getTotalLength();
const linearTransition = d3.transition().duration(duration).ease(d3.easeLinear);
path path
.attr('stroke-dasharray', `${lineLength} ${lineLength}`) .attr('stroke-dasharray', `${lineLength} ${lineLength}`)
.attr('stroke-dashoffset', lineLength) .attr('stroke-dashoffset', lineLength)
.transition() .transition(linearTransition)
.duration(duration)
.ease('linear')
.attr('stroke-dashoffset', 0) .attr('stroke-dashoffset', 0)
.call(after, () => { .on('end', () => {
path.attr('stroke-dasharray', null); path.attr('stroke-dasharray', null);
if (cb) cb(); if (cb) cb();
}); });
......
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, camelcase, one-var-declaration-per-line, quotes, no-param-reassign, quote-props, comma-dangle, prefer-template, max-len, no-return-assign, no-shadow */ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, camelcase, one-var-declaration-per-line, quotes, no-param-reassign, quote-props, comma-dangle, prefer-template, max-len, no-return-assign, no-shadow */
import _ from 'underscore'; import _ from 'underscore';
import d3 from 'd3'; import { timeFormat } from 'd3-time-format';
import { ContributorsGraph, ContributorsAuthorGraph, ContributorsMasterGraph } from './stat_graph_contributors_graph'; import { ContributorsGraph, ContributorsAuthorGraph, ContributorsMasterGraph } from './stat_graph_contributors_graph';
import ContributorsStatGraphUtil from './stat_graph_contributors_util'; import ContributorsStatGraphUtil from './stat_graph_contributors_util';
import { n__ } from '../locale'; import { n__ } from '../locale';
const d3 = { timeFormat };
export default (function() { export default (function() {
function ContributorsStatGraph() {} function ContributorsStatGraph() {}
...@@ -83,9 +85,12 @@ export default (function() { ...@@ -83,9 +85,12 @@ export default (function() {
return _.each(author_commits, (function(_this) { return _.each(author_commits, (function(_this) {
return function(d) { return function(d) {
_this.redraw_author_commit_info(d); _this.redraw_author_commit_info(d);
$(_this.authors[d.author_name].list_item).appendTo("ol"); if (_this.authors[d.author_name] != null) {
_this.authors[d.author_name].set_data(d.dates); $(_this.authors[d.author_name].list_item).appendTo("ol");
return _this.authors[d.author_name].redraw(); _this.authors[d.author_name].set_data(d.dates);
return _this.authors[d.author_name].redraw();
}
return '';
}; };
})(this)); })(this));
}; };
...@@ -97,16 +102,20 @@ export default (function() { ...@@ -97,16 +102,20 @@ export default (function() {
ContributorsStatGraph.prototype.change_date_header = function() { ContributorsStatGraph.prototype.change_date_header = function() {
var print, print_date_format, x_domain; var print, print_date_format, x_domain;
x_domain = ContributorsGraph.prototype.x_domain; x_domain = ContributorsGraph.prototype.x_domain;
print_date_format = d3.time.format("%B %e %Y"); print_date_format = d3.timeFormat("%B %e %Y");
print = print_date_format(x_domain[0]) + " - " + print_date_format(x_domain[1]); print = print_date_format(x_domain[0]) + " - " + print_date_format(x_domain[1]);
return $("#date_header").text(print); return $("#date_header").text(print);
}; };
ContributorsStatGraph.prototype.redraw_author_commit_info = function(author) { ContributorsStatGraph.prototype.redraw_author_commit_info = function(author) {
var author_commit_info, author_list_item; var author_commit_info, author_list_item, $author;
author_list_item = $(this.authors[author.author_name].list_item); $author = this.authors[author.author_name];
author_commit_info = this.format_author_commit_info(author); if ($author != null) {
return author_list_item.find("span").html(author_commit_info); author_list_item = $(this.authors[author.author_name].list_item);
author_commit_info = this.format_author_commit_info(author);
return author_list_item.find("span").html(author_commit_info);
}
return '';
}; };
return ContributorsStatGraph; return ContributorsStatGraph;
......
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, max-len, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, comma-dangle, no-return-assign, prefer-arrow-callback, quotes, prefer-template, newline-per-chained-call, no-else-return, no-shadow */ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, max-len, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, comma-dangle, no-return-assign, prefer-arrow-callback, quotes, prefer-template, newline-per-chained-call, no-else-return, no-shadow */
import _ from 'underscore'; import _ from 'underscore';
import d3 from 'd3'; import { extent, max } from 'd3-array';
import { select, event as d3Event } from 'd3-selection';
import { scaleTime, scaleLinear } from 'd3-scale';
import { axisLeft, axisBottom } from 'd3-axis';
import { area } from 'd3-shape';
import { brushX } from 'd3-brush';
import { timeParse } from 'd3-time-format';
const d3 = { extent, max, select, scaleTime, scaleLinear, axisLeft, axisBottom, area, brushX, timeParse };
const extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; const extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
const hasProp = {}.hasOwnProperty; const hasProp = {}.hasOwnProperty;
...@@ -70,8 +78,8 @@ export const ContributorsGraph = (function() { ...@@ -70,8 +78,8 @@ export const ContributorsGraph = (function() {
}; };
ContributorsGraph.prototype.create_scale = function(width, height) { ContributorsGraph.prototype.create_scale = function(width, height) {
this.x = d3.time.scale().range([0, width]).clamp(true); this.x = d3.scaleTime().range([0, width]).clamp(true);
return this.y = d3.scale.linear().range([height, 0]).nice(); return this.y = d3.scaleLinear().range([height, 0]).nice();
}; };
ContributorsGraph.prototype.draw_x_axis = function() { ContributorsGraph.prototype.draw_x_axis = function() {
...@@ -120,7 +128,7 @@ export const ContributorsMasterGraph = (function(superClass) { ...@@ -120,7 +128,7 @@ export const ContributorsMasterGraph = (function(superClass) {
ContributorsMasterGraph.prototype.parse_dates = function(data) { ContributorsMasterGraph.prototype.parse_dates = function(data) {
var parseDate; var parseDate;
parseDate = d3.time.format("%Y-%m-%d").parse; parseDate = d3.timeParse("%Y-%m-%d");
return data.forEach(function(d) { return data.forEach(function(d) {
return d.date = parseDate(d.date); return d.date = parseDate(d.date);
}); });
...@@ -131,8 +139,8 @@ export const ContributorsMasterGraph = (function(superClass) { ...@@ -131,8 +139,8 @@ export const ContributorsMasterGraph = (function(superClass) {
}; };
ContributorsMasterGraph.prototype.create_axes = function() { ContributorsMasterGraph.prototype.create_axes = function() {
this.x_axis = d3.svg.axis().scale(this.x).orient("bottom"); this.x_axis = d3.axisBottom().scale(this.x);
return this.y_axis = d3.svg.axis().scale(this.y).orient("left").ticks(5); return this.y_axis = d3.axisLeft().scale(this.y).ticks(5);
}; };
ContributorsMasterGraph.prototype.create_svg = function() { ContributorsMasterGraph.prototype.create_svg = function() {
...@@ -140,16 +148,16 @@ export const ContributorsMasterGraph = (function(superClass) { ...@@ -140,16 +148,16 @@ export const ContributorsMasterGraph = (function(superClass) {
}; };
ContributorsMasterGraph.prototype.create_area = function(x, y) { ContributorsMasterGraph.prototype.create_area = function(x, y) {
return this.area = d3.svg.area().x(function(d) { return this.area = d3.area().x(function(d) {
return x(d.date); return x(d.date);
}).y0(this.height).y1(function(d) { }).y0(this.height).y1(function(d) {
d.commits = d.commits || d.additions || d.deletions; d.commits = d.commits || d.additions || d.deletions;
return y(d.commits); return y(d.commits);
}).interpolate("basis"); });
}; };
ContributorsMasterGraph.prototype.create_brush = function() { ContributorsMasterGraph.prototype.create_brush = function() {
return this.brush = d3.svg.brush().x(this.x).on("brushend", this.update_content); return this.brush = d3.brushX(this.x).extent([[this.x.range()[0], 0], [this.x.range()[1], this.height]]).on("end", this.update_content);
}; };
ContributorsMasterGraph.prototype.draw_path = function(data) { ContributorsMasterGraph.prototype.draw_path = function(data) {
...@@ -161,7 +169,12 @@ export const ContributorsMasterGraph = (function(superClass) { ...@@ -161,7 +169,12 @@ export const ContributorsMasterGraph = (function(superClass) {
}; };
ContributorsMasterGraph.prototype.update_content = function() { ContributorsMasterGraph.prototype.update_content = function() {
ContributorsGraph.set_x_domain(this.brush.empty() ? this.x_max_domain : this.brush.extent()); // d3Event.selection replaces the function brush.empty() calls
if (d3Event.selection != null) {
ContributorsGraph.set_x_domain(d3Event.selection.map(this.x.invert));
} else {
ContributorsGraph.set_x_domain(this.x_max_domain);
}
return $("#brush_change").trigger('change'); return $("#brush_change").trigger('change');
}; };
...@@ -219,14 +232,14 @@ export const ContributorsAuthorGraph = (function(superClass) { ...@@ -219,14 +232,14 @@ export const ContributorsAuthorGraph = (function(superClass) {
}; };
ContributorsAuthorGraph.prototype.create_axes = function() { ContributorsAuthorGraph.prototype.create_axes = function() {
this.x_axis = d3.svg.axis().scale(this.x).orient("bottom").ticks(8); this.x_axis = d3.axisBottom().scale(this.x).ticks(8);
return this.y_axis = d3.svg.axis().scale(this.y).orient("left").ticks(5); return this.y_axis = d3.axisLeft().scale(this.y).ticks(5);
}; };
ContributorsAuthorGraph.prototype.create_area = function(x, y) { ContributorsAuthorGraph.prototype.create_area = function(x, y) {
return this.area = d3.svg.area().x(function(d) { return this.area = d3.area().x(function(d) {
var parseDate; var parseDate;
parseDate = d3.time.format("%Y-%m-%d").parse; parseDate = d3.timeParse("%Y-%m-%d");
return x(parseDate(d)); return x(parseDate(d));
}).y0(this.height).y1((function(_this) { }).y0(this.height).y1((function(_this) {
return function(d) { return function(d) {
...@@ -236,11 +249,12 @@ export const ContributorsAuthorGraph = (function(superClass) { ...@@ -236,11 +249,12 @@ export const ContributorsAuthorGraph = (function(superClass) {
return y(0); return y(0);
} }
}; };
})(this)).interpolate("basis"); })(this));
}; };
ContributorsAuthorGraph.prototype.create_svg = function() { ContributorsAuthorGraph.prototype.create_svg = function() {
this.list_item = d3.selectAll(".person")[0].pop(); var persons = document.querySelectorAll('.person');
this.list_item = persons[persons.length - 1];
return this.svg = d3.select(this.list_item).append("svg").attr("width", this.width + this.MARGIN.left + this.MARGIN.right).attr("height", this.height + this.MARGIN.top + this.MARGIN.bottom).attr("class", "spark").append("g").attr("transform", "translate(" + this.MARGIN.left + "," + this.MARGIN.top + ")"); return this.svg = d3.select(this.list_item).append("svg").attr("width", this.width + this.MARGIN.left + this.MARGIN.right).attr("height", this.height + this.MARGIN.top + this.MARGIN.bottom).attr("class", "spark").append("g").attr("transform", "translate(" + this.MARGIN.left + "," + this.MARGIN.top + ")");
}; };
......
<script> <script>
import d3 from 'd3'; import { scaleLinear, scaleTime } from 'd3-scale';
import { axisLeft, axisBottom } from 'd3-axis';
import { max, extent } from 'd3-array';
import { select } from 'd3-selection';
import GraphLegend from './graph/legend.vue'; import GraphLegend from './graph/legend.vue';
import GraphFlag from './graph/flag.vue'; import GraphFlag from './graph/flag.vue';
import GraphDeployment from './graph/deployment.vue'; import GraphDeployment from './graph/deployment.vue';
...@@ -7,10 +10,12 @@ ...@@ -7,10 +10,12 @@
import MonitoringMixin from '../mixins/monitoring_mixins'; import MonitoringMixin from '../mixins/monitoring_mixins';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import measurements from '../utils/measurements'; import measurements from '../utils/measurements';
import { timeScaleFormat, bisectDate } from '../utils/date_time_formatters'; import { bisectDate, timeScaleFormat } from '../utils/date_time_formatters';
import createTimeSeries from '../utils/multiple_time_series'; import createTimeSeries from '../utils/multiple_time_series';
import bp from '../../breakpoints'; import bp from '../../breakpoints';
const d3 = { scaleLinear, scaleTime, axisLeft, axisBottom, max, extent, select };
export default { export default {
props: { props: {
graphData: { graphData: {
...@@ -156,25 +161,22 @@ ...@@ -156,25 +161,22 @@
this.baseGraphHeight = this.baseGraphHeight += (this.timeSeries.length - 3) * 20; this.baseGraphHeight = this.baseGraphHeight += (this.timeSeries.length - 3) * 20;
} }
const axisXScale = d3.time.scale() const axisXScale = d3.scaleTime()
.range([0, this.graphWidth - 70]); .range([0, this.graphWidth - 70]);
const axisYScale = d3.scale.linear() const axisYScale = d3.scaleLinear()
.range([this.graphHeight - this.graphHeightOffset, 0]); .range([this.graphHeight - this.graphHeightOffset, 0]);
const allValues = this.timeSeries.reduce((all, { values }) => all.concat(values), []); const allValues = this.timeSeries.reduce((all, { values }) => all.concat(values), []);
axisXScale.domain(d3.extent(allValues, d => d.time)); axisXScale.domain(d3.extent(allValues, d => d.time));
axisYScale.domain([0, d3.max(allValues.map(d => d.value))]); axisYScale.domain([0, d3.max(allValues.map(d => d.value))]);
const xAxis = d3.svg.axis() const xAxis = d3.axisBottom()
.scale(axisXScale) .scale(axisXScale)
.ticks(d3.time.minute, 60) .tickFormat(timeScaleFormat);
.tickFormat(timeScaleFormat)
.orient('bottom');
const yAxis = d3.svg.axis() const yAxis = d3.axisLeft()
.scale(axisYScale) .scale(axisYScale)
.ticks(measurements.yTicks) .ticks(measurements.yTicks);
.orient('left');
d3.select(this.$refs.baseSvg).select('.x-axis').call(xAxis); d3.select(this.$refs.baseSvg).select('.x-axis').call(xAxis);
......
import d3 from 'd3'; import { timeFormat as time } from 'd3-time-format';
import { timeSecond, timeMinute, timeHour, timeDay, timeMonth, timeYear } from 'd3-time';
import { bisector } from 'd3-array';
export const dateFormat = d3.time.format('%b %-d, %Y'); const d3 = { time, bisector, timeSecond, timeMinute, timeHour, timeDay, timeMonth, timeYear };
export const dateFormatWithName = d3.time.format('%a, %b %-d');
export const timeFormat = d3.time.format('%-I:%M%p'); export const dateFormatWithName = d3.time('%a, %b %-d');
export const dateFormat = d3.time('%b %-d, %Y');
export const timeFormat = d3.time('%-I:%M%p');
export const bisectDate = d3.bisector(d => d.time).left; export const bisectDate = d3.bisector(d => d.time).left;
export const timeScaleFormat = d3.time.format.multi([ export function timeScaleFormat(date) {
['.%L', d => d.getMilliseconds()], let formatFunction;
[':%S', d => d.getSeconds()], if (d3.timeSecond(date) < date) {
['%-I:%M', d => d.getMinutes()], formatFunction = d3.time('.%L');
['%-I %p', d => d.getHours()], } else if (d3.timeMinute(date) < date) {
['%a %-d', d => d.getDay() && d.getDate() !== 1], formatFunction = d3.time(':%S');
['%b %-d', d => d.getDate() !== 1], } else if (d3.timeHour(date) < date) {
['%B', d => d.getMonth()], formatFunction = d3.time('%-I:%M');
['%Y', () => true], } else if (d3.timeDay(date) < date) {
]); formatFunction = d3.time('%-I %p');
} else if (d3.timeWeek(date) < date) {
formatFunction = d3.time('%a %d');
} else if (d3.timeMonth(date) < date) {
formatFunction = d3.time('%b %d');
} else if (d3.timeYear(date) < date) {
formatFunction = d3.time('%B');
} else {
formatFunction = d3.time('%Y');
}
return formatFunction(date);
}
import d3 from 'd3';
import _ from 'underscore'; import _ from 'underscore';
import { scaleLinear, scaleTime } from 'd3-scale';
import { line, area, curveLinear } from 'd3-shape';
import { extent, max } from 'd3-array';
import { timeMinute } from 'd3-time';
const d3 = { scaleLinear, scaleTime, line, area, curveLinear, extent, max, timeMinute };
const defaultColorPalette = { const defaultColorPalette = {
blue: ['#1f78d1', '#8fbce8'], blue: ['#1f78d1', '#8fbce8'],
...@@ -38,27 +43,27 @@ function queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom ...@@ -38,27 +43,27 @@ function queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom
let lineColor = ''; let lineColor = '';
let areaColor = ''; let areaColor = '';
const timeSeriesScaleX = d3.time.scale() const timeSeriesScaleX = d3.scaleTime()
.range([0, graphWidth - 70]); .range([0, graphWidth - 70]);
const timeSeriesScaleY = d3.scale.linear() const timeSeriesScaleY = d3.scaleLinear()
.range([graphHeight - graphHeightOffset, 0]); .range([graphHeight - graphHeightOffset, 0]);
timeSeriesScaleX.domain(xDom); timeSeriesScaleX.domain(xDom);
timeSeriesScaleX.ticks(d3.time.minute, 60); timeSeriesScaleX.ticks(d3.timeMinute, 60);
timeSeriesScaleY.domain(yDom); timeSeriesScaleY.domain(yDom);
const defined = d => !isNaN(d.value) && d.value != null; const defined = d => !isNaN(d.value) && d.value != null;
const lineFunction = d3.svg.line() const lineFunction = d3.line()
.defined(defined) .defined(defined)
.interpolate('linear') .curve(d3.curveLinear) // d3 v4 uses curbe instead of interpolate
.x(d => timeSeriesScaleX(d.time)) .x(d => timeSeriesScaleX(d.time))
.y(d => timeSeriesScaleY(d.value)); .y(d => timeSeriesScaleY(d.value));
const areaFunction = d3.svg.area() const areaFunction = d3.area()
.defined(defined) .defined(defined)
.interpolate('linear') .curve(d3.curveLinear)
.x(d => timeSeriesScaleX(d.time)) .x(d => timeSeriesScaleX(d.time))
.y0(graphHeight - graphHeightOffset) .y0(graphHeight - graphHeightOffset)
.y1(d => timeSeriesScaleY(d.value)); .y1(d => timeSeriesScaleY(d.value));
......
import _ from 'underscore'; import _ from 'underscore';
import d3 from 'd3'; import { scaleLinear, scaleThreshold } from 'd3-scale';
import { select } from 'd3-selection';
import { getDayName, getDayDifference } from '../lib/utils/datetime_utility'; import { getDayName, getDayDifference } from '../lib/utils/datetime_utility';
const d3 = { select, scaleLinear, scaleThreshold };
const LOADING_HTML = ` const LOADING_HTML = `
<div class="text-center"> <div class="text-center">
<i class="fa fa-spinner fa-spin user-calendar-activities-loading"></i> <i class="fa fa-spinner fa-spin user-calendar-activities-loading"></i>
...@@ -28,7 +31,7 @@ function formatTooltipText({ date, count }) { ...@@ -28,7 +31,7 @@ function formatTooltipText({ date, count }) {
return `${contribText}<br />${dateDayName} ${dateText}`; return `${contribText}<br />${dateDayName} ${dateText}`;
} }
const initColorKey = () => d3.scale.linear().range(['#acd5f2', '#254e77']).domain([0, 3]); const initColorKey = () => d3.scaleLinear().range(['#acd5f2', '#254e77']).domain([0, 3]);
export default class ActivityCalendar { export default class ActivityCalendar {
constructor(container, timestamps, calendarActivitiesPath, utcOffset = 0) { constructor(container, timestamps, calendarActivitiesPath, utcOffset = 0) {
...@@ -205,7 +208,7 @@ export default class ActivityCalendar { ...@@ -205,7 +208,7 @@ export default class ActivityCalendar {
initColor() { initColor() {
const colorRange = ['#ededed', this.colorKey(0), this.colorKey(1), this.colorKey(2), this.colorKey(3)]; const colorRange = ['#ededed', this.colorKey(0), this.colorKey(1), this.colorKey(2), this.colorKey(3)];
return d3.scale.threshold().domain([0, 10, 20, 30]).range(colorRange); return d3.scaleThreshold().domain([0, 10, 20, 30]).range(colorRange);
} }
clickDay(stamp) { clickDay(stamp) {
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
} }
.axis { .axis {
fill: $stat-graph-axis-fill;
font-size: 10px; font-size: 10px;
} }
...@@ -54,9 +53,7 @@ ...@@ -54,9 +53,7 @@
} }
.selection rect { .selection rect {
fill: $stat-graph-selection-fill;
fill-opacity: 0.1; fill-opacity: 0.1;
stroke: $stat-graph-selection-stroke;
stroke-width: 1px; stroke-width: 1px;
stroke-opacity: 0.4; stroke-opacity: 0.4;
shape-rendering: crispedges; shape-rendering: crispedges;
......
...@@ -34,7 +34,6 @@ var config = { ...@@ -34,7 +34,6 @@ var config = {
burndown_chart: './burndown_chart/index.js', burndown_chart: './burndown_chart/index.js',
common: './commons/index.js', common: './commons/index.js',
common_vue: './vue_shared/vue_resource_interceptor.js', common_vue: './vue_shared/vue_resource_interceptor.js',
common_d3: ['d3'],
cycle_analytics: './cycle_analytics/cycle_analytics_bundle.js', cycle_analytics: './cycle_analytics/cycle_analytics_bundle.js',
commit_pipelines: './commit/pipelines/pipelines_bundle.js', commit_pipelines: './commit/pipelines/pipelines_bundle.js',
deploy_keys: './deploy_keys/index.js', deploy_keys: './deploy_keys/index.js',
...@@ -240,6 +239,9 @@ var config = { ...@@ -240,6 +239,9 @@ var config = {
'users', 'users',
'burndown_chart', // EE 'burndown_chart', // EE
], ],
minChunks: function (module, count) {
return module.resource && /d3-/.test(module.resource);
},
}), }),
// create cacheable common library bundles // create cacheable common library bundles
......
...@@ -12,7 +12,7 @@ feature 'Contributions Calendar', :js do ...@@ -12,7 +12,7 @@ feature 'Contributions Calendar', :js do
issue_params = { title: issue_title } issue_params = { title: issue_title }
def get_cell_color_selector(contributions) def get_cell_color_selector(contributions)
activity_colors = %w[#ededed #acd5f2 #7fa8c9 #527ba0 #254e77] activity_colors = ["#ededed", "rgb(172, 213, 242)", "rgb(127, 168, 201)", "rgb(82, 123, 160)", "rgb(37, 78, 119)"]
# We currently don't actually test the cases with contributions >= 20 # We currently don't actually test the cases with contributions >= 20
activity_colors_index = activity_colors_index =
if contributions > 0 && contributions < 10 if contributions > 0 && contributions < 10
......
/* eslint-disable quotes, jasmine/no-suite-dupes, vars-on-top, no-var */ /* eslint-disable quotes, jasmine/no-suite-dupes, vars-on-top, no-var */
import { scaleLinear, scaleTime } from 'd3-scale';
import d3 from 'd3'; import { timeParse } from 'd3-time-format';
import { ContributorsGraph, ContributorsMasterGraph } from '~/graphs/stat_graph_contributors_graph'; import { ContributorsGraph, ContributorsMasterGraph } from '~/graphs/stat_graph_contributors_graph';
const d3 = { scaleLinear, scaleTime, timeParse };
describe("ContributorsGraph", function () { describe("ContributorsGraph", function () {
describe("#set_x_domain", function () { describe("#set_x_domain", function () {
it("set the x_domain", function () { it("set the x_domain", function () {
...@@ -53,7 +55,7 @@ describe("ContributorsGraph", function () { ...@@ -53,7 +55,7 @@ describe("ContributorsGraph", function () {
it("sets the instance's x domain using the prototype's x_domain", function () { it("sets the instance's x domain using the prototype's x_domain", function () {
ContributorsGraph.prototype.x_domain = 20; ContributorsGraph.prototype.x_domain = 20;
var instance = new ContributorsGraph(); var instance = new ContributorsGraph();
instance.x = d3.time.scale().range([0, 100]).clamp(true); instance.x = d3.scaleTime().range([0, 100]).clamp(true);
spyOn(instance.x, 'domain'); spyOn(instance.x, 'domain');
instance.set_x_domain(); instance.set_x_domain();
expect(instance.x.domain).toHaveBeenCalledWith(20); expect(instance.x.domain).toHaveBeenCalledWith(20);
...@@ -64,7 +66,7 @@ describe("ContributorsGraph", function () { ...@@ -64,7 +66,7 @@ describe("ContributorsGraph", function () {
it("sets the instance's y domain using the prototype's y_domain", function () { it("sets the instance's y domain using the prototype's y_domain", function () {
ContributorsGraph.prototype.y_domain = 30; ContributorsGraph.prototype.y_domain = 30;
var instance = new ContributorsGraph(); var instance = new ContributorsGraph();
instance.y = d3.scale.linear().range([100, 0]).nice(); instance.y = d3.scaleLinear().range([100, 0]).nice();
spyOn(instance.y, 'domain'); spyOn(instance.y, 'domain');
instance.set_y_domain(); instance.set_y_domain();
expect(instance.y.domain).toHaveBeenCalledWith(30); expect(instance.y.domain).toHaveBeenCalledWith(30);
...@@ -118,7 +120,7 @@ describe("ContributorsMasterGraph", function () { ...@@ -118,7 +120,7 @@ describe("ContributorsMasterGraph", function () {
describe("#parse_dates", function () { describe("#parse_dates", function () {
it("parses the dates", function () { it("parses the dates", function () {
var graph = new ContributorsMasterGraph(); var graph = new ContributorsMasterGraph();
var parseDate = d3.time.format("%Y-%m-%d").parse; var parseDate = d3.timeParse("%Y-%m-%d");
var data = [{ date: "2013-01-01" }, { date: "2012-12-15" }]; var data = [{ date: "2013-01-01" }, { date: "2012-12-15" }];
var correct = [{ date: parseDate(data[0].date) }, { date: parseDate(data[1].date) }]; var correct = [{ date: parseDate(data[0].date) }, { date: parseDate(data[1].date) }];
graph.parse_dates(data); graph.parse_dates(data);
......
...@@ -1704,14 +1704,112 @@ custom-event@~1.0.0: ...@@ -1704,14 +1704,112 @@ custom-event@~1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425"
d3-array@^1.2.0, d3-array@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.1.tgz#d1ca33de2f6ac31efadb8e050a021d7e2396d5dc"
d3-axis@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-1.0.8.tgz#31a705a0b535e65759de14173a31933137f18efa"
d3-brush@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-1.0.4.tgz#00c2f238019f24f6c0a194a26d41a1530ffe7bc4"
dependencies:
d3-dispatch "1"
d3-drag "1"
d3-interpolate "1"
d3-selection "1"
d3-transition "1"
d3-collection@1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.4.tgz#342dfd12837c90974f33f1cc0a785aea570dcdc2"
d3-color@1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.0.3.tgz#bc7643fca8e53a8347e2fbdaffa236796b58509b"
d3-dispatch@1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.3.tgz#46e1491eaa9b58c358fce5be4e8bed626e7871f8"
d3-drag@1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-1.2.1.tgz#df8dd4c502fb490fc7462046a8ad98a5c479282d"
dependencies:
d3-dispatch "1"
d3-selection "1"
d3-ease@1, d3-ease@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.3.tgz#68bfbc349338a380c44d8acc4fbc3304aa2d8c0e"
d3-format@1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.2.1.tgz#4e19ecdb081a341dafaf5f555ee956bcfdbf167f"
d3-interpolate@1:
version "1.1.6"
resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.1.6.tgz#2cf395ae2381804df08aa1bf766b7f97b5f68fb6"
dependencies:
d3-color "1"
d3-path@1:
version "1.0.5"
resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.5.tgz#241eb1849bd9e9e8021c0d0a799f8a0e8e441764"
d3-scale@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-1.0.7.tgz#fa90324b3ea8a776422bd0472afab0b252a0945d"
dependencies:
d3-array "^1.2.0"
d3-collection "1"
d3-color "1"
d3-format "1"
d3-interpolate "1"
d3-time "1"
d3-time-format "2"
d3-selection@1, d3-selection@^1.1.0, d3-selection@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.2.0.tgz#1b8ec1c7cedadfb691f2ba20a4a3cfbeb71bbc88"
d3-shape@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.2.0.tgz#45d01538f064bafd05ea3d6d2cb748fd8c41f777"
dependencies:
d3-path "1"
d3-time-format@2, d3-time-format@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.1.1.tgz#85b7cdfbc9ffca187f14d3c456ffda268081bb31"
dependencies:
d3-time "1"
d3-time@1, d3-time@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.0.8.tgz#dbd2d6007bf416fe67a76d17947b784bffea1e84"
d3-timer@1:
version "1.0.7"
resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.7.tgz#df9650ca587f6c96607ff4e60cc38229e8dd8531"
d3-transition@1, d3-transition@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-1.1.1.tgz#d8ef89c3b848735b060e54a39b32aaebaa421039"
dependencies:
d3-color "1"
d3-dispatch "1"
d3-ease "1"
d3-interpolate "1"
d3-selection "^1.1.0"
d3-timer "1"
d3@3.5.17: d3@3.5.17:
version "3.5.17" version "3.5.17"
resolved "https://registry.yarnpkg.com/d3/-/d3-3.5.17.tgz#bc46748004378b21a360c9fc7cf5231790762fb8" resolved "https://registry.yarnpkg.com/d3/-/d3-3.5.17.tgz#bc46748004378b21a360c9fc7cf5231790762fb8"
d3@^3.5.11:
version "3.5.11"
resolved "https://registry.yarnpkg.com/d3/-/d3-3.5.11.tgz#d130750eed0554db70e8432102f920a12407b69c"
d@1: d@1:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
......
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