I am using GraphView Library for creating Bar graph as shown in picture, I need to reduce width of bars and increase space between bars.
Note- Red bars are currently what I'm getting and what I actually need is shown in black.
Below is the code snippet for the above graph:
GraphViewSeriesStyle barStyle = new GraphViewSeriesStyle();
barStyle.thickness = 5;
barStyle.setValueDependentColor(new ValueDependentColor() {
#Override
public int get(GraphViewDataInterface data) {
return Color.rgb(205, 0, 0);
}
});
// init example series data
GraphViewSeries scoreSeries = new GraphViewSeries(
"HealthCare Bar Graph", barStyle, new GraphViewData[] {
new GraphViewData(1, rsCVD),
new GraphViewData(2, rsHypertension4),
new GraphViewData(3, rsHypertension2),
new GraphViewData(4, rsHypertension1) });
GraphView graphView = new BarGraphView(this // context
, "GRAPH_VIEW_HEADING" // heading
);
graphView.setHorizontalLabels(new String[] { "1", "2",
"3", "4" });
graphView.addSeries(scoreSeries);
graphView.setViewPort(0, 25);
graphView.setScalable(true);
graphView.getGraphViewStyle().setHorizontalLabelsColor(Color.BLACK);
graphView.getGraphViewStyle().setVerticalLabelsColor(Color.BLACK);
graphView.getGraphViewStyle().setTextSize(16);
graphView.getGraphViewStyle().setGridColor(Color.WHITE);
// graphView.getGraphViewStyle().setLegendWidth(legendWidth)
int maxValue = myScore+1;
// search the interval between 2 vertical labels
double interval;
if (maxValue >= 0 && maxValue < 3) {
interval = 0.5; // increment of 1 between each label
} else if (maxValue >= 3 && maxValue < 55) {
interval = 5; // increment of 5 between each label
} else if (maxValue >= 55 && maxValue <= 110) {
interval = 10; // increment of 10 between each label
} else {
interval = 20; // increment of 20 between each label
}
// search the top value of our graph
int maxLabel = maxValue;
while (maxLabel % interval != 0) {
maxLabel++;
}
// set manual bounds
graphView.setManualYAxisBounds(maxLabel, 0);
// indicate number of vertical labels
int numVerticalLabels = (int) ((int) maxLabel / interval + 1);
Log.v(TAG, "numVerticalLabels: " + numVerticalLabels);
graphView.getGraphViewStyle().setNumVerticalLabels(numVerticalLabels);
graphView.getGraphViewStyle().setVerticalLabelsWidth(20);
// graphView.getGraphViewStyle().setLegendWidth(20);
graphView.getGraphViewStyle().setLegendSpacing(30);
// LinearLayout layout = (LinearLayout) findViewById(R.id.layout);
m_llayForRiskGraphContainer.addView(graphView);
there's currently no build in method to do this. but if you want to, you can easily modify the code. The point where you can add a spacing is here:
BarGraphView.java Line 95:
float left = (i * colwidth) + horstart -offset;
float top = (border - y) + graphheight;
float right = ((i * colwidth) + horstart) + (colwidth - 1) -offset;
canvas.drawRect(left, top, right, graphheight + border - 1, paint);
Just add a few pixels to left and remove a few pixels from right and it will look like you want.
https://github.com/jjoe64/GraphView/blob/master/src/main/java/com/jjoe64/graphview/BarGraphView.java#L97
Related
Problem:
MPAndroidChart calculates grid and label position nicely for decimal values but not so for a date/time axis.
I would like to have label positions justified to exactly midnight eg. with a x-axis range of 4 days on:
[26.1-00h, 27.1-00h, 28.1-00h,29.1-00h, 30.1-00h]
Or if the range is eg. only 2 days:
[26.1-00h, 26.1-12h, 27.1-00h, 27.1-12h,28.1-00h]
etc.
What I tried:
Adapting the solution of MPAndroidChart x-axis date/time label formatting but it didn't work for recent release 3.1.0 of MPAndroidChart.
Correcting the Chart min and max by using setAxisMinimum() and setAxisMaximum() to midnight timestamps.
Playing with different value scaling.
Setting the granularity with setGranularity() to a whole day, but then datapoints snaps away from its original to ganularity positions.
The calculation of the grid origin and spacing seems to be done in computeAxisValues() of class AxisRenderer but this class cant be overloaded (?)
Is there a way to control the positioning of the x-axis labels without changing the library?
Answering my own Question:
Add the Date format as well as the scaling constants:
private static final long MS_PER_XSCALE = 1000 * 60; // scale to minute resolution
private static final long XSCALE_ONE_DAY = 60 * 24; // one day
private final SimpleDateFormat xAxisDataFormat_DD_MMM_H = new SimpleDateFormat("dd.MMM'_'H'h'", Locale.ENGLISH);
private final SimpleDateFormat xAxisDataFormat_DD_MMM = new SimpleDateFormat("dd.MMM", Locale.ENGLISH);
private static final long TIMEOFFSET = TimeZone.getDefault().getRawOffset();
Set a customized Date Axis Renderer as well as the Date Formatter in onCreate() of the Activity:
chart.setXAxisRenderer(new DateXAxisRenderer(chart.getViewPortHandler(), chart.getXAxis(), chart.getTransformer(null)));
chart.getXAxis().setValueFormatter(new ValueFormatter() {
#Override
public String getFormattedValue(float value) {
if ((int) value / XSCALE_ONE_DAY * XSCALE_ONE_DAY == value)
return xAxisDataFormat_DD_MMM.format(new Date((long) value * MS_PER_XSCALE - TIMEOFFSET));
else
return xAxisDataFormat_DD_MMM_H.format(new Date((long) value * MS_PER_XSCALE - TIMEOFFSET));
}
});
Implement the Date Axis Renderer as follows:
class DateXAxisRenderer extends XAxisRenderer {
public DateXAxisRenderer(ViewPortHandler viewPortHandler, XAxis xAxis, Transformer trans) {
super(viewPortHandler, xAxis, trans);
}
#Override
protected void computeAxisValues(float min, float max) {
int day_fraction[] = {1,2,3,4,6,8,12,24};
float interval=0;
int labelCount=0;
float xMin = min;
float xMax = max;
xMax -= xMax % XSCALE_ONE_DAY;
xMin += XSCALE_ONE_DAY - (xMin % XSCALE_ONE_DAY);
int days = (int) ((xMax - xMin) / XSCALE_ONE_DAY);
float days_interval = days / 3;
if (days_interval > 0) {
interval = days_interval * XSCALE_ONE_DAY;
labelCount = (int) ((xMax - xMin) / interval);
}
if (days_interval == 0 || labelCount<3) {
int i = day_fraction.length-1;
do {
xMax = max - max % (XSCALE_ONE_DAY / day_fraction[i]);
xMin = min + (XSCALE_ONE_DAY / day_fraction[i] - (min % (XSCALE_ONE_DAY / day_fraction[i])));
labelCount = (int) ((xMax - xMin) / (XSCALE_ONE_DAY / day_fraction[i]));
} while (labelCount > 4 && i-- > 0);
interval = (xMax - xMin) / labelCount;
}
if (labelCount == 0 /*|| range <= 0 || Double.isInfinite(range)*/) {
mAxis.mEntries = new float[]{};
mAxis.mCenteredEntries = new float[]{};
mAxis.mEntryCount = 0;
return;
}
labelCount++; // add last label
//Timber.i("corrected min:" + xMin + ", max:" + xMax + ", interval:" + interval + ", labelcount:" + labelCount);
mAxis.mEntries = new float[labelCount];
float v = xMin;
for (int i = 0; i < labelCount; i++) {
mAxis.mEntries[i] = v;
Timber.i("Label " + i + " at:" + mAxis.mEntries[i] + " day:" + mAxis.mEntries[i] / XSCALE_ONE_DAY);
v += interval;
}
//mAxis.setLabelCount(labelCount);
//mAxis.setGranularityEnabled(false);
mAxis.mEntryCount = labelCount;
}
}
That's it!
Remark: The range which is nicely presented isl days down to minutes but i you need years, months or seconds you have to adapt the formatter as well as the implemented computeAxisValues() the it accordingly.
I need to know why this extraspace is added as left margin. Due to this wakllpaper is not setting properly in my app. If i try to set leftmost portion as wallpaper then centre portion is getting set as wallpaper due to this extraspace margin.
cropImageAndSetWallpaper(android.net.Uri uri, com.android.wallpapercropper.WallpaperCropActivity$OnBitmapCroppedHandler onBitmapCroppedHandler, boolean finishActivityWhenDone)
boolean centerCrop = getResources().getBoolean(R.bool.center_crop);
// Get the crop
boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
Display d = getWindowManager().getDefaultDisplay();
Point displaySize = new Point();
d.getSize(displaySize);
boolean isPortrait = displaySize.x < displaySize.y;
Point defaultWallpaperSize = getDefaultWallpaperSize(getResources(),
getWindowManager());
// Get the crop
RectF cropRect = mCropView.getCrop();
Point inSize = mCropView.getSourceDimensions();
int cropRotation = mCropView.getImageRotation();
float cropScale = mCropView.getWidth() / (float) cropRect.width();
Matrix rotateMatrix = new Matrix();
rotateMatrix.setRotate(cropRotation);
float[] rotatedInSize = new float[] { inSize.x, inSize.y };
rotateMatrix.mapPoints(rotatedInSize);
rotatedInSize[0] = Math.abs(rotatedInSize[0]);
rotatedInSize[1] = Math.abs(rotatedInSize[1]);
// Due to rounding errors in the cropview renderer the edges can be slightly offset
// therefore we ensure that the boundaries are sanely defined
cropRect.left = Math.max(0, cropRect.left);
cropRect.right = Math.min(rotatedInSize[0], cropRect.right);
cropRect.top = Math.max(0, cropRect.top);
cropRect.bottom = Math.min(rotatedInSize[1], cropRect.bottom);
// ADJUST CROP WIDTH
// Extend the crop all the way to the right, for parallax
// (or all the way to the left, in RTL)
float extraSpace;
if (centerCrop) {
extraSpace = 2f * Math.min(rotatedInSize[0] - cropRect.right, cropRect.left);
} else {
extraSpace = ltr ? rotatedInSize[0] - cropRect.right : cropRect.left;
}
// Cap the amount of extra width
float maxExtraSpace = defaultWallpaperSize.x / cropScale - cropRect.width();
extraSpace = Math.min(extraSpace, maxExtraSpace);
if (centerCrop) {
cropRect.left -= extraSpace / 2f;
cropRect.right += extraSpace / 2f;
} else {
if (ltr) {
cropRect.right += extraSpace;
} else {
cropRect.left -= extraSpace;
}
}
// ADJUST CROP HEIGHT
if (isPortrait) {
cropRect.bottom = cropRect.top + defaultWallpaperSize.y / cropScale;
} else { // LANDSCAPE
float extraPortraitHeight =
defaultWallpaperSize.y / cropScale - cropRect.height();
float expandHeight =
Math.min(Math.min(rotatedInSize[1] - cropRect.bottom, cropRect.top),
extraPortraitHeight / 2);
cropRect.top -= expandHeight;
cropRect.bottom += expandHeight;
}
final int outWidth = (int) Math.round(cropRect.width() * cropScale);
final int outHeight = (int) Math.round(cropRect.height() * cropScale);
Runnable onEndCrop = new Runnable() {
public void run() {
if (finishActivityWhenDone) {
setResult(Activity.RESULT_OK);
finish();
}
}
};
BitmapCropTask cropTask = new BitmapCropTask(this, uri,
cropRect, cropRotation, outWidth, outHeight, true, false, onEndCrop);
if (onBitmapCroppedHandler != null) {
cropTask.setOnBitmapCropped(onBitmapCroppedHandler);
}
cropTask.execute();
Extra space is added to the wallpaper to allow for a parallax effect. In case your phone uses a right-to-left layout, this space is added to the left of the crop you chose. Google's launcher starts out on the rightmost page in RTL layouts.
If you choose a crop on the left side of the picture, then the expansion will take place on the right side of the crop, an you will see mainly this extension on the main page of the launcher.
I'm in a tremendous bind with a last minute request on a consulting project I'm working on.
Essentially here is what I am trying to accomplish:
I have a surfaceview that draws a series of randomly sized circles. Each circle can have a radius from 50-100.
The x,y values are randomly generated along with a random radius
Each circle is created as an object representing that circle (x, y coord's and radius) and it is added to a list.
Once they are all created they are drawn.
The problem is I want to make sure none of these circles overlap.
I'm struggling a bit. This seems like it's shouldn't be all that difficult but it is for me unfortunately.
Here's my code so far (I know it's not close...be kind):
x = 100 + (int) (Math.random() * (mCanvasWidth - 200));
y = 100 + (int) (Math.random() * (mCanvasHeight - 200));
radius = 50 + (int) (Math.random() * 99);
color[0] = (float) (Math.random() * 360);
color[1] = 1;
color[2] = 1;
String radVal = String.valueOf(radius);
circle circ = new circle(x, y, radius, Color.HSVToColor(128, color), radVal);
boolean addit = true;
for (dot d : Dots) {
int leftSide = d.get_x() - radius;
int rightSide = d.get_x() + radius;
int xBoundary = x + radius;
int yBoundary = y + radius;
int exist_xLeft = d.get_x() - d.get_radius();
int exist_xRight = d.get_x() + d.get_radius();
int exist_yTop = d.get_y() - d.get_radius();
int exist_yBottom = d.get_y() + d.get_radius();
if ((xBoundary > exist_xLeft) && (xBoundary < exist_xRight))
{
if (yBoundary > (exist_yTop) && (yBoundary < exist_yBottom)) {
addit = false;
break;
}
}
}
if (addit)
circles.add(mdot);
if (circles.size() >= 5)
running = false;
Then it iterates the circles list and draws them to the canvas.
Any suggestions on where I'm failing in the collision detection?
You can detect if 2 circles are colliding like this:
Given:
centerpoints cx1,cy1 & cx2,cy2
and given radii r1 & r2,
Then you can determine if the 2 circles are colliding:
areColliding=((cx2-cx1)*(cx2-cx1)+(cy2-cy1)*(cy2-cy1))<((r1+r2)*(r1+r2));
How can I get current position of thumb in pixel for SeekBar?
Currently I am trying to get the position on the bases of calculation.
Screen width, Seek Bar width, current seek progress and all. But I am not able to get exact position out of it.
Do any one have any idea?
Coding for same is as below.
I want to drow one component on top of SeekBar thumb.
translation = calculateTranslation(this.deviceScreenWidth, seekBarWidth, seekBar1T.getMax(), Integer.valueOf(ConstantData.seekbar_fifth.toString()), topComponentWidth, 0);
if (currentapiVersion < android.os.Build.VERSION_CODES.HONEYCOMB){
TranslateAnimation anim = new TranslateAnimation(translation - 1,
translation, 0, 0);
anim.setFillAfter(true);
anim.setDuration(0);
edtTextRodUpDown.startAnimation(anim);
}else{
edtTextRodUpDown.setTranslationX(translation);
}
and calculate Translation like
private float calculateTranslation(int screenWidth, int seekBarWidth, int seekMaxProgress, int currentProgress, int componentWidth, int extraDifference){
double calculatedPosition = 0f;
calculatedPosition = (double)((double)(seekBarWidth-((screenWidth-seekBarWidth))) / (double)seekMaxProgress) * (double)currentProgress;
calculatedPosition = calculatedPosition - (double)(componentWidth/2);
calculatedPosition = calculatedPosition + extraDifference;
Double d = new Double(calculatedPosition);
if(d < 0){
return 0.0f;
}else if(d + componentWidth > screenWidth){
return screenWidth-componentWidth;
}else{
return d.floatValue();
}
}
I did this:
int width = seekBar.getWidth()
- seekBar.getPaddingLeft()
- seekBar.getPaddingRight();
int thumbPos = seekBar.getPaddingLeft()
+ width
* seekBar.getProgress()
/ seekBar.getMax();
You can use the getBounds() to get this info.
This sample code below is for instance aligning a TextView with the seekbar thumb position.
TextView sliderIndicator = ...
Rect bounds = seekBar.getThumb().getBounds();
sliderIndicator.setTranslationX(seekBar.getLeft() + bounds.left);
The seekbar thumb has a thumb offset, which is basically a slight shift to the right. So you have to make sure that you take this into account as well:
int thumbPos = seekbar.getMeasuredWidth() * seekbar.getProgress() / seekbar.getMax() - seekbar.getThumbOffset();
I'm trying to change the background color of a layout but depending on a value.
For example. 100 means read, 75: orange 60: yellow-ish and 20 like blue.
Also, have a transition between each color.
I'm new on Android development and I'm not sure exactly what to search for. If you can point me in the right direction, class, website or something.
update
I'm currently trying:
if(percentage <= 100 && percentage >= 85) {
// red
} else if(percentage < 85 && percentage >= 70) {
}
...
Try something like below -
In your Layout, assign an id to the View whose background you want to change, for e.g.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/linear"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:background="#e5e5e5">
<!-- Other Views -->
</LinearLayout>
then in Activity -
LinearLayout ll = findViewById(R.id.linear);
if(percentage <= 100 && percentage >= 85) ll.setBackgroundColor(Color.RED);
else if(percentage < 85 && percentage >= 70) ll.setBackgroundColor(Color.BLUE);
I put together a demo. Assuming
amount is from 0 to 100
0 = rgb(0, 0, 255) - blue
50 = rgb(255, 255, 0) - yellow
100 = rgb(255, 0, 0) - red
This is a sample activity changing color every 2 seconds:
class BackgroundActivity : Activity() {
private lateinit var root: LinearLayout
private val values = arrayOf(0F, 40F, 60F, 100F, 10F)
private var counter = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_background)
root = findViewById(R.id.background)
val timer = Timer()
val task = object : TimerTask() {
override fun run() {
changeBackground(values[counter])
counter++
if (counter >= values.size)
timer.cancel()
}
}
timer.schedule(task, 0, 2000)
}
private fun changeBackground(amount: Float) {
val r = Math.min(255*amount*2/100, 255F)
val g = if (50 > amount) 255*amount*2/100 else 255*(100-amount)*2/100
val b = Math.max(255*(1-amount*2/100), 0F)
val color = getIntFromColor(r.toInt(), g.toInt(), b.toInt())
runOnUiThread {
root.setBackgroundColor(color)
}
}
private fun getIntFromColor(r: Int, g: Int, b: Int): Int {
val red = r shl 16 and 0x00FF0000 //Shift red 16-bits and mask out other stuff
val green = g shl 8 and 0x0000FF00 //Shift Green 8-bits and mask out other stuff
val blue = b and 0x000000FF //Mask out anything not blue.
return -0x1000000 or red or green or blue //0xFF000000 for 100% Alpha. Bitwise OR everything together.
}
}
The important part is the changeBackground() method - based on the amount calculates final color (int).
I am not really sure about the transition.
(thanks #initramfs for this answer)
I ended up using something else
boolean good = false;
double percentage = getPercentage((int) temp);
int screenHeight = getScreenHeight();
int pos1 = 0, pos2 = 0;
Integer[] firstColor = new Integer[]{0, 155, 255}, secondColor = new Integer[]{255, 152, 0};
if (percentage <= 0) {
firstColor = new Integer[]{0, 155, 255};
secondColor = new Integer[]{163, 235, 255};
pos1 = 0;
pos2 = 50;
good = true;
}
if (percentage <= 50 && !good) {
firstColor = new Integer[]{0, 155, 255};
secondColor = new Integer[]{163, 235, 255};
pos1 = 0;
pos2 = 50;
good = true;
}
if (percentage <= 100 && !good) {
firstColor = new Integer[]{163, 235, 255};
secondColor = new Integer[]{255, 152, 0};
pos1 = 50;
pos2 = 100;
}
int firstColor_X = screenHeight * (pos1 / 100);
int secondColor_X = (int) (screenHeight * ((double) pos2 / 100) - firstColor_X);
double slider_X = (screenHeight * (percentage / 100) - firstColor_X);
double ratio = slider_X / secondColor_X;
ArrayList<Integer> result = hexColor(secondColor, firstColor, ratio);
int red = result.get(0);
int green = result.get(1);
int blue = result.get(2);
background.setBackgroundColor(Color.rgb(red, green, blue));