| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255 |
- /* *
- *
- * (c) 2010-2020 Torstein Honsi
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- 'use strict';
- import H from '../Core/Globals.js';
- import SVGRenderer from '../Core/Renderer/SVG/SVGRenderer.js';
- import LegendSymbolMixin from '../Mixins/LegendSymbol.js';
- import Point from '../Core/Series/Point.js';
- import U from '../Core/Utilities.js';
- var addEvent = U.addEvent, clamp = U.clamp, defined = U.defined, fireEvent = U.fireEvent, isNumber = U.isNumber, merge = U.merge, pick = U.pick, relativeLength = U.relativeLength, seriesType = U.seriesType, setAnimation = U.setAnimation;
- import './ColumnSeries.js';
- import centeredSeriesMixin from '../Mixins/CenteredSeries.js';
- import '../Core/Options.js';
- var getStartAndEndRadians = centeredSeriesMixin.getStartAndEndRadians, noop = H.noop, Series = H.Series, seriesTypes = H.seriesTypes;
- /**
- * Pie series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.pie
- *
- * @augments Highcharts.Series
- */
- seriesType('pie', 'line',
- /**
- * A pie chart is a circular graphic which is divided into slices to
- * illustrate numerical proportion.
- *
- * @sample highcharts/demo/pie-basic/
- * Pie chart
- *
- * @extends plotOptions.line
- * @excluding animationLimit, boostThreshold, connectEnds, connectNulls,
- * cropThreshold, dashStyle, dataSorting, dragDrop,
- * findNearestPointBy, getExtremesFromAll, label, lineWidth,
- * marker, negativeColor, pointInterval, pointIntervalUnit,
- * pointPlacement, pointStart, softThreshold, stacking, step,
- * threshold, turboThreshold, zoneAxis, zones, dataSorting,
- * boostBlending
- * @product highcharts
- * @optionparent plotOptions.pie
- */
- {
- /**
- * @excluding legendItemClick
- * @apioption plotOptions.pie.events
- */
- /**
- * Fires when the checkbox next to the point name in the legend is
- * clicked. One parameter, event, is passed to the function. The state
- * of the checkbox is found by event.checked. The checked item is found
- * by event.item. Return false to prevent the default action which is to
- * toggle the select state of the series.
- *
- * @sample {highcharts} highcharts/plotoptions/series-events-checkboxclick/
- * Alert checkbox status
- *
- * @type {Function}
- * @since 1.2.0
- * @product highcharts
- * @context Highcharts.Point
- * @apioption plotOptions.pie.events.checkboxClick
- */
- /**
- * Fires when the legend item belonging to the pie point (slice) is
- * clicked. The `this` keyword refers to the point itself. One
- * parameter, `event`, is passed to the function, containing common
- * event information. The default action is to toggle the visibility of
- * the point. This can be prevented by calling `event.preventDefault()`.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-point-events-legenditemclick/
- * Confirm toggle visibility
- *
- * @type {Highcharts.PointLegendItemClickCallbackFunction}
- * @since 1.2.0
- * @product highcharts
- * @apioption plotOptions.pie.point.events.legendItemClick
- */
- /**
- * The center of the pie chart relative to the plot area. Can be
- * percentages or pixel values. The default behaviour (as of 3.0) is to
- * center the pie so that all slices and data labels are within the plot
- * area. As a consequence, the pie may actually jump around in a chart
- * with dynamic values, as the data labels move. In that case, the
- * center should be explicitly set, for example to `["50%", "50%"]`.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-center/
- * Centered at 100, 100
- *
- * @type {Array<(number|string|null),(number|string|null)>}
- * @default [null, null]
- * @product highcharts
- *
- * @private
- */
- center: [null, null],
- /**
- * The color of the pie series. A pie series is represented as an empty
- * circle if the total sum of its values is 0. Use this property to
- * define the color of its border.
- *
- * In styled mode, the color can be defined by the
- * [colorIndex](#plotOptions.series.colorIndex) option. Also, the series
- * color can be set with the `.highcharts-series`,
- * `.highcharts-color-{n}`, `.highcharts-{type}-series` or
- * `.highcharts-series-{n}` class, or individual classes given by the
- * `className` option.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-emptyseries/
- * Empty pie series
- *
- * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
- * @default #cccccc
- * @apioption plotOptions.pie.color
- */
- /**
- * @product highcharts
- *
- * @private
- */
- clip: false,
- /**
- * @ignore-option
- *
- * @private
- */
- colorByPoint: true,
- /**
- * A series specific or series type specific color set to use instead
- * of the global [colors](#colors).
- *
- * @sample {highcharts} highcharts/demo/pie-monochrome/
- * Set default colors for all pies
- *
- * @type {Array<Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject>}
- * @since 3.0
- * @product highcharts
- * @apioption plotOptions.pie.colors
- */
- /**
- * @declare Highcharts.SeriesPieDataLabelsOptionsObject
- * @extends plotOptions.series.dataLabels
- * @excluding align, allowOverlap, inside, staggerLines, step
- * @private
- */
- dataLabels: {
- /**
- * Alignment method for data labels. Possible values are:
- *
- * - `toPlotEdges`: Each label touches the nearest vertical edge of
- * the plot area.
- *
- * - `connectors`: Connectors have the same x position and the
- * widest label of each half (left & right) touches the nearest
- * vertical edge of the plot area.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-datalabels-alignto-connectors/
- * alignTo: connectors
- * @sample {highcharts} highcharts/plotoptions/pie-datalabels-alignto-plotedges/
- * alignTo: plotEdges
- *
- * @type {string}
- * @since 7.0.0
- * @product highcharts
- * @apioption plotOptions.pie.dataLabels.alignTo
- */
- allowOverlap: true,
- /**
- * The color of the line connecting the data label to the pie slice.
- * The default color is the same as the point's color.
- *
- * In styled mode, the connector stroke is given in the
- * `.highcharts-data-label-connector` class.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorcolor/
- * Blue connectors
- * @sample {highcharts} highcharts/css/pie-point/
- * Styled connectors
- *
- * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
- * @since 2.1
- * @product highcharts
- * @apioption plotOptions.pie.dataLabels.connectorColor
- */
- /**
- * The distance from the data label to the connector. Note that
- * data labels also have a default `padding`, so in order for the
- * connector to touch the text, the `padding` must also be 0.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorpadding/
- * No padding
- *
- * @since 2.1
- * @product highcharts
- */
- connectorPadding: 5,
- /**
- * Specifies the method that is used to generate the connector path.
- * Highcharts provides 3 built-in connector shapes: `'fixedOffset'`
- * (default), `'straight'` and `'crookedLine'`. Using
- * `'crookedLine'` has the most sense (in most of the cases) when
- * `'alignTo'` is set.
- *
- * Users can provide their own method by passing a function instead
- * of a String. 3 arguments are passed to the callback:
- *
- * - Object that holds the information about the coordinates of the
- * label (`x` & `y` properties) and how the label is located in
- * relation to the pie (`alignment` property). `alignment` can by
- * one of the following:
- * `'left'` (pie on the left side of the data label),
- * `'right'` (pie on the right side of the data label) or
- * `'center'` (data label overlaps the pie).
- *
- * - Object that holds the information about the position of the
- * connector. Its `touchingSliceAt` porperty tells the position
- * of the place where the connector touches the slice.
- *
- * - Data label options
- *
- * The function has to return an SVG path definition in array form
- * (see the example).
- *
- * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorshape-string/
- * connectorShape is a String
- * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorshape-function/
- * connectorShape is a function
- *
- * @type {string|Function}
- * @since 7.0.0
- * @product highcharts
- */
- connectorShape: 'fixedOffset',
- /**
- * The width of the line connecting the data label to the pie slice.
- *
- * In styled mode, the connector stroke width is given in the
- * `.highcharts-data-label-connector` class.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorwidth-disabled/
- * Disable the connector
- * @sample {highcharts} highcharts/css/pie-point/
- * Styled connectors
- *
- * @type {number}
- * @default 1
- * @since 2.1
- * @product highcharts
- * @apioption plotOptions.pie.dataLabels.connectorWidth
- */
- /**
- * Works only if `connectorShape` is `'crookedLine'`. It defines how
- * far from the vertical plot edge the coonnector path should be
- * crooked.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-datalabels-crookdistance/
- * crookDistance set to 90%
- *
- * @since 7.0.0
- * @product highcharts
- */
- crookDistance: '70%',
- /**
- * The distance of the data label from the pie's edge. Negative
- * numbers put the data label on top of the pie slices. Can also be
- * defined as a percentage of pie's radius. Connectors are only
- * shown for data labels outside the pie.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-datalabels-distance/
- * Data labels on top of the pie
- *
- * @type {number|string}
- * @since 2.1
- * @product highcharts
- */
- distance: 30,
- enabled: true,
- formatter: function () {
- return this.point.isNull ? void 0 : this.point.name;
- },
- /**
- * Whether to render the connector as a soft arc or a line with
- * sharp break. Works only if `connectorShape` equals to
- * `fixedOffset`.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-datalabels-softconnector-true/
- * Soft
- * @sample {highcharts} highcharts/plotoptions/pie-datalabels-softconnector-false/
- * Non soft
- *
- * @since 2.1.7
- * @product highcharts
- */
- softConnector: true,
- /**
- * @sample {highcharts} highcharts/plotoptions/pie-datalabels-overflow
- * Long labels truncated with an ellipsis
- * @sample {highcharts} highcharts/plotoptions/pie-datalabels-overflow-wrap
- * Long labels are wrapped
- *
- * @type {Highcharts.CSSObject}
- * @apioption plotOptions.pie.dataLabels.style
- */
- x: 0
- },
- /**
- * If the total sum of the pie's values is 0, the series is represented
- * as an empty circle . The `fillColor` option defines the color of that
- * circle. Use [pie.borderWidth](#plotOptions.pie.borderWidth) to set
- * the border thickness.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-emptyseries/
- * Empty pie series
- *
- * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
- * @private
- */
- fillColor: void 0,
- /**
- * The end angle of the pie in degrees where 0 is top and 90 is right.
- * Defaults to `startAngle` plus 360.
- *
- * @sample {highcharts} highcharts/demo/pie-semi-circle/
- * Semi-circle donut
- *
- * @type {number}
- * @since 1.3.6
- * @product highcharts
- * @apioption plotOptions.pie.endAngle
- */
- /**
- * Equivalent to [chart.ignoreHiddenSeries](#chart.ignoreHiddenSeries),
- * this option tells whether the series shall be redrawn as if the
- * hidden point were `null`.
- *
- * The default value changed from `false` to `true` with Highcharts
- * 3.0.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-ignorehiddenpoint/
- * True, the hiddden point is ignored
- *
- * @since 2.3.0
- * @product highcharts
- *
- * @private
- */
- ignoreHiddenPoint: true,
- /**
- * @ignore-option
- *
- * @private
- */
- inactiveOtherPoints: true,
- /**
- * The size of the inner diameter for the pie. A size greater than 0
- * renders a donut chart. Can be a percentage or pixel value.
- * Percentages are relative to the pie size. Pixel values are given as
- * integers.
- *
- *
- * Note: in Highcharts < 4.1.2, the percentage was relative to the plot
- * area, not the pie size.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-innersize-80px/
- * 80px inner size
- * @sample {highcharts} highcharts/plotoptions/pie-innersize-50percent/
- * 50% of the plot area
- * @sample {highcharts} highcharts/demo/3d-pie-donut/
- * 3D donut
- *
- * @type {number|string}
- * @default 0
- * @since 2.0
- * @product highcharts
- * @apioption plotOptions.pie.innerSize
- */
- /**
- * @ignore-option
- *
- * @private
- */
- legendType: 'point',
- /**
- * @ignore-option
- *
- * @private
- */
- marker: null,
- /**
- * The minimum size for a pie in response to auto margins. The pie will
- * try to shrink to make room for data labels in side the plot area,
- * but only to this size.
- *
- * @type {number|string}
- * @default 80
- * @since 3.0
- * @product highcharts
- * @apioption plotOptions.pie.minSize
- */
- /**
- * The diameter of the pie relative to the plot area. Can be a
- * percentage or pixel value. Pixel values are given as integers. The
- * default behaviour (as of 3.0) is to scale to the plot area and give
- * room for data labels within the plot area.
- * [slicedOffset](#plotOptions.pie.slicedOffset) is also included in the
- * default size calculation. As a consequence, the size of the pie may
- * vary when points are updated and data labels more around. In that
- * case it is best to set a fixed value, for example `"75%"`.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-size/
- * Smaller pie
- *
- * @type {number|string|null}
- * @product highcharts
- *
- * @private
- */
- size: null,
- /**
- * Whether to display this particular series or series type in the
- * legend. Since 2.1, pies are not shown in the legend by default.
- *
- * @sample {highcharts} highcharts/plotoptions/series-showinlegend/
- * One series in the legend, one hidden
- *
- * @product highcharts
- *
- * @private
- */
- showInLegend: false,
- /**
- * If a point is sliced, moved out from the center, how many pixels
- * should it be moved?.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-slicedoffset-20/
- * 20px offset
- *
- * @product highcharts
- *
- * @private
- */
- slicedOffset: 10,
- /**
- * The start angle of the pie slices in degrees where 0 is top and 90
- * right.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-startangle-90/
- * Start from right
- *
- * @type {number}
- * @default 0
- * @since 2.3.4
- * @product highcharts
- * @apioption plotOptions.pie.startAngle
- */
- /**
- * Sticky tracking of mouse events. When true, the `mouseOut` event
- * on a series isn't triggered until the mouse moves over another
- * series, or out of the plot area. When false, the `mouseOut` event on
- * a series is triggered when the mouse leaves the area around the
- * series' graph or markers. This also implies the tooltip. When
- * `stickyTracking` is false and `tooltip.shared` is false, the tooltip
- * will be hidden when moving the mouse between series.
- *
- * @product highcharts
- *
- * @private
- */
- stickyTracking: false,
- tooltip: {
- followPointer: true
- },
- /**
- * The color of the border surrounding each slice. When `null`, the
- * border takes the same color as the slice fill. This can be used
- * together with a `borderWidth` to fill drawing gaps created by
- * antialiazing artefacts in borderless pies.
- *
- * In styled mode, the border stroke is given in the `.highcharts-point`
- * class.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-bordercolor-black/
- * Black border
- *
- * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
- * @default #ffffff
- * @product highcharts
- *
- * @private
- */
- borderColor: '#ffffff',
- /**
- * The width of the border surrounding each slice.
- *
- * When setting the border width to 0, there may be small gaps between
- * the slices due to SVG antialiasing artefacts. To work around this,
- * keep the border width at 0.5 or 1, but set the `borderColor` to
- * `null` instead.
- *
- * In styled mode, the border stroke width is given in the
- * `.highcharts-point` class.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-borderwidth/
- * 3px border
- *
- * @product highcharts
- *
- * @private
- */
- borderWidth: 1,
- /**
- * @ignore-options
- * @private
- */
- lineWidth: void 0,
- states: {
- /**
- * @extends plotOptions.series.states.hover
- * @excluding marker, lineWidth, lineWidthPlus
- * @product highcharts
- */
- hover: {
- /**
- * How much to brighten the point on interaction. Requires the
- * main color to be defined in hex or rgb(a) format.
- *
- * In styled mode, the hover brightness is by default replaced
- * by a fill-opacity given in the `.highcharts-point-hover`
- * class.
- *
- * @sample {highcharts} highcharts/plotoptions/pie-states-hover-brightness/
- * Brightened by 0.5
- *
- * @product highcharts
- */
- brightness: 0.1
- }
- }
- },
- /* eslint-disable valid-jsdoc */
- /**
- * @lends seriesTypes.pie.prototype
- */
- {
- isCartesian: false,
- requireSorting: false,
- directTouch: true,
- noSharedTooltip: true,
- trackerGroups: ['group', 'dataLabelsGroup'],
- axisTypes: [],
- pointAttribs: seriesTypes.column.prototype.pointAttribs,
- /**
- * Animate the pies in
- *
- * @private
- * @function Highcharts.seriesTypes.pie#animate
- *
- * @param {boolean} [init=false]
- */
- animate: function (init) {
- var series = this, points = series.points, startAngleRad = series.startAngleRad;
- if (!init) {
- points.forEach(function (point) {
- var graphic = point.graphic, args = point.shapeArgs;
- if (graphic && args) {
- // start values
- graphic.attr({
- // animate from inner radius (#779)
- r: pick(point.startR, (series.center && series.center[3] / 2)),
- start: startAngleRad,
- end: startAngleRad
- });
- // animate
- graphic.animate({
- r: args.r,
- start: args.start,
- end: args.end
- }, series.options.animation);
- }
- });
- }
- },
- // Define hasData function for non-cartesian series.
- // Returns true if the series has points at all.
- hasData: function () {
- return !!this.processedXData.length; // != 0
- },
- /**
- * Recompute total chart sum and update percentages of points.
- *
- * @private
- * @function Highcharts.seriesTypes.pie#updateTotals
- * @return {void}
- */
- updateTotals: function () {
- var i, total = 0, points = this.points, len = points.length, point, ignoreHiddenPoint = this.options.ignoreHiddenPoint;
- // Get the total sum
- for (i = 0; i < len; i++) {
- point = points[i];
- total += (ignoreHiddenPoint && !point.visible) ?
- 0 :
- point.isNull ?
- 0 :
- point.y;
- }
- this.total = total;
- // Set each point's properties
- for (i = 0; i < len; i++) {
- point = points[i];
- point.percentage =
- (total > 0 && (point.visible || !ignoreHiddenPoint)) ?
- point.y / total * 100 :
- 0;
- point.total = total;
- }
- },
- /**
- * Extend the generatePoints method by adding total and percentage
- * properties to each point
- *
- * @private
- * @function Highcharts.seriesTypes.pie#generatePoints
- * @return {void}
- */
- generatePoints: function () {
- Series.prototype.generatePoints.call(this);
- this.updateTotals();
- },
- /**
- * Utility for getting the x value from a given y, used for
- * anticollision logic in data labels. Added point for using specific
- * points' label distance.
- * @private
- */
- getX: function (y, left, point) {
- var center = this.center,
- // Variable pie has individual radius
- radius = this.radii ?
- this.radii[point.index] :
- center[2] / 2, angle, x;
- angle = Math.asin(clamp((y - center[1]) / (radius + point.labelDistance), -1, 1));
- x = center[0] +
- (left ? -1 : 1) *
- (Math.cos(angle) * (radius + point.labelDistance)) +
- (point.labelDistance > 0 ?
- (left ? -1 : 1) * this.options.dataLabels.padding :
- 0);
- return x;
- },
- /**
- * Do translation for pie slices
- *
- * @private
- * @function Highcharts.seriesTypes.pie#translate
- * @param {Array<number>} [positions]
- * @return {void}
- */
- translate: function (positions) {
- this.generatePoints();
- var series = this, cumulative = 0, precision = 1000, // issue #172
- options = series.options, slicedOffset = options.slicedOffset, connectorOffset = slicedOffset + (options.borderWidth || 0), finalConnectorOffset, start, end, angle, radians = getStartAndEndRadians(options.startAngle, options.endAngle), startAngleRad = series.startAngleRad = radians.start, endAngleRad = series.endAngleRad = radians.end, circ = endAngleRad - startAngleRad, // 2 * Math.PI,
- points = series.points,
- // the x component of the radius vector for a given point
- radiusX, radiusY, labelDistance = options.dataLabels.distance, ignoreHiddenPoint = options.ignoreHiddenPoint, i, len = points.length, point;
- // Get positions - either an integer or a percentage string must be
- // given. If positions are passed as a parameter, we're in a
- // recursive loop for adjusting space for data labels.
- if (!positions) {
- series.center = positions = series.getCenter();
- }
- // Calculate the geometry for each point
- for (i = 0; i < len; i++) {
- point = points[i];
- // set start and end angle
- start = startAngleRad + (cumulative * circ);
- if (!ignoreHiddenPoint || point.visible) {
- cumulative += point.percentage / 100;
- }
- end = startAngleRad + (cumulative * circ);
- // set the shape
- point.shapeType = 'arc';
- point.shapeArgs = {
- x: positions[0],
- y: positions[1],
- r: positions[2] / 2,
- innerR: positions[3] / 2,
- start: Math.round(start * precision) / precision,
- end: Math.round(end * precision) / precision
- };
- // Used for distance calculation for specific point.
- point.labelDistance = pick((point.options.dataLabels &&
- point.options.dataLabels.distance), labelDistance);
- // Compute point.labelDistance if it's defined as percentage
- // of slice radius (#8854)
- point.labelDistance = relativeLength(point.labelDistance, point.shapeArgs.r);
- // Saved for later dataLabels distance calculation.
- series.maxLabelDistance = Math.max(series.maxLabelDistance || 0, point.labelDistance);
- // The angle must stay within -90 and 270 (#2645)
- angle = (end + start) / 2;
- if (angle > 1.5 * Math.PI) {
- angle -= 2 * Math.PI;
- }
- else if (angle < -Math.PI / 2) {
- angle += 2 * Math.PI;
- }
- // Center for the sliced out slice
- point.slicedTranslation = {
- translateX: Math.round(Math.cos(angle) * slicedOffset),
- translateY: Math.round(Math.sin(angle) * slicedOffset)
- };
- // set the anchor point for tooltips
- radiusX = Math.cos(angle) * positions[2] / 2;
- radiusY = Math.sin(angle) * positions[2] / 2;
- point.tooltipPos = [
- positions[0] + radiusX * 0.7,
- positions[1] + radiusY * 0.7
- ];
- point.half = angle < -Math.PI / 2 || angle > Math.PI / 2 ?
- 1 :
- 0;
- point.angle = angle;
- // Set the anchor point for data labels. Use point.labelDistance
- // instead of labelDistance // #1174
- // finalConnectorOffset - not override connectorOffset value.
- finalConnectorOffset = Math.min(connectorOffset, point.labelDistance / 5); // #1678
- point.labelPosition = {
- natural: {
- // initial position of the data label - it's utilized for
- // finding the final position for the label
- x: positions[0] + radiusX + Math.cos(angle) *
- point.labelDistance,
- y: positions[1] + radiusY + Math.sin(angle) *
- point.labelDistance
- },
- 'final': {
- // used for generating connector path -
- // initialized later in drawDataLabels function
- // x: undefined,
- // y: undefined
- },
- // left - pie on the left side of the data label
- // right - pie on the right side of the data label
- // center - data label overlaps the pie
- alignment: point.labelDistance < 0 ?
- 'center' : point.half ? 'right' : 'left',
- connectorPosition: {
- breakAt: {
- x: positions[0] + radiusX + Math.cos(angle) *
- finalConnectorOffset,
- y: positions[1] + radiusY + Math.sin(angle) *
- finalConnectorOffset
- },
- touchingSliceAt: {
- x: positions[0] + radiusX,
- y: positions[1] + radiusY
- }
- }
- };
- }
- fireEvent(series, 'afterTranslate');
- },
- /**
- * Called internally to draw auxiliary graph in pie-like series in
- * situtation when the default graph is not sufficient enough to present
- * the data well. Auxiliary graph is saved in the same object as
- * regular graph.
- *
- * @private
- * @function Highcharts.seriesTypes.pie#drawEmpty
- */
- drawEmpty: function () {
- var centerX, centerY, start = this.startAngleRad, end = this.endAngleRad, options = this.options;
- // Draw auxiliary graph if there're no visible points.
- if (this.total === 0 && this.center) {
- centerX = this.center[0];
- centerY = this.center[1];
- if (!this.graph) {
- this.graph = this.chart.renderer
- .arc(centerX, centerY, this.center[1] / 2, 0, start, end)
- .addClass('highcharts-empty-series')
- .add(this.group);
- }
- this.graph.attr({
- d: SVGRenderer.prototype.symbols.arc(centerX, centerY, this.center[2] / 2, 0, {
- start: start,
- end: end,
- innerR: this.center[3] / 2
- })
- });
- if (!this.chart.styledMode) {
- this.graph.attr({
- 'stroke-width': options.borderWidth,
- fill: options.fillColor || 'none',
- stroke: options.color ||
- '#cccccc'
- });
- }
- }
- else if (this.graph) { // Destroy the graph object.
- this.graph = this.graph.destroy();
- }
- },
- /**
- * Draw the data points
- *
- * @private
- * @function Highcharts.seriesTypes.pie#drawPoints
- * @return {void}
- */
- redrawPoints: function () {
- var series = this, chart = series.chart, renderer = chart.renderer, groupTranslation, graphic, pointAttr, shapeArgs, shadow = series.options.shadow;
- this.drawEmpty();
- if (shadow && !series.shadowGroup && !chart.styledMode) {
- series.shadowGroup = renderer.g('shadow')
- .attr({ zIndex: -1 })
- .add(series.group);
- }
- // draw the slices
- series.points.forEach(function (point) {
- var animateTo = {};
- graphic = point.graphic;
- if (!point.isNull && graphic) {
- shapeArgs = point.shapeArgs;
- // If the point is sliced, use special translation, else use
- // plot area translation
- groupTranslation = point.getTranslate();
- if (!chart.styledMode) {
- // Put the shadow behind all points
- var shadowGroup = point.shadowGroup;
- if (shadow && !shadowGroup) {
- shadowGroup = point.shadowGroup = renderer
- .g('shadow')
- .add(series.shadowGroup);
- }
- if (shadowGroup) {
- shadowGroup.attr(groupTranslation);
- }
- pointAttr = series.pointAttribs(point, (point.selected && 'select'));
- }
- // Draw the slice
- if (!point.delayedRendering) {
- graphic
- .setRadialReference(series.center);
- if (!chart.styledMode) {
- merge(true, animateTo, pointAttr);
- }
- merge(true, animateTo, shapeArgs, groupTranslation);
- graphic.animate(animateTo);
- }
- else {
- graphic
- .setRadialReference(series.center)
- .attr(shapeArgs)
- .attr(groupTranslation);
- if (!chart.styledMode) {
- graphic
- .attr(pointAttr)
- .attr({ 'stroke-linejoin': 'round' })
- .shadow(shadow, shadowGroup);
- }
- point.delayedRendering = false;
- }
- graphic.attr({
- visibility: point.visible ? 'inherit' : 'hidden'
- });
- graphic.addClass(point.getClassName());
- }
- else if (graphic) {
- point.graphic = graphic.destroy();
- }
- });
- },
- /**
- * Slices in pie chart are initialized in DOM, but it's shapes and
- * animations are normally run in `drawPoints()`.
- * @private
- */
- drawPoints: function () {
- var renderer = this.chart.renderer;
- this.points.forEach(function (point) {
- // When updating a series between 2d and 3d or cartesian and
- // polar, the shape type changes.
- if (point.graphic && point.hasNewShapeType()) {
- point.graphic = point.graphic.destroy();
- }
- if (!point.graphic) {
- point.graphic = renderer[point.shapeType](point.shapeArgs)
- .add(point.series.group);
- point.delayedRendering = true;
- }
- });
- },
- /**
- * @private
- * @deprecated
- * @function Highcharts.seriesTypes.pie#searchPoint
- */
- searchPoint: noop,
- /**
- * Utility for sorting data labels
- *
- * @private
- * @function Highcharts.seriesTypes.pie#sortByAngle
- * @param {Array<Highcharts.Point>} points
- * @param {number} sign
- * @return {void}
- */
- sortByAngle: function (points, sign) {
- points.sort(function (a, b) {
- return ((typeof a.angle !== 'undefined') &&
- (b.angle - a.angle) * sign);
- });
- },
- /**
- * Use a simple symbol from LegendSymbolMixin.
- *
- * @private
- * @borrows Highcharts.LegendSymbolMixin.drawRectangle as Highcharts.seriesTypes.pie#drawLegendSymbol
- */
- drawLegendSymbol: LegendSymbolMixin.drawRectangle,
- /**
- * Use the getCenter method from drawLegendSymbol.
- *
- * @private
- * @borrows Highcharts.CenteredSeriesMixin.getCenter as Highcharts.seriesTypes.pie#getCenter
- */
- getCenter: centeredSeriesMixin.getCenter,
- /**
- * Pies don't have point marker symbols.
- *
- * @deprecated
- * @private
- * @function Highcharts.seriesTypes.pie#getSymbol
- */
- getSymbol: noop,
- /**
- * @private
- * @type {null}
- */
- drawGraph: null
- },
- /**
- * @lends seriesTypes.pie.prototype.pointClass.prototype
- */
- {
- /**
- * Initialize the pie slice
- *
- * @private
- * @function Highcharts.seriesTypes.pie#pointClass#init
- * @return {Highcharts.Point}
- */
- init: function () {
- Point.prototype.init.apply(this, arguments);
- var point = this, toggleSlice;
- point.name = pick(point.name, 'Slice');
- // add event listener for select
- toggleSlice = function (e) {
- point.slice(e.type === 'select');
- };
- addEvent(point, 'select', toggleSlice);
- addEvent(point, 'unselect', toggleSlice);
- return point;
- },
- /**
- * Negative points are not valid (#1530, #3623, #5322)
- *
- * @private
- * @function Highcharts.seriesTypes.pie#pointClass#isValid
- * @return {boolean}
- */
- isValid: function () {
- return isNumber(this.y) && this.y >= 0;
- },
- /**
- * Toggle the visibility of the pie slice
- *
- * @private
- * @function Highcharts.seriesTypes.pie#pointClass#setVisible
- * @param {boolean} vis
- * Whether to show the slice or not. If undefined, the visibility
- * is toggled.
- * @param {boolean} [redraw=false]
- * @return {void}
- */
- setVisible: function (vis, redraw) {
- var point = this, series = point.series, chart = series.chart, ignoreHiddenPoint = series.options.ignoreHiddenPoint;
- redraw = pick(redraw, ignoreHiddenPoint);
- if (vis !== point.visible) {
- // If called without an argument, toggle visibility
- point.visible = point.options.visible = vis =
- typeof vis === 'undefined' ? !point.visible : vis;
- // update userOptions.data
- series.options.data[series.data.indexOf(point)] =
- point.options;
- // Show and hide associated elements. This is performed
- // regardless of redraw or not, because chart.redraw only
- // handles full series.
- ['graphic', 'dataLabel', 'connector', 'shadowGroup'].forEach(function (key) {
- if (point[key]) {
- point[key][vis ? 'show' : 'hide'](true);
- }
- });
- if (point.legendItem) {
- chart.legend.colorizeItem(point, vis);
- }
- // #4170, hide halo after hiding point
- if (!vis && point.state === 'hover') {
- point.setState('');
- }
- // Handle ignore hidden slices
- if (ignoreHiddenPoint) {
- series.isDirty = true;
- }
- if (redraw) {
- chart.redraw();
- }
- }
- },
- /**
- * Set or toggle whether the slice is cut out from the pie
- *
- * @private
- * @function Highcharts.seriesTypes.pie#pointClass#slice
- * @param {boolean} sliced
- * When undefined, the slice state is toggled.
- * @param {boolean} redraw
- * Whether to redraw the chart. True by default.
- * @param {boolean|Partial<Highcharts.AnimationOptionsObject>}
- * Animation options.
- * @return {void}
- */
- slice: function (sliced, redraw, animation) {
- var point = this, series = point.series, chart = series.chart;
- setAnimation(animation, chart);
- // redraw is true by default
- redraw = pick(redraw, true);
- /**
- * Pie series only. Whether to display a slice offset from the
- * center.
- * @name Highcharts.Point#sliced
- * @type {boolean|undefined}
- */
- // if called without an argument, toggle
- point.sliced = point.options.sliced = sliced =
- defined(sliced) ? sliced : !point.sliced;
- // update userOptions.data
- series.options.data[series.data.indexOf(point)] =
- point.options;
- if (point.graphic) {
- point.graphic.animate(this.getTranslate());
- }
- if (point.shadowGroup) {
- point.shadowGroup.animate(this.getTranslate());
- }
- },
- /**
- * @private
- * @function Highcharts.seriesTypes.pie#pointClass#getTranslate
- * @return {Highcharts.TranslationAttributes}
- */
- getTranslate: function () {
- return this.sliced ? this.slicedTranslation : {
- translateX: 0,
- translateY: 0
- };
- },
- /**
- * @private
- * @function Highcharts.seriesTypes.pie#pointClass#haloPath
- * @param {number} size
- * @return {Highcharts.SVGPathArray}
- */
- haloPath: function (size) {
- var shapeArgs = this.shapeArgs;
- return this.sliced || !this.visible ?
- [] :
- this.series.chart.renderer.symbols.arc(shapeArgs.x, shapeArgs.y, shapeArgs.r + size, shapeArgs.r + size, {
- // Substract 1px to ensure the background is not bleeding
- // through between the halo and the slice (#7495).
- innerR: shapeArgs.r - 1,
- start: shapeArgs.start,
- end: shapeArgs.end
- });
- },
- connectorShapes: {
- // only one available before v7.0.0
- fixedOffset: function (labelPosition, connectorPosition, options) {
- var breakAt = connectorPosition.breakAt, touchingSliceAt = connectorPosition.touchingSliceAt, lineSegment = options.softConnector ? [
- 'C',
- // 1st control point (of the curve)
- labelPosition.x +
- // 5 gives the connector a little horizontal bend
- (labelPosition.alignment === 'left' ? -5 : 5),
- labelPosition.y,
- 2 * breakAt.x - touchingSliceAt.x,
- 2 * breakAt.y - touchingSliceAt.y,
- breakAt.x,
- breakAt.y //
- ] : [
- 'L',
- breakAt.x,
- breakAt.y
- ];
- // assemble the path
- return ([
- ['M', labelPosition.x, labelPosition.y],
- lineSegment,
- ['L', touchingSliceAt.x, touchingSliceAt.y]
- ]);
- },
- straight: function (labelPosition, connectorPosition) {
- var touchingSliceAt = connectorPosition.touchingSliceAt;
- // direct line to the slice
- return [
- ['M', labelPosition.x, labelPosition.y],
- ['L', touchingSliceAt.x, touchingSliceAt.y]
- ];
- },
- crookedLine: function (labelPosition, connectorPosition, options) {
- var touchingSliceAt = connectorPosition.touchingSliceAt, series = this.series, pieCenterX = series.center[0], plotWidth = series.chart.plotWidth, plotLeft = series.chart.plotLeft, alignment = labelPosition.alignment, radius = this.shapeArgs.r, crookDistance = relativeLength(// % to fraction
- options.crookDistance, 1), crookX = alignment === 'left' ?
- pieCenterX + radius + (plotWidth + plotLeft -
- pieCenterX - radius) * (1 - crookDistance) :
- plotLeft + (pieCenterX - radius) * crookDistance, segmentWithCrook = [
- 'L',
- crookX,
- labelPosition.y
- ], useCrook = true;
- // crookedLine formula doesn't make sense if the path overlaps
- // the label - use straight line instead in that case
- if (alignment === 'left' ?
- (crookX > labelPosition.x || crookX < touchingSliceAt.x) :
- (crookX < labelPosition.x || crookX > touchingSliceAt.x)) {
- useCrook = false;
- }
- // assemble the path
- var path = [
- ['M', labelPosition.x, labelPosition.y]
- ];
- if (useCrook) {
- path.push(segmentWithCrook);
- }
- path.push(['L', touchingSliceAt.x, touchingSliceAt.y]);
- return path;
- }
- },
- /**
- * Extendable method for getting the path of the connector between the
- * data label and the pie slice.
- */
- getConnectorPath: function () {
- var labelPosition = this.labelPosition, options = this.series.options.dataLabels, connectorShape = options.connectorShape, predefinedShapes = this.connectorShapes;
- // find out whether to use the predefined shape
- if (predefinedShapes[connectorShape]) {
- connectorShape = predefinedShapes[connectorShape];
- }
- return connectorShape.call(this, {
- // pass simplified label position object for user's convenience
- x: labelPosition.final.x,
- y: labelPosition.final.y,
- alignment: labelPosition.alignment
- }, labelPosition.connectorPosition, options);
- }
- }
- /* eslint-enable valid-jsdoc */
- );
- /**
- * A `pie` series. If the [type](#series.pie.type) option is not specified,
- * it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.pie
- * @excluding cropThreshold, dataParser, dataURL, stack, xAxis, yAxis,
- * dataSorting, step, boostThreshold, boostBlending
- * @product highcharts
- * @apioption series.pie
- */
- /**
- * An array of data points for the series. For the `pie` series type,
- * points can be given in the following ways:
- *
- * 1. An array of numerical values. In this case, the numerical values will be
- * interpreted as `y` options. Example:
- * ```js
- * data: [0, 5, 3, 5]
- * ```
- *
- * 2. An array of objects with named values. The following snippet shows only a
- * few settings, see the complete options set below. If the total number of
- * data points exceeds the series'
- * [turboThreshold](#series.pie.turboThreshold),
- * this option is not available.
- * ```js
- * data: [{
- * y: 1,
- * name: "Point2",
- * color: "#00FF00"
- * }, {
- * y: 7,
- * name: "Point1",
- * color: "#FF00FF"
- * }]
- * ```
- *
- * @sample {highcharts} highcharts/chart/reflow-true/
- * Numerical values
- * @sample {highcharts} highcharts/series/data-array-of-arrays/
- * Arrays of numeric x and y
- * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
- * Arrays of datetime x and y
- * @sample {highcharts} highcharts/series/data-array-of-name-value/
- * Arrays of point.name and y
- * @sample {highcharts} highcharts/series/data-array-of-objects/
- * Config objects
- *
- * @type {Array<number|Array<string,(number|null)>|null|*>}
- * @extends series.line.data
- * @excluding marker, x
- * @product highcharts
- * @apioption series.pie.data
- */
- /**
- * @type {Highcharts.SeriesPieDataLabelsOptionsObject}
- * @product highcharts
- * @apioption series.pie.data.dataLabels
- */
- /**
- * The sequential index of the data point in the legend.
- *
- * @type {number}
- * @product highcharts
- * @apioption series.pie.data.legendIndex
- */
- /**
- * Whether to display a slice offset from the center.
- *
- * @sample {highcharts} highcharts/point/sliced/
- * One sliced point
- *
- * @type {boolean}
- * @product highcharts
- * @apioption series.pie.data.sliced
- */
- /**
- * @excluding legendItemClick
- * @product highcharts
- * @apioption series.pie.events
- */
- ''; // placeholder for transpiled doclets above
|