GanttSeries.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. /* *
  2. *
  3. * (c) 2016-2019 Highsoft AS
  4. *
  5. * Author: Lars A. V. Cabrera
  6. *
  7. * License: www.highcharts.com/license
  8. *
  9. * */
  10. 'use strict';
  11. import H from '../parts/Globals.js';
  12. import 'CurrentDateIndicator.js';
  13. import 'GridAxis.js';
  14. import '../modules/static-scale.src.js';
  15. import 'TreeGrid.js';
  16. import 'Pathfinder.js';
  17. import '../modules/xrange.src.js';
  18. var dateFormat = H.dateFormat,
  19. isObject = H.isObject,
  20. isNumber = H.isNumber,
  21. merge = H.merge,
  22. pick = H.pick,
  23. seriesType = H.seriesType,
  24. seriesTypes = H.seriesTypes,
  25. stop = H.stop,
  26. Series = H.Series,
  27. parent = seriesTypes.xrange;
  28. /**
  29. * @private
  30. * @class
  31. * @name Highcharts.seriesTypes.gantt
  32. *
  33. * @augments Highcharts.Series
  34. */
  35. seriesType('gantt', 'xrange'
  36. /**
  37. * A `gantt` series. If the [type](#series.gantt.type) option is not specified,
  38. * it is inherited from [chart.type](#chart.type).
  39. *
  40. * @extends plotOptions.xrange
  41. * @product gantt
  42. * @optionparent plotOptions.gantt
  43. */
  44. , {
  45. // options - default options merged with parent
  46. grouping: false,
  47. dataLabels: {
  48. enabled: true,
  49. formatter: function () {
  50. var point = this,
  51. amount = point.point.partialFill;
  52. if (isObject(amount)) {
  53. amount = amount.amount;
  54. }
  55. if (isNumber(amount) && amount > 0) {
  56. return (amount * 100) + '%';
  57. }
  58. }
  59. },
  60. tooltip: {
  61. headerFormat: '<span style="font-size: 10px">{series.name}</span><br/>',
  62. pointFormat: null,
  63. pointFormatter: function () {
  64. var point = this,
  65. series = point.series,
  66. tooltip = series.chart.tooltip,
  67. xAxis = series.xAxis,
  68. options = xAxis.options,
  69. formats = options.dateTimeLabelFormats,
  70. startOfWeek = xAxis.options.startOfWeek,
  71. ttOptions = series.tooltipOptions,
  72. format = ttOptions.xDateFormat,
  73. range = point.end ? point.end - point.start : 0,
  74. start,
  75. end,
  76. milestone = point.options.milestone,
  77. retVal = '<b>' + (point.name || point.yCategory) + '</b>';
  78. if (ttOptions.pointFormat) {
  79. return point.tooltipFormatter(ttOptions.pointFormat);
  80. }
  81. if (!format) {
  82. format = H.splat(
  83. tooltip.getDateFormat(
  84. range,
  85. point.start,
  86. startOfWeek,
  87. formats
  88. )
  89. )[0];
  90. }
  91. start = dateFormat(format, point.start);
  92. end = dateFormat(format, point.end);
  93. retVal += '<br/>';
  94. if (!milestone) {
  95. retVal += 'Start: ' + start + '<br/>';
  96. retVal += 'End: ' + end + '<br/>';
  97. } else {
  98. retVal += 'Date ' + start + '<br/>';
  99. }
  100. return retVal;
  101. }
  102. },
  103. connectors: {
  104. type: 'simpleConnect',
  105. animation: {
  106. reversed: true // Dependencies go from child to parent
  107. },
  108. startMarker: {
  109. enabled: true,
  110. symbol: 'arrow-filled',
  111. radius: 4,
  112. fill: '#fa0',
  113. align: 'left'
  114. },
  115. endMarker: {
  116. enabled: false, // Only show arrow on the dependent task
  117. align: 'right'
  118. }
  119. }
  120. }, {
  121. // props - series member overrides
  122. pointArrayMap: ['start', 'end', 'y'],
  123. // Keyboard navigation, don't use nearest vertical mode
  124. keyboardMoveVertical: false,
  125. // Handle milestones, as they have no x2
  126. translatePoint: function (point) {
  127. var series = this,
  128. shapeArgs,
  129. size;
  130. parent.prototype.translatePoint.call(series, point);
  131. if (point.options.milestone) {
  132. shapeArgs = point.shapeArgs;
  133. size = shapeArgs.height;
  134. point.shapeArgs = {
  135. x: shapeArgs.x - (size / 2),
  136. y: shapeArgs.y,
  137. width: size,
  138. height: size
  139. };
  140. }
  141. },
  142. /**
  143. * Draws a single point in the series.
  144. *
  145. * This override draws the point as a diamond if point.options.milestone is
  146. * true, and uses the original drawPoint() if it is false or not set.
  147. *
  148. * @requires module:highcharts-gantt
  149. *
  150. * @private
  151. * @function Highcharts.seriesTypes.gantt#drawPoint
  152. *
  153. * @param {Highcharts.Point} point
  154. * An instance of Point in the series
  155. *
  156. * @param {"animate"|"attr"} verb
  157. * 'animate' (animates changes) or 'attr' (sets options)
  158. */
  159. drawPoint: function (point, verb) {
  160. var series = this,
  161. seriesOpts = series.options,
  162. renderer = series.chart.renderer,
  163. shapeArgs = point.shapeArgs,
  164. plotY = point.plotY,
  165. graphic = point.graphic,
  166. state = point.selected && 'select',
  167. cutOff = seriesOpts.stacking && !seriesOpts.borderRadius,
  168. diamondShape;
  169. if (point.options.milestone) {
  170. if (isNumber(plotY) && point.y !== null) {
  171. diamondShape = renderer.symbols.diamond(
  172. shapeArgs.x,
  173. shapeArgs.y,
  174. shapeArgs.width,
  175. shapeArgs.height
  176. );
  177. if (graphic) {
  178. stop(graphic);
  179. graphic[verb]({
  180. d: diamondShape
  181. });
  182. } else {
  183. point.graphic = graphic = renderer.path(diamondShape)
  184. .addClass(point.getClassName(), true)
  185. .add(point.group || series.group);
  186. }
  187. // Presentational
  188. if (!series.chart.styledMode) {
  189. point.graphic
  190. .attr(series.pointAttribs(point, state))
  191. .shadow(seriesOpts.shadow, null, cutOff);
  192. }
  193. } else if (graphic) {
  194. point.graphic = graphic.destroy(); // #1269
  195. }
  196. } else {
  197. parent.prototype.drawPoint.call(series, point, verb);
  198. }
  199. },
  200. setData: Series.prototype.setData,
  201. setGanttPointAliases: function (options) {
  202. // Add a value to options if the value exists
  203. function addIfExists(prop, val) {
  204. if (val !== undefined) {
  205. options[prop] = val;
  206. }
  207. }
  208. addIfExists('x', pick(options.start, options.x));
  209. addIfExists('x2', pick(options.end, options.x2));
  210. addIfExists(
  211. 'partialFill', pick(options.completed, options.partialFill)
  212. );
  213. addIfExists('connect', pick(options.dependency, options.connect));
  214. }
  215. }, merge(parent.prototype.pointClass.prototype, {
  216. // pointProps - point member overrides. We inherit from parent as well.
  217. /**
  218. * Applies the options containing the x and y data and possible some extra
  219. * properties. This is called on point init or from point.update.
  220. *
  221. * @private
  222. * @function Highcharts.Point#applyOptions
  223. *
  224. * @param {object} options
  225. * The point options
  226. *
  227. * @param {number} x
  228. * The x value
  229. *
  230. * @return {Highcharts.Point}
  231. * The Point instance
  232. */
  233. applyOptions: function (options, x) {
  234. var point = this,
  235. retVal = merge(options);
  236. H.seriesTypes.gantt.prototype.setGanttPointAliases(retVal);
  237. retVal = parent.prototype.pointClass.prototype.applyOptions
  238. .call(point, retVal, x);
  239. return retVal;
  240. }
  241. }));
  242. /**
  243. * A `gantt` series.
  244. *
  245. * @extends series,plotOptions.gantt
  246. * @excluding boostThreshold, connectors, dashStyle, findNearestPointBy,
  247. * getExtremesFromAll, marker, negativeColor, pointInterval,
  248. * pointIntervalUnit, pointPlacement, pointStart
  249. * @product gantt
  250. * @apioption series.gantt
  251. */
  252. /**
  253. * Data for a Gantt series.
  254. *
  255. * @type {Array<*>}
  256. * @extends series.xrange.data
  257. * @excluding className, color, colorIndex, connect, dataLabels, events, id,
  258. * partialFill, selected, x, x2
  259. * @product gantt
  260. * @apioption series.gantt.data
  261. */
  262. /**
  263. * Whether the grid node belonging to this point should start as collapsed. Used
  264. * in axes of type treegrid.
  265. *
  266. * @sample {gantt} gantt/treegrid-axis/collapsed/
  267. * Start as collapsed
  268. *
  269. * @type {boolean}
  270. * @default false
  271. * @product gantt
  272. * @apioption series.gantt.data.collapsed
  273. */
  274. /**
  275. * The start time of a task.
  276. *
  277. * @type {number}
  278. * @product gantt
  279. * @apioption series.gantt.data.start
  280. */
  281. /**
  282. * The end time of a task.
  283. *
  284. * @type {number}
  285. * @product gantt
  286. * @apioption series.gantt.data.end
  287. */
  288. /**
  289. * The Y value of a task.
  290. *
  291. * @type {number}
  292. * @product gantt
  293. * @apioption series.gantt.data.y
  294. */
  295. /**
  296. * The name of a task. If a `treegrid` y-axis is used (default in Gantt charts),
  297. * this will be picked up automatically, and used to calculate the y-value.
  298. *
  299. * @type {string}
  300. * @product gantt
  301. * @apioption series.gantt.data.name
  302. */
  303. /**
  304. * Progress indicator, how much of the task completed. If it is a number, the
  305. * `fill` will be applied automatically.
  306. *
  307. * @sample {gantt} gantt/demo/progress-indicator
  308. * Progress indicator
  309. *
  310. * @type {number|*}
  311. * @extends series.xrange.data.partialFill
  312. * @product gantt
  313. * @apioption series.gantt.data.completed
  314. */
  315. /**
  316. * The amount of the progress indicator, ranging from 0 (not started) to 1
  317. * (finished).
  318. *
  319. * @type {number}
  320. * @default 0
  321. * @apioption series.gantt.data.completed.amount
  322. */
  323. /**
  324. * The fill of the progress indicator. Defaults to a darkened variety of the
  325. * main color.
  326. *
  327. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  328. * @apioption series.gantt.data.completed.fill
  329. */
  330. /**
  331. * The ID of the point (task) that this point depends on in Gantt charts.
  332. * Aliases [connect](series.xrange.data.connect). Can also be an object,
  333. * specifying further connecting [options](series.gantt.connectors) between the
  334. * points. Multiple connections can be specified by providing an array.
  335. *
  336. * @sample gantt/demo/project-management
  337. * Dependencies
  338. * @sample gantt/pathfinder/demo
  339. * Different connection types
  340. *
  341. * @type {string|Array<string|*>|*}
  342. * @extends series.xrange.data.connect
  343. * @since 6.2.0
  344. * @product gantt
  345. * @apioption series.gantt.data.dependency
  346. */
  347. /**
  348. * Whether this point is a milestone. If so, only the `start` option is handled,
  349. * while `end` is ignored.
  350. *
  351. * @sample gantt/gantt/milestones
  352. * Milestones
  353. *
  354. * @type {boolean}
  355. * @since 6.2.0
  356. * @product gantt
  357. * @apioption series.gantt.data.milestone
  358. */
  359. /**
  360. * The ID of the parent point (task) of this point in Gantt charts.
  361. *
  362. * @sample gantt/demo/subtasks
  363. * Gantt chart with subtasks
  364. *
  365. * @type {string}
  366. * @since 6.2.0
  367. * @product gantt
  368. * @apioption series.gantt.data.parent
  369. */
  370. /**
  371. * @excluding afterAnimate
  372. * @apioption series.gantt.events
  373. */