UNPKG

@progress/kendo-charts

Version:

Kendo UI platform-independent Charts library

227 lines (181 loc) 6.53 kB
import { geometry as geom, drawing as draw } from '@progress/kendo-drawing'; import GridLinesMixin from './mixins/grid-lines-mixin'; import CategoryAxis from './category-axis'; import ShapeBuilder from './shape-builder'; import Ring from './ring'; import Box from './box'; import { COORD_PRECISION, ARC } from '../common/constants'; import { deepExtend, getSpacing, inArray, limitValue, map, rad, round, setDefaultOptions } from '../common'; class RadarCategoryAxis extends CategoryAxis { range() { return { min: 0, max: this.options.categories.length }; } reflow(box) { this.box = box; this.reflowLabels(); } lineBox() { return this.box; } reflowLabels() { const { labels, options: { labels: labelOptions } } = this; const skip = labelOptions.skip || 0; const step = labelOptions.step || 1; const measureBox = new Box(); for (let i = 0; i < labels.length; i++) { labels[i].reflow(measureBox); const labelBox = labels[i].box; labels[i].reflow(this.getSlot(skip + i * step).adjacentBox( 0, labelBox.width(), labelBox.height() )); } } intervals(size, skipOption, stepOption, skipAngles = false) { const options = this.options; const categories = options.categories.length; const divCount = categories / size || 1; const divAngle = 360 / divCount; const skip = skipOption || 0; const step = stepOption || 1; const divs = []; let angle = 0; for (let i = skip; i < divCount; i += step) { if (options.reverse) { angle = 360 - i * divAngle; } else { angle = i * divAngle; } angle = round(angle, COORD_PRECISION) % 360; if (!(skipAngles && inArray(angle, skipAngles))) { divs.push(angle); } } return divs; } majorIntervals() { return this.intervals(1); } minorIntervals() { return this.intervals(0.5); } intervalAngle(interval) { return (360 + interval + this.options.startAngle) % 360; } majorAngles() { return map(this.majorIntervals(), (interval) => this.intervalAngle(interval)); } createLine() { return []; } majorGridLineAngles(altAxis) { const majorGridLines = this.options.majorGridLines; return this.gridLineAngles(altAxis, 1, majorGridLines.skip, majorGridLines.step); } minorGridLineAngles(altAxis, skipMajor) { const { minorGridLines, majorGridLines } = this.options; const majorGridLineAngles = skipMajor ? this.intervals(1, majorGridLines.skip, majorGridLines.step) : null; return this.gridLineAngles(altAxis, 0.5, minorGridLines.skip, minorGridLines.step, majorGridLineAngles); } radiusCallback(radius, altAxis, skipMajor) { if (altAxis.options.type !== ARC) { const minorAngle = rad(360 / (this.options.categories.length * 2)); const minorRadius = Math.cos(minorAngle) * radius; const majorAngles = this.majorAngles(); const radiusCallback = function(angle) { if (!skipMajor && inArray(angle, majorAngles)) { return radius; } return minorRadius; }; return radiusCallback; } } createPlotBands() { const plotBands = this.options.plotBands || []; const group = this._plotbandGroup = new draw.Group({ zIndex: -1 }); for (let i = 0; i < plotBands.length; i++) { const band = plotBands[i]; const slot = this.plotBandSlot(band); const singleSlot = this.getSlot(band.from); const head = band.from - Math.floor(band.from); slot.startAngle += head * singleSlot.angle; const tail = Math.ceil(band.to) - band.to; slot.angle -= (tail + head) * singleSlot.angle; const ring = ShapeBuilder.current.createRing(slot, { fill: { color: band.color, opacity: band.opacity }, stroke: { opacity: band.opacity } }); group.append(ring); } this.appendVisual(group); } plotBandSlot(band) { return this.getSlot(band.from, band.to - 1); } getSlot(from, to) { const options = this.options; const justified = options.justified; const box = this.box; const divs = this.majorAngles(); const totalDivs = divs.length; const slotAngle = 360 / totalDivs; let fromValue = from; if (options.reverse && !justified) { fromValue = (fromValue + 1) % totalDivs; } fromValue = limitValue(Math.floor(fromValue), 0, totalDivs - 1); let slotStart = divs[fromValue]; if (justified) { slotStart = slotStart - slotAngle / 2; if (slotStart < 0) { slotStart += 360; } } const toValue = limitValue(Math.ceil(to || fromValue), fromValue, totalDivs - 1); const slots = toValue - fromValue + 1; const angle = slotAngle * slots; return new Ring(box.center(), 0, box.height() / 2, slotStart, angle); } slot(from, to) { const slot = this.getSlot(from, to); const startAngle = slot.startAngle + 180; const endAngle = startAngle + slot.angle; return new geom.Arc([ slot.center.x, slot.center.y ], { startAngle: startAngle, endAngle: endAngle, radiusX: slot.radius, radiusY: slot.radius }); } pointCategoryIndex(point) { const length = this.options.categories.length; let index = null; for (let i = 0; i < length; i++) { const slot = this.getSlot(i); if (slot.containsPoint(point)) { index = i; break; } } return index; } } setDefaultOptions(RadarCategoryAxis, { startAngle: 90, labels: { margin: getSpacing(10) }, majorGridLines: { visible: true }, justified: true }); deepExtend(RadarCategoryAxis.prototype, GridLinesMixin); export default RadarCategoryAxis;