| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544 |
- /**
- * @license Highcharts JS v8.2.0 (2020-08-20)
- *
- * Item series type for Highcharts
- *
- * (c) 2019 Torstein Honsi
- *
- * License: www.highcharts.com/license
- */
- 'use strict';
- (function (factory) {
- if (typeof module === 'object' && module.exports) {
- factory['default'] = factory;
- module.exports = factory;
- } else if (typeof define === 'function' && define.amd) {
- define('highcharts/modules/item-series', ['highcharts'], function (Highcharts) {
- factory(Highcharts);
- factory.Highcharts = Highcharts;
- return factory;
- });
- } else {
- factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined);
- }
- }(function (Highcharts) {
- var _modules = Highcharts ? Highcharts._modules : {};
- function _registerModule(obj, path, args, fn) {
- if (!obj.hasOwnProperty(path)) {
- obj[path] = fn.apply(null, args);
- }
- }
- _registerModule(_modules, 'Series/ItemSeries.js', [_modules['Core/Globals.js'], _modules['Core/Options.js'], _modules['Core/Utilities.js']], function (H, O, U) {
- /* *
- *
- * (c) 2020 Torstein Honsi
- *
- * Item series type for Highcharts
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var defaultOptions = O.defaultOptions;
- var defined = U.defined,
- extend = U.extend,
- fireEvent = U.fireEvent,
- isNumber = U.isNumber,
- merge = U.merge,
- objectEach = U.objectEach,
- pick = U.pick,
- seriesType = U.seriesType;
- var piePoint = H.seriesTypes.pie.prototype.pointClass.prototype;
- /**
- * The item series type.
- *
- * @requires module:modules/item-series
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.item
- *
- * @augments Highcharts.seriesTypes.pie
- */
- seriesType('item',
- // Inherits pie as the most tested non-cartesian series with individual
- // point legend, tooltips etc. Only downside is we need to re-enable
- // marker options.
- 'pie',
- /**
- * An item chart is an infographic chart where a number of items are laid
- * out in either a rectangular or circular pattern. It can be used to
- * visualize counts within a group, or for the circular pattern, typically
- * a parliament.
- *
- * The circular layout has much in common with a pie chart. Many of the item
- * series options, like `center`, `size` and data label positioning, are
- * inherited from the pie series and don't apply for rectangular layouts.
- *
- * @sample highcharts/demo/parliament-chart
- * Parliament chart (circular item chart)
- * @sample highcharts/series-item/rectangular
- * Rectangular item chart
- * @sample highcharts/series-item/symbols
- * Infographic with symbols
- *
- * @extends plotOptions.pie
- * @since 7.1.0
- * @product highcharts
- * @excluding borderColor, borderWidth, depth, linecap, shadow,
- * slicedOffset
- * @requires modules/item-series
- * @optionparent plotOptions.item
- */
- {
- /**
- * In circular view, the end angle of the item layout, in degrees where
- * 0 is up.
- *
- * @sample highcharts/demo/parliament-chart
- * Parliament chart
- * @type {undefined|number}
- */
- endAngle: void 0,
- /**
- * In circular view, the size of the inner diameter of the circle. Can
- * be a percentage or pixel value. Percentages are relative to the outer
- * perimeter. Pixel values are given as integers.
- *
- * If the `rows` option is set, it overrides the `innerSize` setting.
- *
- * @sample highcharts/demo/parliament-chart
- * Parliament chart
- * @type {string|number}
- */
- innerSize: '40%',
- /**
- * The padding between the items, given in relative size where the size
- * of the item is 1.
- * @type {number}
- */
- itemPadding: 0.1,
- /**
- * The layout of the items in rectangular view. Can be either
- * `horizontal` or `vertical`.
- * @sample highcharts/series-item/symbols
- * Horizontal layout
- * @type {string}
- */
- layout: 'vertical',
- /**
- * @extends plotOptions.series.marker
- */
- marker: merge(defaultOptions.plotOptions.line.marker, {
- radius: null
- }),
- /**
- * The number of rows to display in the rectangular or circular view. If
- * the `innerSize` is set, it will be overridden by the `rows` setting.
- *
- * @sample highcharts/series-item/rows-columns
- * Fixed row count
- * @type {number}
- */
- rows: void 0,
- crisp: false,
- showInLegend: true,
- /**
- * In circular view, the start angle of the item layout, in degrees
- * where 0 is up.
- *
- * @sample highcharts/demo/parliament-chart
- * Parliament chart
- * @type {undefined|number}
- */
- startAngle: void 0
- },
- // Prototype members
- {
- markerAttribs: void 0,
- translate: function (positions) {
- // Initialize chart without setting data, #13379.
- if (this.total === 0) {
- this.center = this.getCenter();
- }
- if (!this.slots) {
- this.slots = [];
- }
- if (isNumber(this.options.startAngle) &&
- isNumber(this.options.endAngle)) {
- H.seriesTypes.pie.prototype.translate.apply(this, arguments);
- this.slots = this.getSlots();
- }
- else {
- this.generatePoints();
- fireEvent(this, 'afterTranslate');
- }
- },
- // Get the semi-circular slots
- getSlots: function () {
- var center = this.center,
- diameter = center[2],
- innerSize = center[3],
- row,
- slots = this.slots,
- x,
- y,
- rowRadius,
- rowLength,
- colCount,
- increment,
- angle,
- col,
- itemSize = 0,
- rowCount,
- fullAngle = (this.endAngleRad - this.startAngleRad),
- itemCount = Number.MAX_VALUE,
- finalItemCount,
- rows,
- testRows,
- rowsOption = this.options.rows,
- // How many rows (arcs) should be used
- rowFraction = (diameter - innerSize) / diameter,
- isCircle = fullAngle % (2 * Math.PI) === 0;
- // Increase the itemSize until we find the best fit
- while (itemCount > this.total + (rows && isCircle ? rows.length : 0)) {
- finalItemCount = itemCount;
- // Reset
- slots.length = 0;
- itemCount = 0;
- // Now rows is the last successful run
- rows = testRows;
- testRows = [];
- itemSize++;
- // Total number of rows (arcs) from the center to the
- // perimeter
- rowCount = diameter / itemSize / 2;
- if (rowsOption) {
- innerSize = ((rowCount - rowsOption) / rowCount) * diameter;
- if (innerSize >= 0) {
- rowCount = rowsOption;
- // If innerSize is negative, we are trying to set too
- // many rows in the rows option, so fall back to
- // treating it as innerSize 0
- }
- else {
- innerSize = 0;
- rowFraction = 1;
- }
- }
- else {
- rowCount = Math.floor(rowCount * rowFraction);
- }
- for (row = rowCount; row > 0; row--) {
- rowRadius = (innerSize + (row / rowCount) *
- (diameter - innerSize - itemSize)) / 2;
- rowLength = fullAngle * rowRadius;
- colCount = Math.ceil(rowLength / itemSize);
- testRows.push({
- rowRadius: rowRadius,
- rowLength: rowLength,
- colCount: colCount
- });
- itemCount += colCount + 1;
- }
- }
- if (!rows) {
- return;
- }
- // We now have more slots than we have total items. Loop over
- // the rows and remove the last slot until the count is correct.
- // For each iteration we sort the last slot by the angle, and
- // remove those with the highest angles.
- var overshoot = finalItemCount - this.total -
- (isCircle ? rows.length : 0);
- /**
- * @private
- * @param {Highcharts.ItemRowContainerObject} item
- * Wrapped object with angle and row
- * @return {void}
- */
- function cutOffRow(item) {
- if (overshoot > 0) {
- item.row.colCount--;
- overshoot--;
- }
- }
- while (overshoot > 0) {
- rows
- // Return a simplified representation of the angle of
- // the last slot within each row.
- .map(function (row) {
- return {
- angle: row.colCount / row.rowLength,
- row: row
- };
- })
- // Sort by the angles...
- .sort(function (a, b) {
- return b.angle - a.angle;
- })
- // ...so that we can ignore the items with the lowest
- // angles...
- .slice(0, Math.min(overshoot, Math.ceil(rows.length / 2)))
- // ...and remove the ones with the highest angles
- .forEach(cutOffRow);
- }
- rows.forEach(function (row) {
- var rowRadius = row.rowRadius,
- colCount = row.colCount;
- increment = colCount ? fullAngle / colCount : 0;
- for (col = 0; col <= colCount; col += 1) {
- angle = this.startAngleRad + col * increment;
- x = center[0] + Math.cos(angle) * rowRadius;
- y = center[1] + Math.sin(angle) * rowRadius;
- slots.push({ x: x, y: y, angle: angle });
- }
- }, this);
- // Sort by angle
- slots.sort(function (a, b) {
- return a.angle - b.angle;
- });
- this.itemSize = itemSize;
- return slots;
- },
- getRows: function () {
- var rows = this.options.rows,
- cols,
- ratio;
- // Get the row count that gives the most square cells
- if (!rows) {
- ratio = this.chart.plotWidth / this.chart.plotHeight;
- rows = Math.sqrt(this.total);
- if (ratio > 1) {
- rows = Math.ceil(rows);
- while (rows > 0) {
- cols = this.total / rows;
- if (cols / rows > ratio) {
- break;
- }
- rows--;
- }
- }
- else {
- rows = Math.floor(rows);
- while (rows < this.total) {
- cols = this.total / rows;
- if (cols / rows < ratio) {
- break;
- }
- rows++;
- }
- }
- }
- return rows;
- },
- drawPoints: function () {
- var series = this,
- options = this.options,
- renderer = series.chart.renderer,
- seriesMarkerOptions = options.marker,
- borderWidth = this.borderWidth,
- crisp = borderWidth % 2 ? 0.5 : 1,
- i = 0,
- rows = this.getRows(),
- cols = Math.ceil(this.total / rows),
- cellWidth = this.chart.plotWidth / cols,
- cellHeight = this.chart.plotHeight / rows,
- itemSize = this.itemSize || Math.min(cellWidth,
- cellHeight);
- /*
- this.slots.forEach(slot => {
- this.chart.renderer.circle(slot.x, slot.y, 6)
- .attr({
- fill: 'silver'
- })
- .add(this.group);
- });
- //*/
- this.points.forEach(function (point) {
- var attr,
- graphics,
- pointAttr,
- pointMarkerOptions = point.marker || {},
- symbol = (pointMarkerOptions.symbol ||
- seriesMarkerOptions.symbol),
- r = pick(pointMarkerOptions.radius,
- seriesMarkerOptions.radius),
- size = defined(r) ? 2 * r : itemSize,
- padding = size * options.itemPadding,
- x,
- y,
- width,
- height;
- point.graphics = graphics = point.graphics || {};
- if (!series.chart.styledMode) {
- pointAttr = series.pointAttribs(point, point.selected && 'select');
- }
- if (!point.isNull && point.visible) {
- if (!point.graphic) {
- point.graphic = renderer.g('point')
- .add(series.group);
- }
- for (var val = 0; val < point.y; val++) {
- // Semi-circle
- if (series.center && series.slots) {
- // Fill up the slots from left to right
- var slot = series.slots.shift();
- x = slot.x - itemSize / 2;
- y = slot.y - itemSize / 2;
- }
- else if (options.layout === 'horizontal') {
- x = cellWidth * (i % cols);
- y = cellHeight * Math.floor(i / cols);
- }
- else {
- x = cellWidth * Math.floor(i / rows);
- y = cellHeight * (i % rows);
- }
- x += padding;
- y += padding;
- width = Math.round(size - 2 * padding);
- height = width;
- if (series.options.crisp) {
- x = Math.round(x) - crisp;
- y = Math.round(y) + crisp;
- }
- attr = {
- x: x,
- y: y,
- width: width,
- height: height
- };
- if (typeof r !== 'undefined') {
- attr.r = r;
- }
- if (graphics[val]) {
- graphics[val].animate(attr);
- }
- else {
- graphics[val] = renderer
- .symbol(symbol, null, null, null, null, {
- backgroundSize: 'within'
- })
- .attr(extend(attr, pointAttr))
- .add(point.graphic);
- }
- graphics[val].isActive = true;
- i++;
- }
- }
- objectEach(graphics, function (graphic, key) {
- if (!graphic.isActive) {
- graphic.destroy();
- delete graphics[key];
- }
- else {
- graphic.isActive = false;
- }
- });
- });
- },
- drawDataLabels: function () {
- if (this.center && this.slots) {
- H.seriesTypes.pie.prototype.drawDataLabels.call(this);
- // else, it's just a dot chart with no natural place to put the
- // data labels
- }
- else {
- this.points.forEach(function (point) {
- point.destroyElements({ dataLabel: 1 });
- });
- }
- },
- // Fade in the whole chart
- animate: function (init) {
- if (init) {
- this.group.attr({
- opacity: 0
- });
- }
- else {
- this.group.animate({
- opacity: 1
- }, this.options.animation);
- }
- }
- },
- // Point class
- {
- connectorShapes: piePoint.connectorShapes,
- getConnectorPath: piePoint.getConnectorPath,
- setVisible: piePoint.setVisible,
- getTranslate: piePoint.getTranslate
- });
- /**
- * An `item` series. If the [type](#series.item.type) option is not specified,
- * it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.item
- * @excluding dataParser, dataURL, stack, xAxis, yAxis, dataSorting,
- * boostThreshold, boostBlending
- * @product highcharts
- * @requires modules/item-series
- * @apioption series.item
- */
- /**
- * An array of data points for the series. For the `item` 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.item.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.pie.data
- * @excludes sliced
- * @product highcharts
- * @apioption series.item.data
- */
- /**
- * The sequential index of the data point in the legend.
- *
- * @type {number}
- * @product highcharts
- * @apioption series.pie.data.legendIndex
- */
- ''; // adds the doclets above to the transpiled file
- });
- _registerModule(_modules, 'masters/modules/item-series.src.js', [], function () {
- });
- }));
|