/* * * * (c) 2016-2019 Highsoft AS * * Author: Lars A. V. Cabrera * * License: www.highcharts.com/license * * */ 'use strict'; import H from '../parts/Globals.js'; import './CurrentDateIndicator'; import 'GridAxis.js'; import '../modules/static-scale.src.js'; import 'TreeGrid.js'; import 'Pathfinder.js'; import '../modules/xrange.src.js'; var dateFormat = H.dateFormat, isObject = H.isObject, isNumber = H.isNumber, merge = H.merge, pick = H.pick, seriesType = H.seriesType, seriesTypes = H.seriesTypes, stop = H.stop, Series = H.Series, parent = seriesTypes.xrange; /** * @private * @class * @name Highcharts.seriesTypes.gantt * * @augments Highcharts.Series */ seriesType('gantt', 'xrange' /** * A `gantt` series. If the [type](#series.gantt.type) option is not specified, * it is inherited from [chart.type](#chart.type). * * @extends plotOptions.xrange * @product gantt * @optionparent plotOptions.gantt */ , { // options - default options merged with parent grouping: false, dataLabels: { enabled: true, formatter: function () { var point = this, amount = point.point.partialFill; if (isObject(amount)) { amount = amount.amount; } if (isNumber(amount) && amount > 0) { return (amount * 100) + '%'; } } }, tooltip: { headerFormat: '{series.name}
', pointFormat: null, pointFormatter: function () { var point = this, series = point.series, tooltip = series.chart.tooltip, xAxis = series.xAxis, options = xAxis.options, formats = options.dateTimeLabelFormats, startOfWeek = xAxis.options.startOfWeek, ttOptions = series.tooltipOptions, format = ttOptions.xDateFormat, range = point.end ? point.end - point.start : 0, start, end, milestone = point.options.milestone, retVal = '' + (point.name || point.yCategory) + ''; if (ttOptions.pointFormat) { return point.tooltipFormatter(ttOptions.pointFormat); } if (!format) { format = H.splat( tooltip.getDateFormat( range, point.start, startOfWeek, formats ) )[0]; } start = dateFormat(format, point.start); end = dateFormat(format, point.end); retVal += '
'; if (!milestone) { retVal += 'Start: ' + start + '
'; retVal += 'End: ' + end + '
'; } else { retVal += 'Date ' + start + '
'; } return retVal; } }, connectors: { type: 'simpleConnect', animation: { reversed: true // Dependencies go from child to parent }, startMarker: { enabled: true, symbol: 'arrow-filled', radius: 4, fill: '#fa0', align: 'left' }, endMarker: { enabled: false, // Only show arrow on the dependent task align: 'right' } } }, { // props - series member overrides pointArrayMap: ['start', 'end', 'y'], // Keyboard navigation, don't use nearest vertical mode keyboardMoveVertical: false, // Handle milestones, as they have no x2 translatePoint: function (point) { var series = this, shapeArgs, size; parent.prototype.translatePoint.call(series, point); if (point.options.milestone) { shapeArgs = point.shapeArgs; size = shapeArgs.height; point.shapeArgs = { x: shapeArgs.x - (size / 2), y: shapeArgs.y, width: size, height: size }; } }, /** * Draws a single point in the series. * * This override draws the point as a diamond if point.options.milestone is * true, and uses the original drawPoint() if it is false or not set. * * @requires module:highcharts-gantt * * @private * @function Highcharts.seriesTypes.gantt#drawPoint * * @param {Highcharts.Point} point * An instance of Point in the series * * @param {"animate"|"attr"} verb * 'animate' (animates changes) or 'attr' (sets options) */ drawPoint: function (point, verb) { var series = this, seriesOpts = series.options, renderer = series.chart.renderer, shapeArgs = point.shapeArgs, plotY = point.plotY, graphic = point.graphic, state = point.selected && 'select', cutOff = seriesOpts.stacking && !seriesOpts.borderRadius, diamondShape; if (point.options.milestone) { if (isNumber(plotY) && point.y !== null) { diamondShape = renderer.symbols.diamond( shapeArgs.x, shapeArgs.y, shapeArgs.width, shapeArgs.height ); if (graphic) { stop(graphic); graphic[verb]({ d: diamondShape }); } else { point.graphic = graphic = renderer.path(diamondShape) .addClass(point.getClassName(), true) .add(point.group || series.group); } // Presentational if (!series.chart.styledMode) { point.graphic .attr(series.pointAttribs(point, state)) .shadow(seriesOpts.shadow, null, cutOff); } } else if (graphic) { point.graphic = graphic.destroy(); // #1269 } } else { parent.prototype.drawPoint.call(series, point, verb); } }, setData: Series.prototype.setData, setGanttPointAliases: function (options) { // Add a value to options if the value exists function addIfExists(prop, val) { if (val !== undefined) { options[prop] = val; } } addIfExists('x', pick(options.start, options.x)); addIfExists('x2', pick(options.end, options.x2)); addIfExists( 'partialFill', pick(options.completed, options.partialFill) ); addIfExists('connect', pick(options.dependency, options.connect)); } }, merge(parent.prototype.pointClass.prototype, { // pointProps - point member overrides. We inherit from parent as well. /** * Applies the options containing the x and y data and possible some extra * properties. This is called on point init or from point.update. * * @private * @function Highcharts.Point#applyOptions * * @param {object} options * The point options * * @param {number} x * The x value * * @return {Highcharts.Point} * The Point instance */ applyOptions: function (options, x) { var point = this, retVal = merge(options); H.seriesTypes.gantt.prototype.setGanttPointAliases(retVal); retVal = parent.prototype.pointClass.prototype.applyOptions .call(point, retVal, x); return retVal; } })); /** * A `gantt` series. * * @extends series,plotOptions.gantt * @excluding boostThreshold, connectors, dashStyle, findNearestPointBy, * getExtremesFromAll, marker, negativeColor, pointInterval, * pointIntervalUnit, pointPlacement, pointStart * @product gantt * @apioption series.gantt */ /** * Data for a Gantt series. * * @type {Array<*>} * @extends series.xrange.data * @excluding className, color, colorIndex, connect, dataLabels, events, id, * partialFill, selected, x, x2 * @product gantt * @apioption series.gantt.data */ /** * Whether the grid node belonging to this point should start as collapsed. Used * in axes of type treegrid. * * @sample {gantt} gantt/treegrid-axis/collapsed/ * Start as collapsed * * @type {boolean} * @default false * @product gantt * @apioption series.gantt.data.collapsed */ /** * The start time of a task. * * @type {number} * @product gantt * @apioption series.gantt.data.start */ /** * The end time of a task. * * @type {number} * @product gantt * @apioption series.gantt.data.end */ /** * The Y value of a task. * * @type {number} * @product gantt * @apioption series.gantt.data.y */ /** * The name of a task. If a `treegrid` y-axis is used (default in Gantt charts), * this will be picked up automatically, and used to calculate the y-value. * * @type {string} * @product gantt * @apioption series.gantt.data.name */ /** * Progress indicator, how much of the task completed. If it is a number, the * `fill` will be applied automatically. * * @sample {gantt} gantt/demo/progress-indicator * Progress indicator * * @type {number|*} * @extends series.xrange.data.partialFill * @product gantt * @apioption series.gantt.data.completed */ /** * The amount of the progress indicator, ranging from 0 (not started) to 1 * (finished). * * @type {number} * @default 0 * @apioption series.gantt.data.completed.amount */ /** * The fill of the progress indicator. Defaults to a darkened variety of the * main color. * * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject} * @apioption series.gantt.data.completed.fill */ /** * The ID of the point (task) that this point depends on in Gantt charts. * Aliases [connect](series.xrange.data.connect). Can also be an object, * specifying further connecting [options](series.gantt.connectors) between the * points. Multiple connections can be specified by providing an array. * * @sample gantt/demo/project-management * Dependencies * @sample gantt/pathfinder/demo * Different connection types * * @type {string|Array|*} * @extends series.xrange.data.connect * @since 6.2.0 * @product gantt * @apioption series.gantt.data.dependency */ /** * Whether this point is a milestone. If so, only the `start` option is handled, * while `end` is ignored. * * @sample gantt/gantt/milestones * Milestones * * @type {boolean} * @since 6.2.0 * @product gantt * @apioption series.gantt.data.milestone */ /** * The ID of the parent point (task) of this point in Gantt charts. * * @sample gantt/demo/subtasks * Gantt chart with subtasks * * @type {string} * @since 6.2.0 * @product gantt * @apioption series.gantt.data.parent */ /** * @excluding afterAnimate * @apioption series.gantt.events */