private Item createItem(String label, float percent, int sliceColor, int itemColor) { Item it = new Item(); it.mLabel = label; it.mItemColor = itemColor; it.cSliceColor = sliceColor; it.cPercent = percent; // Log.d(TAG, "Percent for "+it.mLabel+": "+it.cPercent); // Calculate the highlight color. Saturate at 0xff to make sure that high values // don't result in aliasing. it.mItemHighlight = Color.argb( 0xff, Math.min((int) (mHighlightStrength * (float) Color.red(itemColor)), 0xff), Math.min((int) (mHighlightStrength * (float) Color.green(itemColor)), 0xff), Math.min((int) (mHighlightStrength * (float) Color.blue(itemColor)), 0xff)); it.cSliceHighlight = Color.argb( 0xff, Math.min((int) (mHighlightStrength * (float) Color.red(sliceColor)), 0xff), Math.min((int) (mHighlightStrength * (float) Color.green(sliceColor)), 0xff), Math.min((int) (mHighlightStrength * (float) Color.blue(sliceColor)), 0xff)); float centerX = mPieBounds.width() / 2; float centerY = mPieBounds.height() / 2; float itemW = (mPieBounds.width() / 2) * it.cPercent; float itemH = (mPieBounds.height() / 2) * it.cPercent; it.cSliceBounds = new RectF(centerX - itemW, centerY - itemH, centerX + itemW, centerY + itemH); return it; }
/** Do all of the recalculations needed when the data array changes. */ private void onDataChanged() { int angle = 360 / mData.size(); // This is the extra degrees that cannot be equally divided by the number of sides int extra = 360 % mData.size(); // When the data changes, we have to recalculate // all of the angles. int currentAngle = 0; for (Item it : mData) { // Adds the extra degrees to the last slice to ensue no gaps if (mData.get(mData.size() - 1).mLabel.equals(it.mLabel)) { it.mEndAngle = currentAngle + angle + extra; } else { it.mEndAngle = currentAngle + angle; } it.mStartAngle = currentAngle; currentAngle = it.mEndAngle; // Recalculate the gradient shaders. There are // three values in this gradient, even though only // two are necessary, in order to work around // a bug in certain versions of the graphics engine // that expects at least three values if the // positions array is non-null. // it.mItemShader = new SweepGradient( mPieBounds.width() / 2.0f, mPieBounds.height() / 2.0f, new int[] { it.mItemHighlight, it.mItemHighlight, it.mItemColor, it.mItemColor, }, new float[] { 0, (float) (360 - it.mEndAngle) / 360.0f, (float) (360 - it.mStartAngle) / 360.0f, 1.0f }); it.cSliceShader = new SweepGradient( mPieBounds.width() / 2.0f, mPieBounds.height() / 2.0f, new int[] { it.cSliceHighlight, it.cSliceHighlight, it.cSliceColor, it.cSliceColor, }, new float[] { 0, (float) (360 - it.mEndAngle) / 360.0f, (float) (360 - it.mStartAngle) / 360.0f, 1.0f }); } calcCurrentItem(); onScrollFinished(); }
@Override protected void onDraw(Canvas canvas) { float ringWidth = textHeight + 4; int height = getMeasuredHeight(); int width = getMeasuredWidth(); int px = width / 2; int py = height / 2; Point center = new Point(px, py); int radius = Math.min(px, py) - 2; RectF boundingBox = new RectF(center.x - radius, center.y - radius, center.x + radius, center.y + radius); RectF innerBoundingBox = new RectF( center.x - radius + ringWidth, center.y - radius + ringWidth, center.x + radius - ringWidth, center.y + radius - ringWidth); float innerRadius = innerBoundingBox.height() / 2; RadialGradient borderGradient = new RadialGradient( px, py, radius, borderGradientColors, borderGradientPositions, TileMode.CLAMP); Paint pgb = new Paint(); pgb.setShader(borderGradient); Path outerRingPath = new Path(); outerRingPath.addOval(boundingBox, Direction.CW); canvas.drawPath(outerRingPath, pgb); LinearGradient skyShader = new LinearGradient( center.x, innerBoundingBox.top, center.x, innerBoundingBox.bottom, skyHorizonColorFrom, skyHorizonColorTo, TileMode.CLAMP); Paint skyPaint = new Paint(); skyPaint.setShader(skyShader); LinearGradient groundShader = new LinearGradient( center.x, innerBoundingBox.top, center.x, innerBoundingBox.bottom, groundHorizonColorFrom, groundHorizonColorTo, TileMode.CLAMP); Paint groundPaint = new Paint(); groundPaint.setShader(groundShader); float tiltDegree = pitch; while (tiltDegree > 90 || tiltDegree < -90) { if (tiltDegree > 90) tiltDegree = -90 + (tiltDegree - 90); if (tiltDegree < -90) tiltDegree = 90 - (tiltDegree + 90); } float rollDegree = roll; while (rollDegree > 180 || rollDegree < -180) { if (rollDegree > 180) rollDegree = -180 + (rollDegree - 180); if (rollDegree < -180) rollDegree = 180 - (rollDegree + 180); } Path skyPath = new Path(); skyPath.addArc(innerBoundingBox, -rollDegree, (180 + (2 * rollDegree))); canvas.rotate(-tiltDegree, px, py); canvas.drawOval(innerBoundingBox, groundPaint); canvas.drawPath(skyPath, skyPaint); canvas.drawPath(skyPath, markerPaint); int markWidth = radius / 3; int startX = center.x - markWidth; int endX = center.x + markWidth; Log.d("PAARV ", "Roll " + String.valueOf(rollDegree)); Log.d("PAARV ", "Pitch " + String.valueOf(tiltDegree)); double h = innerRadius * Math.cos(Math.toRadians(90 - tiltDegree)); double justTiltX = center.x - h; float pxPerDegree = (innerBoundingBox.height() / 2) / 45f; for (int i = 90; i >= -90; i -= 10) { double ypos = justTiltX + i * pxPerDegree; if ((ypos < (innerBoundingBox.top + textHeight)) || (ypos > innerBoundingBox.bottom - textHeight)) continue; canvas.drawLine(startX, (float) ypos, endX, (float) ypos, markerPaint); int displayPos = (int) (tiltDegree - i); String displayString = String.valueOf(displayPos); float stringSizeWidth = textPaint.measureText(displayString); canvas.drawText( displayString, (int) (center.x - stringSizeWidth / 2), (int) (ypos) + 1, textPaint); } markerPaint.setStrokeWidth(2); canvas.drawLine( center.x - radius / 2, (float) justTiltX, center.x + radius / 2, (float) justTiltX, markerPaint); markerPaint.setStrokeWidth(1); Path rollArrow = new Path(); rollArrow.moveTo(center.x - 3, (int) innerBoundingBox.top + 14); rollArrow.lineTo(center.x, (int) innerBoundingBox.top + 10); rollArrow.moveTo(center.x + 3, innerBoundingBox.top + 14); rollArrow.lineTo(center.x, innerBoundingBox.top + 10); canvas.drawPath(rollArrow, markerPaint); String rollText = String.valueOf(rollDegree); double rollTextWidth = textPaint.measureText(rollText); canvas.drawText( rollText, (float) (center.x - rollTextWidth / 2), innerBoundingBox.top + textHeight + 2, textPaint); canvas.restore(); canvas.save(); canvas.rotate(180, center.x, center.y); for (int i = -180; i < 180; i += 10) { if (i % 30 == 0) { String rollString = String.valueOf(i * -1); float rollStringWidth = textPaint.measureText(rollString); PointF rollStringCenter = new PointF(center.x - rollStringWidth / 2, innerBoundingBox.top + 1 + textHeight); canvas.drawText(rollString, rollStringCenter.x, rollStringCenter.y, textPaint); } else { canvas.drawLine( center.x, (int) innerBoundingBox.top, center.x, (int) innerBoundingBox.top + 5, markerPaint); } canvas.rotate(10, center.x, center.y); } canvas.restore(); canvas.save(); canvas.rotate(-1 * (bearing), px, py); double increment = 22.5; for (double i = 0; i < 360; i += increment) { CompassDirection cd = CompassDirection.values()[(int) (i / 22.5)]; String headString = cd.toString(); float headStringWidth = textPaint.measureText(headString); PointF headStringCenter = new PointF(center.x - headStringWidth / 2, boundingBox.top + 1 + textHeight); if (i % increment == 0) canvas.drawText(headString, headStringCenter.x, headStringCenter.y, textPaint); else canvas.drawLine( center.x, (int) boundingBox.top, center.x, (int) boundingBox.top + 3, markerPaint); canvas.rotate((int) increment, center.x, center.y); } canvas.restore(); RadialGradient glassShader = new RadialGradient( px, py, (int) innerRadius, glassGradientColors, glassGradientPositions, TileMode.CLAMP); Paint glassPaint = new Paint(); glassPaint.setShader(glassShader); canvas.drawOval(innerBoundingBox, glassPaint); canvas.drawOval(boundingBox, circlePaint); circlePaint.setStrokeWidth(2); canvas.drawOval(innerBoundingBox, circlePaint); canvas.restore(); }
private int calcY(float y) { RectF r = mPlotBounds; return Math.round(r.top + r.height() * (1 - (y - getYMin()) / (getYMax() - getYMin()))); }
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); Log.d(TAG, "Slice Count: " + mData.size()); if (mData.size() > 0) { // // Set dimensions for text, pie chart, etc // // Account for padding float xpad = (float) (getPaddingLeft() + getPaddingRight()); float ypad = (float) (getPaddingTop() + getPaddingBottom()); // Account for the label if (mShowText) xpad += mTextWidth; float ww = (float) w - xpad; float hh = (float) h - ypad; // Figure out how big we can make the pie. float diameter = Math.min(ww, hh); mPieBounds = new RectF(0.0f, 0.0f, diameter, diameter); mPieBounds.offsetTo(getPaddingLeft(), getPaddingTop()); // Log.d(TAG, "mPieBounds>> "+mPieBounds); mPointerY = mTextY - (mTextHeight / 2.0f); float pointerOffset = mPieBounds.centerY() - mPointerY; // Make adjustments based on text position if (mTextPos == TEXTPOS_LEFT) { mTextPaint.setTextAlign(Paint.Align.RIGHT); if (mShowText) mPieBounds.offset(mTextWidth, 0.0f); mTextX = mPieBounds.left; if (pointerOffset < 0) { pointerOffset = -pointerOffset; mCurrentItemAngle = 225; } else { mCurrentItemAngle = 135; } mPointerX = mPieBounds.centerX() - pointerOffset; } else { mTextPaint.setTextAlign(Paint.Align.LEFT); mTextX = mPieBounds.right; if (pointerOffset < 0) { pointerOffset = -pointerOffset; mCurrentItemAngle = 315; } else { mCurrentItemAngle = 45; } mPointerX = mPieBounds.centerX() + pointerOffset; } mShadowBounds = new RectF( mPieBounds.left + 10, mPieBounds.bottom + 10, mPieBounds.right - 10, mPieBounds.bottom + 20); // Lay out the child view that actually draws the pie. mPieView.layout( (int) mPieBounds.left, (int) mPieBounds.top, (int) mPieBounds.right, (int) mPieBounds.bottom); mPieView.setPivot(mPieBounds.width() / 2, mPieBounds.height() / 2); mPointerView.layout(0, 0, w, h); onDataChanged(); } }