Open MGaetan89 opened 9 years ago
That's actually a very good idea. I will consider to add this in a future update. In my opinion it should be possible to implement such a feature with moderate effort.
Seems like this is similar to the feature implemented in this pull request: https://github.com/PhilJay/MPAndroidChart/pull/478
I couldn't find the commits, but I assume the Y-axis drawing eventually got merged in. If so it shouldn't be hard to get similar functionality on the X-axis I'd imagine.
+1, this would be great!
Is this implemented?
+1
[Update: the behavior of the axis highlight has changed in the final version - PR #4477. The axis now draw a recttangle and text at the highlighted value. See the PR for details.]
I am pretty close to completing work on this. The proposed functionality is documented below, and an example screen shot is provided. Please provide feedback and suggestions for changes / improvements.
Maps the largest cities in California. Two points on the right log log axis have been touched, and only cities whose populations are between those values are rendered. The city of Bakersfield has also been highlighted.
This section focuses on the topic of highlighting entries in the chart, both via tap-gesture and programmatically based on Pull Request ###.
Both data vales and individual axes can be highlighted.
setHighlightPerDragEnabled(boolean enabled)
: Set this to true on your Chart
to allow highlighting per dragging over the chart surface when it is fully zoomed out. Default: truesetHighlightPerTapEnabled(boolean enabled)
: Set this to false on your Chart
to prevent values from being highlighted by tap gesture. Values can still be highlighted via drag or programmatically. Default: truesetMaxHighlightDistance(float distanceDp)
: Sets the maximum highlight distance in dp. Taps on the chart further away from an entry than that distance will not trigger a highlight. Default: 500dpHighlighting can be configured for individual DataSet
objects:
dataSet.setHighlightEnabled(true); // allow highlighting for DataSet
// set this to false to disable the drawing of highlight indicator (lines)
dataSet.setDrawHighlightIndicators(true);
dataSet.setHighlightColor(Color.BLACK); // color for highlight indicator
// and more...
Highlighting can be configured for each axis:
axis.setHighlightEnabled(true); // allow highlighting for Axis. Default false.
// if set, touching an axis will change the color of the nearest label
axis.setSnapHighlightToLabel(true);
axis.setHighlightColor(Color.RED);
To remove single or multiple highlights, touch in a 'blank' area of the data (as defined by setMaxHighlightDistance
above), touch the same entry twice, or the same axis at the same position twice. The latter action may be difficult to perform.
For each highlightable item (each data set and each axis), either single or multiple highlights can be enabled:
item.setMultipleHighlightsEnabled(true);
If false, highlighting one item removes any existing highlight on that item. If true, multiple highlights can coexist.
This library two listeners for callbacks upon highlighting: OnChartValueSelectedListener
and OnAxisSelectedListener
. If both listeners exist, the onNothingSelected
callback is made to the OnChartValueSelectedListener
and not to the OnAxisSelectedListener
.
For callbacks when a data value has been selected for highlighting
public interface OnChartValueSelectedListener {
/**
* Called when a value has been selected inside the chart.
*
* @param e The selected Entry.
* @param h The corresponding highlight object that contains information
* about the highlighted position
*/
public void onValueSelected(@Nullable Entry e, Highlight h);
/**
* Called when nothing has been selected or an "un-select" has been made.
*/
public void onNothingSelected();
}
Simply let your class that should receive the callbacks implement this interface and set it as a listener to the chart:
chart.setOnChartValueSelectedListener(this);
For callbacks when an axis has been selected.
/**
* Called when an axis has been selected outside the chart.
*
* @param h highlight object that contains information
* about the highlighted position.
*/
onAxisSelected(Highlight h);
/**
* Called when nothing has been selected or an "un-select" has been made.
*/
public void onNothingSelected();
Simply let your class that should receive the callbacks implement this interface and set it as a listener to the chart::
chart.setOnAxisSelectedListener(this);
A highlight has a type: VALUE, X_AXIS, LEFT_AXIS, RIGHT _AXIS or NULL.
Each highlight can be queried for its type:
There are a number of constructors available, including:
// for an axis highlight, create a highlight at the given x or y point.
// for a value highlight, search for the entry closest to x, y and highlight it.
Highlight(float xVal, float yVal, Type highlightType, float xPix, float yPix)
// if we already know which entry to highlight, set dataSetIndex
// and dataIndex to skip the search
Highlight(float x, float y, float xPx, float yPx, int dataSetIndex, int dataIndex, YAxis.AxisDependency axis)
The Highlights
class holds a collection of Highlight
s of a particular type. There can only be one 'Highlight Type' in an instance of Highlights
, determined by the first Highlight
added to the collection. Attempting to add a different type to a non-empty Highlights
instance will throw a run time exception.
Each Highlight Type is gotten through different methods:
VALUE: chart.getHighlights();
X_AXIS: if (chart.hasXAxis)
chart.getXAxis().getHighlights();
LEFT_AXIS: if (chart.hasLeftAxis)
chart.getLeftAxis().getHighlights();
RIGHTT_AXIS: if (chart.hasRightAxis)
chart.getRightAxis().getHighlights();
You can skip the hasAxis
checks if you are sure that the given axis exists, but you will get a run time exception if you are wrong.
Multiple highlights are supported at the Highlights
level. Setting or getting these fields for a highlightable item simply passes the call through to the underlying `Highlights' class.
setMultipleHighlightsEnabled(true);
boolean isMultipleHighlightsEnabled();
/**
* Adds the given Highlight.
* Deletes any pre-existing highlights if
* `isMultipleHighlightsEnabled` is false.
*/
boolean add(Highlight highlight);
/**
* Removes the given highlight if it exists.
*
* @param highlight to be removed
* @return true if highlight existed and was removed
*/
public boolean remove(Highlight highlight)
// clear all highlights
void clear();
int size();
boolean isEmpty();
boolean hasHighlights(); // same as isEmpty()
Iterator<Highlight> = highlights.iterator()
The Highlight
class represents all data associated with a highlight.
mType - Highlight.Type: VALUE, X_AXIS, LEFT_AXIS, RIGHT _AXIS or NULL
mX, mY - the x and y location in the data space
mXPx, mYPx - the x and y position on the screen in pixels
mDrawX, mDrawY - the position where the highlight was last drawn in pixels. The drawn position may be different than the pixel position. For example, a highlight on a bar chart is drawn above the bar. These values are set by the renderer, and may be null before any rendering has occurred.
mDataSetIndex - for VALUE, the index of the data set. Ignored otherwise.
mDataIndex - for VALUE, the index within the data set. Ignored otherwise
mStackIndex - for VALUE in the stacked BarEntry chart. Ignored otherwise
The indices are ignored for a non-VALUE Highlight
and are generally set to -1.
The Highlight
class provides several constructors for a VALUE Highlight:
/**
* Constructor for standard highlight.
* The data set will be searched for the entry closest to x.
*/
public Highlight(float x, int dataSetIndex) { ... }
/**
* Constructor where we know which entry to highlight.
* This avoids the search overhead.
*/
public Highlight(float x, float y, float xPx, float yPx, int dataSetIndex, int dataIndex, YAxis.AxisDependency axis)
/** constructor for stacked BarEntry highlight */
public Highlight(float x, int dataSetIndex, int stackIndex) { ... }
The generic constructors below can also be used to create a Highlight by providing a VALUE
type to those constructors.
The Highlight
class provides several constructors for a generic Highlight:
// Creates an 'empty' highlight of the given type.
// Generally used to return a NULL highlight rather
// than a null object - ala Kotlin.
Highlight(Type highlightType);
// constructor to support axis highlights with touch position
Highlight(float xVal, float yVal, Type highlightType, float xPix, float yPix)
To highlight a highlight item, simply create a Highlight with the appropriate type and add it to the chart. You need to provide both the xy data values and corresponding pixel position for constructors requiring either.
Highlight highlight = new Highlight(xVal, yVal, xPx, yPx,
dataSetIndex = 1, dataIndex = 2,
stackIndex = -1, YAxis.AxisDependency axis)
chart.addHighlight(highlight, true)
Highlight highlight = new Highlight(12.2f, yVal, highlightType = X_AXIS,
xPix, yPix)
chart.addHighlight(highlight, true)
To add multiple highlights, simply add highlights one at a time, or create a new Highlights and add it to the chart:
Highlights highlights = new Highlights();
highlights.setMultipleHighlightsEnabled(true); // else they will be disabled
highlights.add(new Highlight(...));
... repeat as needed
chart.addHighlights(highlights);
Note that after addHighlights
is called, mMultipleHighlightsEnabled
is true only if it is true before the methd is called and if it is true in the added highlights.
All user input in the form of highlight gestures is internally processed by the default ChartHighlighter
class. It is possible to replace the default highligher with a custom implementation using the below method:
setHighlighter(ChartHighlighter highlighter)
: Sets a custom highligher object for the chart that handles / processes all highlight touch events performed on the chart-view. Your custom highlighter object needs to extend the ChartHighlighter
class.Please @PhilJay , can you review and merge @regas99's PR
Please merge this
merge plz..
I started to use this library for my project and here is a first suggestion/question (depending on whether it is already possible or not).
When I select a point (Entry) on my LineChart, I would like its values (x & y) to be display on the x axis and y axis respectively. Is this possible? If not, is it easy to implement?
Thanks for this awesome library!