Reputation: 143
I am developing a chart based application, I am using MPAndroidChart library, I need to place the text value inside of circle, i tried to display,Thanks for if any suggestions related this,
i attached a screenshot related to that issue. I need to be do like this
but i get like this image:
Thanks Again for helping this issue,
ArrayList<Entry> e1 = new ArrayList<Entry>();
float[] values = new float[]{48, 59, 79, 29, 39, 50, 60};
for (int i = 0; i < values.length; i++) {
e1.add(new Entry(values[i], i, "line3"));
}
int[] color = {Color.parseColor("#D13385"), Color.parseColor("#37D04E"), Color.parseColor("#33D1D1"), Color.parseColor("#D1C933")};
LineDataSet d1 = new LineDataSet(e1, "" + cnt);
d1.setColors(color);
d1.setLineWidth(3.0f);
d1.setCircleSize(7.0f);
d1.setDrawValues(true);
d1.setCircleColor(Color.parseColor("#891e9a"));
d1.setCircleColorHole(Color.parseColor("#891e9a"));
d1.setDrawHighlightIndicators(false);
d1.setDrawFilled(false);
d1.setFillAlpha(20);
d1.setHighlightLineWidth(50f);
d1.setValueTextSize(10f);
Upvotes: 2
Views: 3084
Reputation: 1
There are two possibilities:
(1) Not so good: Shift the y-value of the label position
Pro: Easy
Con: The offset is not always constant (see offset is not always similar)
(2) Better: Override the drawValues method from LineChartRenderer
In LineChartRenderer.java -> drawValues the text is vertically shifted by this line:
drawValue(c, formatter.getPointLabel(entry), x, y - valOffset, dataSet.getValueTextColor(j / 2));
So to get rid of the "- valOffset":
1.Override the drawValues method
Create a new java file "CenteredTextLineChartRenderer.java" and override method drawValues from LineChartRenderer
2.Modify the y-valOffset to y+textHeight*0.35f
Add float textHeight = dataSet.getValueTextSize();
public class CenteredTextLineChartRenderer extends LineChartRenderer {
public CenteredTextLineChartRenderer(LineDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler) {
super(chart, animator, viewPortHandler);
}
//Modified drawValues Method
// Center label on coordinate instead of applying a valOffset
@Override
public void drawValues(Canvas c) {
if (isDrawingValuesAllowed(mChart)) {
List<ILineDataSet> dataSets = mChart.getLineData().getDataSets();
for (int i = 0; i < dataSets.size(); i++) {
ILineDataSet dataSet = dataSets.get(i);
float textHeight = dataSet.getValueTextSize();
if (!shouldDrawValues(dataSet) || dataSet.getEntryCount() < 1)
continue;
// apply the text-styling defined by the DataSet
applyValueTextStyle(dataSet);
Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());
// make sure the values do not interfear with the circles
int valOffset = (int) (dataSet.getCircleRadius() * 1.75f);
if (!dataSet.isDrawCirclesEnabled())
valOffset = valOffset / 2;
mXBounds.set(mChart, dataSet);
float[] positions = trans.generateTransformedValuesLine(dataSet, mAnimator.getPhaseX(), mAnimator
.getPhaseY(), mXBounds.min, mXBounds.max);
ValueFormatter formatter = dataSet.getValueFormatter();
MPPointF iconsOffset = MPPointF.getInstance(dataSet.getIconsOffset());
iconsOffset.x = Utils.convertDpToPixel(iconsOffset.x);
iconsOffset.y = Utils.convertDpToPixel(iconsOffset.y);
for (int j = 0; j < positions.length; j += 2) {
float x = positions[j];
float y = positions[j + 1];
if (!mViewPortHandler.isInBoundsRight(x))
break;
if (!mViewPortHandler.isInBoundsLeft(x) || !mViewPortHandler.isInBoundsY(y))
continue;
Entry entry = dataSet.getEntryForIndex(j / 2 + mXBounds.min);
if (dataSet.isDrawValuesEnabled()) {
//drawValue(c, formatter.getPointLabel(entry), x, y - valOffset, dataSet.getValueTextColor(j / 2));
drawValue(c, formatter.getPointLabel(entry), x, y+textHeight*0.35f, dataSet.getValueTextColor(j / 2));
}
if (entry.getIcon() != null && dataSet.isDrawIconsEnabled()) {
Drawable icon = entry.getIcon();
Utils.drawImage(
c,
icon,
(int)(x + iconsOffset.x),
(int)(y + iconsOffset.y),
icon.getIntrinsicWidth(),
icon.getIntrinsicHeight());
}
}
MPPointF.recycleInstance(iconsOffset);
}
}
}
}
3.Set your own LineChart renderer to your modified drawValues class
LineChart mChart = (LineChart) mainActivity.findViewById(R.id.LineChart);
mChart.setRenderer(new CenteredTextLineChartRenderer(mChart,mChart.getAnimator(),mChart.getViewPortHandler()));
Now your text is always vertically centered!
IMPORTANT: With deleting the valOffset your label is not vertically centered as the text anchor is not in the center of your text label. So you have to insert a manual offset "textHeight*0.35f" (just try it out). But the big advantage of method (2) is that the text is always centered with the same offset also for example in landscape mode and on other screen sizes...
Upvotes: 0
Reputation: 1
there was an easy way to do this
custom maker view
<TextView
android:id="@+id/tvContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="7dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:text=""
android:textSize="12sp"
android:textColor="@android:color/white"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall" />
Marker view class
public class MyMarkerView extends MarkerView {
private final TextView tvContent;
public MyMarkerView(Context context, int layoutResource) {
super(context, layoutResource);
tvContent = findViewById(R.id.tvContent);
}
// runs every time the MarkerView is redrawn, can be used to update the
// content (user-interface)
@SuppressLint("SetTextI18n")
@Override
public void refreshContent(Entry e, Highlight highlight) {
if (e instanceof CandleEntry) {
CandleEntry ce = (CandleEntry) e;
tvContent.setText(Utils.formatNumber(ce.getHigh(), 0, true)+(ce.getData()));
} else {
tvContent.setText(Utils.formatNumber(e.getY(), 0, true)+"\n "+(e.getData()));
}
super.refreshContent(e, highlight);
}
@Override
public MPPointF getOffset() {
return new MPPointF(-(getWidth() / 2), -getHeight());
}
} and lastly in your activity
values.add(new Entry(i, val,"Custom message per value"));
Preview be like example screen shot
Upvotes: 0
Reputation: 1
there was an easy way to do this custom maker view
Marker view
public class MyMarkerView extends MarkerView {
private final TextView tvContent;
public MyMarkerView(Context context, int layoutResource) {
super(context, layoutResource);
tvContent = findViewById(R.id.tvContent);
}
// runs every time the MarkerView is redrawn, can be used to update the
// content (user-interface)
@SuppressLint("SetTextI18n")
@Override
public void refreshContent(Entry e, Highlight highlight) {
if (e instanceof CandleEntry) {
CandleEntry ce = (CandleEntry) e;
tvContent.setText(Utils.formatNumber(ce.getHigh(), 0, true)+(ce.getData()));
} else {
tvContent.setText(Utils.formatNumber(e.getY(), 0, true)+"\n "+(e.getData()));
}
super.refreshContent(e, highlight);
}
@Override
public MPPointF getOffset() {
return new MPPointF(-(getWidth() / 2), -getHeight());
}
} and lastly in your activity
values.add(new Entry(i, val,"Custom message per value"));
Preview be like example screen shot
Upvotes: 0
Reputation: 393
It is a bit "hacky", but I've managed to achieve such layout You've provided by creating two sets of data and attaching them to same chart. One set (lets call it "dots") contains your data needed to be displayed as dots. The second one ("lines") is a bit offset downwards (y value minus some experimentally picked value). Now you can set no line displaying for "lines" and a lines for "dots", no values labels for "dots" and white labels for "lines" and by experimentally moving your y values back and forth you can achieve overlaying values labels from one chart on top of another ("dots" will be covered by "lines" values).
UPDATE: Actually, I've an answer more elegant, that I've provided! Use Highlight[] and create array of highlights.
highlihts = new Highlight[values_dots.size()];
for (int i = 0; i < values_dots.size(); i++) {
Highlight h = new Highlight(values_dots.get(i).getX(),values_dots.get(i).getY(), 0);
highlihts[i] = h;
}
chart.highlightValues(highlihts);
In CustomMarkerView class position marker like so:
@Override
public MPPointF getOffset() {
return new MPPointF(-(getWidth() / 2), -(getHeight() / 2));
}
Boom
P.S. Philipp Jahoda, awesome library!
Upvotes: 0
Reputation: 51411
Currently it is not possible to change the position where the values are drawn by default. You will have to modify the library to get that behaviour.
Upvotes: 1