Arjun Issar
Arjun Issar

Reputation: 654

MarkerView goes out of the chart for the last point on the chart

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 :

enter image description here

The second image, as shown below, shows the markerview for the last point of the chart, which is half within the chart.

enter image description here

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

Answers (9)

ajizul hakim
ajizul hakim

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

Yuri Barbosa
Yuri Barbosa

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

Twinkle
Twinkle

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

Philipp Jahoda
Philipp Jahoda

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

Amit
Amit

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

user7010102
user7010102

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

Chetna Priyadarshini
Chetna Priyadarshini

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

Virthuss
Virthuss

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

Maragues
Maragues

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

enter image description here enter image description here enter image description here

The drawables are copied from MPAndroidChart samples, transformed to 9.patch and adapted to my needs. Place them inside drawable-nodpi

enter image description here enter image description here enter image description here

Upvotes: 9

Related Questions