How can I customize the X axis to show days (or months or years, based on the selected range) where a new day/month/year begins? I am using CategoryDateAxis
(CreateMultiPaneStockChartsFragment example).
What I want:
Larger ranges:
Smaller ranges (easily see where new day begins):
What I have:
Right now I am using default label provider and it is hard to see when new day/month/year begins. E.g. for 7 day range:
Axis is construced like this:
final CategoryDateAxis xAxis = sciChartBuilder.newCategoryDateAxis()
.withVisibility(isMainPane ? View.VISIBLE : View.GONE)
.withVisibleRange(sharedXRange)
//.withLabelProvider(new TradeChartAxisLabelProviderDateTime())
.withGrowBy(0.01d, 0.01d)
.build();
How do I achieve this?
public static class TradeChartAxisLabelProviderDateTime extends TradeChartAxisLabelProvider {
public TradeChartAxisLabelProviderDateTime() {
super();
}
@Override
public String formatLabel(Comparable dataValue) {
if(currentRange == RANGE_1_YEAR) {
} else if(currentRange == RANGE_1_MONTH) {
} else if(currentRange == RANGE_1_DAY) {
}
String text = super.formatLabel(dataValue).toString();
return text;
}
}
To implement selection of label based on VisibleRange you can use code like this:
public static class TradeChartAxisLabelProviderDateTime extends TradeChartAxisLabelProvider {
public TradeChartAxisLabelProviderDateTime() {
super(new TradeChartAxisLabelFormatterDateTime());
}
private static class TradeChartAxisLabelFormatterDateTime implements ILabelFormatter<CategoryDateAxis> {
private final SimpleDateFormat labelFormat, cursorLabelFormat;
private TradeChartAxisLabelFormatterDateTime() {
labelFormat = new SimpleDateFormat(CategoryDateAxis.DEFAULT_TEXT_FORMATTING, Locale.getDefault());
cursorLabelFormat = new SimpleDateFormat(CategoryDateAxis.DEFAULT_TEXT_FORMATTING, Locale.getDefault());
}
@Override
public void update(CategoryDateAxis axis) {
final ICategoryLabelProvider labelProvider = Guard.instanceOfAndNotNull(axis.getLabelProvider(), ICategoryLabelProvider.class);
// this is range of indices which are drawn by CategoryDateAxis
final IRange<Double> visibleRange = axis.getVisibleRange();
// convert indicies to range of dates
final DateRange dateRange = new DateRange(
ComparableUtil.toDate(labelProvider.transformIndexToData((int) NumberUtil.constrain(Math.floor(visibleRange.getMin()), 0, Integer.MAX_VALUE))),
ComparableUtil.toDate(labelProvider.transformIndexToData((int) NumberUtil.constrain(Math.ceil(visibleRange.getMax()), 0, Integer.MAX_VALUE))));
if (dateRange.getIsDefined()) {
long ticksInViewport = dateRange.getDiff().getTime();
// select formatting based on diff in time between Min and Max
if (ticksInViewport > DateIntervalUtil.fromYears(1)) {
// apply year formatting
labelFormat.applyPattern("");
cursorLabelFormat.applyPattern("");
} else if (ticksInViewport > DateIntervalUtil.fromMonths(1)) {
// apply month formatting
labelFormat.applyPattern("");
cursorLabelFormat.applyPattern("");
} else if (ticksInViewport > DateIntervalUtil.fromMonths(1)) {
// apply day formatting
labelFormat.applyPattern("");
cursorLabelFormat.applyPattern("");
}
}
}
@Override
public CharSequence formatLabel(Comparable dataValue) {
final Date valueToFormat = ComparableUtil.toDate(dataValue);
return labelFormat.format(valueToFormat);
}
@Override
public CharSequence formatCursorLabel(Comparable dataValue) {
final Date valueToFormat = ComparableUtil.toDate(dataValue);
return cursorLabelFormat.format(valueToFormat);
}
}
}
In update() you can get access to VisibleRange of axis and based on it select label formatting and then use SimpleDateFormat to format Dates.
But as I understand your case is more complex than this because you can't get labels which allow to see when new day/month/year begins based on current VisibleRange. For this case you'll need to select format string based on previously formatted values and track when day/month/year changes.