Reputation: 654
I am using a MarkerView class to show markerviews in the chart. The markerview layout I have created contains two textview, one below the other.
The problem I am facing is that the markerview for the last point on the chart is half within the chart and half outside the chart. The two images below state the problem clearly :
The first image shows a markerview for a point in the center of the chart which shows without any problem :
The second image, as shown below, shows the markerview for the last point of the chart, which is half within the chart.
How do I get this markerview to adjust so that it shows within the chart area.
The wiki does not state any customizations for the markerview. Are there any more customizations?
Also, in case of a multiple line chart, if I click only on one of the line points, the markerview comes without a problem. But if I click for the markerview on any point on the other line, the application fails. Any idea why this happens.
The code for the markerview class is given below :
public class TooltipView extends MarkerView {
private BaseGraphMetadata mBaseGraphMetadata;
private TextView mTooltipDate, mTooltipValue;
public TooltipView(Context context, int layoutResource, BaseGraphMetadata baseGraphMetadata) {
super(context, layoutResource);
mTooltipDate = (TextView)findViewById(R.id.tooltip_date);
mTooltipValue = (TextView)findViewById(R.id.tooltip_value);
mBaseGraphMetadata = baseGraphMetadata;
}
@Override
public void refreshContent(Entry entry, int i) {
List<DrillDownInfo> drillDownInfoList = (List<DrillDownInfo>) entry.getData();
DrillDownInfo drillDownInfo = drillDownInfoList.get(i);
Map<String, String> group = drillDownInfo.getGroupByNameVsGroupByValue();
Iterator iterator = group.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry pair = (Map.Entry)iterator.next();
if(pair.getKey()!=null && pair.getValue()!=null) {
String key = (String) pair.getKey();
key = key.toUpperCase();
Double value = Double.parseDouble((String) pair.getValue());
String formattedValue = mBaseGraphMetadata.getDataFormatter().getFormattedValue(value);
mTooltipDate.setText(key + " : " + formattedValue);
}
iterator.remove();
}
mTooltipValue.setText(String.valueOf("VALUE : "+entry.getVal()));
}
@Override
public int getXOffset() {
return -(getWidth() / 2);
}
@Override
public int getYOffset() {
return -getHeight();
}
}
Upvotes: 23
Views: 14483
Reputation: 1
in my case is:
first you just override getOffset() in your customMarkerView class and return MPPointF(-(width / 2f), -height.toFloat())
after that, set chart view into MarkerView.chartView.
in my case like this.
val marker=CustomMarkerView(requireContext(),R.layout.custom_market_view,dataMarker)
marker.chartView = binding.chartDiscover
Upvotes: 0
Reputation: 71
try this:
private val uiScreenWidth = resources.displayMetrics.widthPixels
override fun draw(canvas: Canvas?, posX: Float, posY: Float) {
var newPosX = posX
if (uiScreenWidth - posX < width) {
newPosX -= width
}
super.draw(canvas, newPosX, posY)
}
Upvotes: 5
Reputation: 47
You can rectify this by adding chart.setDragOffsetX(50);
. This will add padding on x-axis. Thus, giving space for the markerview to be displayed.
Upvotes: 2
Reputation: 51411
Just put some logic in your MarkerView
. If the last value is highlighted, the getXOffset()
method should return something different.
What is returned, is calculated in the refreshContent(...)
method.
Also, you can take a look at the following xml properties:
android:clipChildren="false"
android:clipToPadding="false"
Which should be set for the chart-view.
Upvotes: 5
Reputation: 3702
The best answer lies in the library itself. Check the method getOffsetForDrawingAtPoint() from MarkerView . It has defined the perfect way to calculate the offset. Use that logic from there and use in onDraw
method of your custom marker as following:
@Override
public void draw(Canvas canvas, float posX, float posY) {
// take offsets into consideration
int lineChartWidth = 0;
float offsetX = getOffset().getX();
posY=0;//fix at top
float width = getWidth();
if(lineChart != null) {
lineChartWidth = lineChart.getWidth();
}
if(posX + offsetX < 0) {
offsetX = - posX;
} else if(posX + width + offsetX > lineChartWidth) {
offsetX = lineChartWidth - posX - width;
}
posX += offsetX;
// translate to the correct position and draw
canvas.translate(posX, posY);
draw(canvas);
canvas.translate(-posX, -posY);
}
Upvotes: 0
Reputation:
I have found a simple solution to this issue. You need to set chart in your custom marker view as below:
setChartView(chart);
..and override the draw method as below:
@Override
public void draw(Canvas canvas, float posX, float posY) {
super.draw(canvas, posX, posY);
getOffsetForDrawingAtPoint(posX, posY);
}
Upvotes: 28
Reputation: 217
I faced the same problem. I rectified it by making my own customMarkerview
class particularly the below method:
@Override
public int getXOffset(float xpos) {
// this will center the marker-view horizontally
int min_offset = 50;
if (xpos < min_offset)
return 0;
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
//For right hand side
if (metrics.widthPixels - xpos < min_offset)
return -getWidth();
//For left hand side
else if (metrics.widthPixels - xpos < 0)
return -getWidth();
return -(getWidth() / 2);
}
Upvotes: 4
Reputation: 3213
A bit late, but here is my easy solution for this problem.
You need to Override
the draw
method of your custom MarkerView
.
You just have then to control that you posx is not going to close from one of your border (from 0
for the right side to location depending on your screen size, as an example 300
for my own screen).
A simple example:
@Override
public void draw(Canvas canvas, float posx, float posy)
{
// take offsets into consideration
posx += getXOffset();
posy=0;
// AVOID OFFSCREEN
if(posx<45)
posx=45;
if(posx>265)
posx=265;
// translate to the correct position and draw
canvas.translate(posx, posy);
draw(canvas);
canvas.translate(-posx, -posy);
}
Here, I can control my x position while ensuring that the marker remain always on the top of the graph (If you dont want it, use posy += getYOffset();
instead)
Upvotes: 7
Reputation: 38324
Since
android:clipChildren="false"
android:clipToPadding="false"
did not work for me, I ended up creating 3 different drawables. Depending on the Entry index, I use one or the other. And, in order to keep the arrow centered, the XOffset changes accordingly. I guess it's a very specific solution, but the idea is exportable
@Override
public void refreshContent(Entry e, int dataSetIndex) {
if (e.getXIndex() < 4) {
xOffsetMultiplier = 3.2f;
tvContent.setBackgroundResource(R.drawable.stats_marker_left_side);
} else if (e.getXIndex() > mTimestamps.length - 6) {
//timestamps is an array containing xValues timestamps
xOffsetMultiplier = 1.12f;
tvContent.setBackgroundResource(R.drawable.stats_marker_right_side);
} else {
xOffsetMultiplier = 2;
tvContent.setBackgroundResource(R.drawable.stats_marker);
}
tvContent.setText(createMarkerViewText(e));
}
@Override
public int getXOffset() {
// this will center the marker-view horizontally
return (int) -(getWidth() / xOffsetMultiplier);
}
This is the result
The drawables are copied from MPAndroidChart samples, transformed to 9.patch and adapted to my needs. Place them inside drawable-nodpi
Upvotes: 9