0
0
mirror of https://github.com/ankidroid/Anki-Android.git synced 2024-09-20 12:02:16 +02:00

- Make pieces of the "Cards Types" pie chart start from the same position (12 o' clock, was 3 o'clock) and move in the same direction (clockwise, was anti-clockwise) as in Anki Desktop (solves https://github.com/ankidroid/Anki-Android/issues/3349)

- Make the order of the legend's elements in the statistics charts deterministic (solves https://github.com/ankidroid/Anki-Android/issues/3349)
- Change text of legend item "Suspended" in the "Cards Types" pie chart start to "Suspended+Buried" (solves https://github.com/ankidroid/Anki-Android/issues/3349 and https://github.com/ankidroid/Anki-Android/issues/3562)

- Explain the algorithm used for calculating ticks in ChartBuilder
- Explain why we use LinkedHashMap instead of HashMap (to retain order of Legend Items)
- Adhere to code conventions

- Behave consistently with Anki Desktop in case of no reviews. In that case the pie chart should not be shown at all (it was all yellow). This was reported between the lines of this issue:https://github.com/ankidroid/Anki-Android/issues/3384

- Replace if / else by (mSum == 0) ? 1 : mSum
This commit is contained in:
jvanprehn 2016-05-15 10:13:39 +02:00
parent 983296b169
commit e754ec71a2
10 changed files with 72 additions and 40 deletions

View File

@ -371,31 +371,50 @@ public class ChartBuilder {
return tics;
}
public double ticksCalcY(int pixelDistance, RectangleWrap field, double start, double end) {
double deltaRange = end - start;
int ticlimit = field.height / pixelDistance;
double tics = Math.pow(10, (int) Math.log10(deltaRange / ticlimit));
while (2.0 * (deltaRange / (tics)) <= ticlimit) {
tics /= 2.0;
}
while ((deltaRange / (tics)) / 2 >= ticlimit) {
tics *= 2.0;
}
Timber.d("ChartBuilder ticksCalcY: pixelDistance: %d, ticks: %,.2f", pixelDistance, tics);
return tics;
}
double size = ticsCalc(pixelDistance, field, end - start);
Timber.d("ChartBuilder ticksCalcY: pixelDistance: %d, ticks: %,.2f, start: %,.2f, end: %,.2f, height: %d", pixelDistance, size, start, end, field.height);
return size;
}
public double ticsCalc(int pixelDistance, RectangleWrap field, double deltaRange) {
int ticlimit = field.height / pixelDistance;
double tics = Math.pow(10, (int) Math.log10(deltaRange / ticlimit));
while (2.0 * (deltaRange / (tics)) <= ticlimit) {
tics /= 2.0;
//Make approximation of number of ticks based on desired number of pixels per tick
double numTicks = field.height / pixelDistance;
//Compute size of one tick in graph-units
double delta = deltaRange / numTicks;
//Write size of one tick in the form norm * magn
double dec = Math.floor(Math.log(delta) / Math.log(10));
double magn = Math.pow(10, dec);
double norm = delta / magn; // norm is between 1.0 and 10.0
//Write size of one tick in the form size * magn
//Where size in (1, 2, 2.5, 5, 10)
double size;
if (norm < 1.5) {
size = 1;
} else if (norm < 3) {
size = 2;
// special case for 2.5, requires an extra decimal
if (norm > 2.25) {
size = 2.5;
}
while ((deltaRange / (tics)) / 2 >= ticlimit) {
tics *= 2.0;
} else if (norm < 7.5) {
size = 5;
} else {
size = 10;
}
return tics;
//Compute size * magn so that we return one number
size *= magn;
Timber.d("ChartBuilder ticksCalc : pixelDistance: %d, ticks: %,.2f, deltaRange: %,.2f, height: %d", pixelDistance, size, deltaRange, field.height);
return size;
}
}

View File

@ -1167,8 +1167,8 @@ public class Stats {
public boolean calculateCardTypes(AxisType type) {
mTitle = R.string.stats_cards_types;
mAxisTitles = new int[] { R.string.stats_answer_type, R.string.stats_answers, R.string.stats_cumulative_correct_percentage };
mValueLabels = new int[] {R.string.statistics_mature, R.string.statistics_young_and_learn, R.string.statistics_unlearned, R.string.statistics_suspended};
mColors = new int[] { R.attr.stats_mature, R.attr.stats_young, R.attr.stats_unseen, R.attr.stats_suspended };
mValueLabels = new int[] {R.string.statistics_mature, R.string.statistics_young_and_learn, R.string.statistics_unlearned, R.string.statistics_suspended_and_buried};
mColors = new int[] { R.attr.stats_mature, R.attr.stats_young, R.attr.stats_unseen, R.attr.stats_suspended_and_buried };
mType = type;
ArrayList<double[]> list = new ArrayList<>();
double[] pieData;

View File

@ -49,9 +49,12 @@ public class PieChart implements Drawable, Legendable {
//mValues = new double[] {5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5};
mPercent = new double[mValues.length];
for(double v: mValues) mSum +=v;
mPercent[0]= mValues[0]/ mSum;
double denominator = (mSum == 0) ? 1 : mSum;
mPercent[0]= mValues[0]/ denominator;
for(int i=1; i< mValues.length; i++){
mPercent[i]= mPercent[i-1]+ mValues[i]/ mSum;
mPercent[i]= mPercent[i-1]+ mValues[i]/ denominator;
}
mColorHelper = mColors.length;
if((mValues.length-1)%(mColors.length)==0) mColorHelper = mColors.length-1;
@ -71,6 +74,10 @@ public class PieChart implements Drawable, Legendable {
* @see rendering.Drawable#paint(java.awt.Graphics)
*/
public void paint(GraphicsWrap g){
//Do not show chart if segments are all zero
if(mSum == 0) return;
RectangleWrap field = g.getClipBounds();
float maxSideBorders = Math.max(mPlotSheet.getFrameThickness()[PlotSheet.LEFT_FRAME_THICKNESS_INDEX],
mPlotSheet.getFrameThickness()[PlotSheet.RIGHT_FRAME_THICKNESS_INDEX]);
@ -87,20 +94,22 @@ public class PieChart implements Drawable, Legendable {
float xMiddle = xCenter - (float)(diameter/2.0);
float yMiddle = yCenter - (float)(diameter/2.0);
float currentAngle = 0;
float nextAngle = (float)(360.0* mPercent[0]);
float angleOffSet = -90;
float currentAngle = angleOffSet;
float nextAngle = currentAngle + (float)(360.0* mPercent[0]);
int tmp = 0;
for(int i = 0; i< mPercent.length-1; i++) {
g.setColor(mColors[i% mColorHelper]);
g.fillArc(xMiddle, yMiddle, (int)diameter, (int)(diameter), currentAngle, nextAngle - currentAngle);
g.fillArc(xMiddle, yMiddle, (int)diameter, (int)(diameter), -1*currentAngle, -1*(nextAngle - currentAngle));
currentAngle = nextAngle;
nextAngle = (int)(360.0* mPercent[i+1]);
nextAngle = (int)(angleOffSet + 360.0* mPercent[i+1]);
tmp = i;
}
tmp++;
//last one does need some corrections to fill a full circle:
g.setColor(mColors[tmp% mColorHelper]);
g.fillArc(xMiddle, yMiddle, diameter, diameter, currentAngle, 360 - currentAngle);
g.fillArc(xMiddle, yMiddle, diameter, diameter, -1*currentAngle, -1*(360 + angleOffSet - currentAngle));
g.setColor(ColorWrap.black);
g.drawArc(xMiddle, yMiddle, diameter, diameter, 0, 360);
@ -113,8 +122,8 @@ public class PieChart implements Drawable, Legendable {
if(j != 0)
oldPercent = mPercent[j-1];
String text = ""+Math.round((((mPercent[j]- oldPercent))*100)*100)/100.0+"%";
float x = (float)(xCenter+Math.cos((oldPercent+(mPercent[j]- oldPercent)*0.5)*360*Math.PI/180.0)*0.375*diameter)-20;
float y = (float)(yCenter-Math.sin((oldPercent+(mPercent[j]- oldPercent)*0.5)*360*Math.PI/180.0)*0.375*diameter);
float x = (float)(xCenter+Math.cos(-1*((oldPercent+(mPercent[j]- oldPercent)*0.5)*360+angleOffSet)*Math.PI/180.0)*0.375*diameter)-20;
float y = (float)(yCenter-Math.sin(-1*((oldPercent+(mPercent[j]- oldPercent)*0.5)*360+angleOffSet)*Math.PI/180.0)*0.375*diameter);
FontMetricsWrap fm = g.getFontMetrics();
float width = fm.stringWidth(text);
float height = fm.getHeight();

View File

@ -22,7 +22,8 @@ import com.wildplot.android.rendering.graphics.wrapper.*;
import com.wildplot.android.rendering.interfaces.Drawable;
import com.wildplot.android.rendering.interfaces.Legendable;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
@ -90,7 +91,10 @@ public class PlotSheet implements Drawable {
* the ploting screens, screen 0 is the only one in single mode
*/
Vector<MultiScreenPart> screenParts = new Vector<>();
private HashMap<String, ColorWrap> mLegendMap = new HashMap<>();
//Use LinkedHashMap so that the legend items will be displayed in the order
//in which they were added
private Map<String, ColorWrap> mLegendMap = new LinkedHashMap<>();
private boolean mDrawablesPrepared = false;
/**

View File

@ -22,7 +22,7 @@
<string name="statistics_mature">Mature</string>
<string name="statistics_young_and_learn">Young and learn</string>
<string name="statistics_unlearned">Unseen</string>
<string name="statistics_suspended">Suspended</string>
<string name="statistics_suspended_and_buried">Suspended+Buried</string>
<string name="statistics_relearn">Relearn</string>
<string name="statistics_learn">Learn</string>
<string name="statistics_cram">Cram</string>

View File

@ -70,7 +70,7 @@
<attr name="stats_hours" format="color"/>
<attr name="stats_counts" format="color"/>
<attr name="stats_unseen" format="color"/>
<attr name="stats_suspended" format="color"/>
<attr name="stats_suspended_and_buried" format="color"/>
<attr name="stats_cumulative" format="color"/>
<!-- Reviewer other colors -->
<attr name="topBarColor" format="color"/>

View File

@ -25,7 +25,7 @@
<color name="stats_hours">#ccc</color>
<color name="stats_counts">#E6000000</color>
<color name="stats_unseen">#000</color>
<color name="stats_suspended">#ff0</color>
<color name="stats_suspended_and_buried">#ff0</color>
<color name="stats_cumulative">#000000</color>
<color name="transparent">#00000000</color>
<color name="white">#ffffff</color>

View File

@ -64,7 +64,7 @@
<item name="stats_hours">@color/material_grey_500</item>
<item name="stats_counts">@color/material_grey_800</item>
<item name="stats_unseen">@color/material_grey_800</item>
<item name="stats_suspended">#ff0</item>
<item name="stats_suspended_and_buried">#ff0</item>
<item name="stats_cumulative">@color/material_grey_800</item>
<!-- Browser colors -->
<item name="suspendedColor">#A8A634</item>

View File

@ -69,7 +69,7 @@
<item name="stats_hours">#ccc</item>
<item name="stats_counts">#E6000000</item>
<item name="stats_unseen">#000</item>
<item name="stats_suspended">#ff0</item>
<item name="stats_suspended_and_buried">#ff0</item>
<item name="stats_cumulative">@color/stats_cumulative</item>
<!-- Browser colors -->
<item name="suspendedColor">@color/material_grey_700</item>

View File

@ -82,7 +82,7 @@ APIs. It's visible when there aren't enough decks to fill the screen.
<item name="stats_hours">#ccc</item>
<item name="stats_counts">#E6000000</item>
<item name="stats_unseen">#000</item>
<item name="stats_suspended">#ff0</item>
<item name="stats_suspended_and_buried">#ff0</item>
<item name="stats_cumulative">@color/stats_cumulative</item>
<!-- Browser colors -->
<item name="suspendedColor">#FFFFB2</item>