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:
parent
983296b169
commit
e754ec71a2
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -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>
|
||||
|
@ -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"/>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user