UNPKG

@nativescript-community/ui-chart

Version:

A powerful chart / graph plugin, supporting line, bar, pie, radar, bubble, and candlestick charts as well as scaling, panning and animations.

290 lines 13 kB
import { Direction, Style } from '@nativescript-community/ui-canvas'; import { Color } from '@nativescript/core'; import { ColorTemplate } from '../utils/ColorTemplate'; import { Utils } from '../utils/Utils'; import { LineRadarRenderer } from './LineRadarRenderer'; export class RadarChartRenderer extends LineRadarRenderer { constructor(chart, animator, viewPortHandler) { super(animator, viewPortHandler); this.mChart = chart; } get highlightPaint() { if (!this.mHighlightPaint) { this.mHighlightPaint = Utils.getTemplatePaint('black-stroke'); this.mHighlightPaint.setStrokeWidth(2); this.mHighlightPaint.setColor(new Color(255, 255, 187, 115)); } return this.mHighlightPaint; } get webPaint() { if (!this.mWebPaint) { this.mWebPaint = Utils.getTemplatePaint('black-stroke'); } return this.mWebPaint; } drawData(c) { const radarData = this.mChart.data; const mostEntries = radarData.maxEntryCountSet.entryCount; for (const set of radarData.dataSets) { if (set.visible) { this.drawDataSet(c, set, mostEntries); } } } /** * Draws the RadarDataSetF * * @param c * @param dataSet * @param mostEntries the entry count of the dataset with the most entries */ drawDataSet(c, dataSet, mostEntries) { const phaseX = this.animator.phaseX; const phaseY = this.animator.phaseY; const sliceangle = this.mChart.sliceAngle; // calculate the factor that is needed for transforming the value to // pixels const factor = this.mChart.factor; const center = this.mChart.centerOffsets; const pOut = { x: 0, y: 0 }; const surface = Utils.getTempPath(); surface.reset(); let hasMovedToPoint = false; const minVal = this.mChart.yChartMin; const angle = this.mChart.rotationAngle; const entryCount = dataSet.entryCount; if (!this.mLineBuffer || this.mLineBuffer.length < Math.max(entryCount * 2, 2) * 2) { this.mLineBuffer = Utils.createArrayBuffer(Math.max(entryCount * 2, 2) * 2); } const float32arr = this.mLineBuffer; let index = 0; const yProperty = dataSet.yProperty; for (let j = 0; j < dataSet.entryCount; j++) { const e = dataSet.getEntryForIndex(j); const yVal = e[yProperty]; if (yVal === undefined || yVal === null) { continue; } Utils.getPosition(center, (yVal - minVal) * factor * phaseY, sliceangle * j * phaseX + angle, pOut); if (isNaN(pOut.x)) continue; if (!hasMovedToPoint) { float32arr[index++] = pOut.x; float32arr[index++] = pOut.y; hasMovedToPoint = true; } float32arr[index++] = pOut.x; float32arr[index++] = pOut.y; } if (dataSet.entryCount > mostEntries) { // if this is not the largest set, draw a line to the center before closing float32arr[index++] = center.x; float32arr[index++] = center.y; } float32arr[index++] = float32arr[0]; float32arr[index++] = float32arr[1]; const points = Utils.pointsFromBuffer(float32arr); if (__ANDROID__ && Utils.supportsDirectArrayBuffers()) { surface['setLinesBuffer'](points, 0, index); } else { surface.setLines(points, 0, index); } // surface.close(); if (dataSet.drawFilledEnabled) { const renderPaint = this.renderPaint; const previousShader = renderPaint.getShader(); const shader = dataSet.fillShader; if (shader) { renderPaint.setShader(shader); } const drawable = dataSet.fillDrawable; if (drawable) { this.drawFilledPathBitmap(c, surface, drawable, dataSet.fillShader); } else { this.drawFilledPath(c, surface, dataSet.fillColor, dataSet.fillAlpha); } renderPaint.setShader(previousShader); } // draw the line (only if filled is disabled or alpha is below 255) const lineWidth = dataSet.lineWidth; if ((!dataSet.drawFilledEnabled || dataSet.fillAlpha < 255) && lineWidth > 0) { const renderPaint = this.renderPaint; renderPaint.setColor(dataSet.color); renderPaint.setStrokeWidth(lineWidth); renderPaint.setStyle(Style.STROKE); c.drawPath(surface, renderPaint); } // MPPointF.recycleInstance(center); // MPPointF.recycleInstance(pOut); } drawValues(c) { const chart = this.mChart; const data = chart.data; const dataSets = data.dataSets; if (dataSets.some((d) => d.drawValuesEnabled || d.drawIconsEnabled) === false) { return; } const phaseX = this.animator.phaseX; const phaseY = this.animator.phaseY; const sliceangle = chart.sliceAngle; // calculate the factor that is needed for transforming the value to // pixels const factor = chart.factor; const center = chart.centerOffsets; const pOut = { x: 0, y: 0 }; const pIcon = { x: 0, y: 0 }; const yoffset = 5; const customRender = chart.customRenderer; for (let i = 0; i < data.dataSetCount; i++) { const dataSet = data.getDataSetByIndex(i); if (!this.shouldDrawValues(dataSet) || dataSet.entryCount < 1) continue; const drawValues = dataSet.drawValuesEnabled; const drawIcons = dataSet.drawIconsEnabled; if (!drawValues && !drawIcons) { continue; } const yProperty = dataSet.yProperty; if (!this.shouldDrawValues(dataSet)) continue; // apply the text-styling defined by the DataSet this.applyValueTextStyle(dataSet); const formatter = dataSet.valueFormatter; const iconsOffset = dataSet.iconsOffset; const valuesOffset = dataSet.valuesOffset; const paint = this.valuePaint; for (let j = 0; j < dataSet.entryCount; j++) { const entry = dataSet.getEntryForIndex(j); const yVal = entry[yProperty]; if (yVal === undefined || yVal === null) { continue; } Utils.getPosition(center, (yVal - chart.yChartMin) * factor * phaseY, sliceangle * j * phaseX + chart.rotationAngle, pOut); if (drawValues) { this.drawValue(c, chart, dataSet, i, entry, j, (formatter.getRadarLabel || formatter.getFormattedValue).call(formatter, yVal, entry), pOut.x + valuesOffset.x, pOut.y + valuesOffset.y - yoffset, dataSet.getValueTextColor(j), paint, customRender); } if (drawIcons) { Utils.getPosition(center, yVal * factor * phaseY + iconsOffset.y, sliceangle * j * phaseX + chart.rotationAngle, pIcon); //noinspection SuspiciousNameCombination pIcon.y += iconsOffset.x; this.drawIcon(c, chart, dataSet, i, entry, j, dataSet.getEntryIcon(entry), pIcon.x, pIcon.y, customRender); } } // MPPointF.recycleInstance(iconsOffset); } // MPPointF.recycleInstance(center); // MPPointF.recycleInstance(pOut); // MPPointF.recycleInstance(pIcon); } drawExtras(c) { this.drawWeb(c); } drawWeb(c) { const sliceangle = this.mChart.sliceAngle; // calculate the factor that is needed for transforming the value to // pixels const factor = this.mChart.factor; const rotationangle = this.mChart.rotationAngle; const center = this.mChart.centerOffsets; // draw the web lines that come from the center const lineWidth = this.mChart.webLineWidth; if (lineWidth > 0) { const paint = this.webPaint; paint.setStrokeWidth(this.mChart.webLineWidth); paint.setColor(this.mChart.webColor); paint.setAlpha(this.mChart.webAlpha); const xIncrements = 1 + this.mChart.skipWebLineCount; const maxEntryCount = this.mChart.data.maxEntryCountSet.entryCount; const p = { x: 0, y: 0 }; for (let i = 0; i < maxEntryCount; i += xIncrements) { Utils.getPosition(center, this.mChart.yRange * factor, sliceangle * i + rotationangle, p); c.drawLine(center.x, center.y, p.x, p.y, paint); } } // MPPointF.recycleInstance(p); // draw the inner-web const innerWidth = this.mChart.webLineWidthInner; if (innerWidth > 0) { const paint = this.webPaint; paint.setStrokeWidth(this.mChart.webLineWidthInner); paint.setColor(this.mChart.webColorInner); paint.setAlpha(this.mChart.webAlpha); const labelCount = this.mChart.yAxis.mEntryCount; const p1out = { x: 0, y: 0 }; const p2out = { x: 0, y: 0 }; for (let j = 0; j < labelCount; j++) { for (let i = 0; i < this.mChart.data.entryCount; i++) { const r = (this.mChart.yAxis.mEntries[j] - this.mChart.yChartMin) * factor; Utils.getPosition(center, r, sliceangle * i + rotationangle, p1out); Utils.getPosition(center, r, sliceangle * (i + 1) + rotationangle, p2out); c.drawLine(p1out.x, p1out.y, p2out.x, p2out.y, this.mWebPaint); } } } // MPPointF.recycleInstance(p1out); // MPPointF.recycleInstance(p2out); } drawHighlighted(c, indices) { const sliceangle = this.mChart.sliceAngle; // calculate the factor that is needed for transforming the value to // pixels const factor = this.mChart.factor; const center = this.mChart.centerOffsets; const pOut = { x: 0, y: 0 }; const radarData = this.mChart.data; for (const high of indices) { const set = radarData.getDataSetByIndex(high.dataSetIndex); const yProperty = set.yProperty; if (!set || !set.highlightEnabled) continue; const e = set.getEntryForIndex(high.x); if (!this.isInBoundsX(e, set)) continue; const y = e[yProperty] - this.mChart.yChartMin; Utils.getPosition(center, y * factor * this.animator.phaseY, sliceangle * high.x * this.animator.phaseX + this.mChart.rotationAngle, pOut); high.drawX = pOut.x; high.drawY = pOut.y; // draw the lines this.drawHighlightLines(c, pOut.x, pOut.y, set); if (set.drawHighlightCircleEnabled) { if (!isNaN(pOut.x) && !isNaN(pOut.y)) { let strokeColor = set.highlightCircleStrokeColor; if (strokeColor === ColorTemplate.COLOR_NONE) { strokeColor = set.getColor(0); } if (set.highlightCircleStrokeAlpha < 255) { strokeColor = ColorTemplate.colorWithAlpha(strokeColor instanceof Color ? strokeColor : new Color(strokeColor), set.highlightCircleStrokeAlpha); } this.drawHighlightCircle(c, pOut, set.highlightCircleInnerRadius, set.highlightCircleOuterRadius, set.highlightCircleFillColor, strokeColor, set.highlightCircleStrokeWidth); } } } // MPPointF.recycleInstance(center); // MPPointF.recycleInstance(pOut); } drawHighlightCircle(c, point, innerRadius, outerRadius, fillColor, strokeColor, strokeWidth) { c.save(); const paint = Utils.getTempPaint(); if (fillColor && fillColor !== ColorTemplate.COLOR_NONE) { const p = Utils.getTempPath(); p.reset(); p.addCircle(point.x, point.y, outerRadius, Direction.CW); if (innerRadius > 0) { p.addCircle(point.x, point.y, innerRadius, Direction.CCW); } paint.setColor(fillColor); paint.setStyle(Style.FILL); c.drawPath(p, paint); } if (strokeColor && strokeColor !== ColorTemplate.COLOR_NONE) { paint.setColor(strokeColor); paint.setStyle(Style.STROKE); paint.setStrokeWidth(strokeWidth); c.drawCircle(point.x, point.y, outerRadius, paint); } c.restore(); } } //# sourceMappingURL=RadarChartRenderer.js.map