Skip to content

Commit d4e27e2

Browse files
authored
Merge pull request #573 from vizzuhq/Translate_legend
Axis fixes
2 parents 507f39a + adeab10 commit d4e27e2

File tree

15 files changed

+636
-564
lines changed

15 files changed

+636
-564
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
- Axis: line, title, labels, guides, interlacing, ticks
1111
- Legend: title, dimension markers, measure extrema labels
1212
- Marker: line with connections
13+
- Fix negative ranges on x, y, color (measure) and lightness.
14+
- Fix axis step parameter if not match with the range sign (neg/pos).
15+
- Fix axis interpolation. From now the axis and axis labels are following the markers.
16+
- Fix measure axis labels when the range started after the 2000th step value from origo.
1317

1418
### Added
1519

src/base/anim/interpolated.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ template <typename Type> class Interpolated
204204
return false;
205205
}
206206

207-
template <class T, class U>
207+
template <class T = double, class U>
208208
[[nodiscard]] T factor(const U &value) const
209209
{
210210
double res{};

src/base/math/range.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,6 @@ template <std::floating_point T> struct Range
7474
return is_zero(s) ? 0.5 : (value - min) / s;
7575
}
7676

77-
[[nodiscard]] Range<T> rescale(const Range<T> &range) const
78-
{
79-
return Range<T>(rescale(range.min), rescale(range.max));
80-
}
81-
8277
[[nodiscard]] T scale(const T &value) const
8378
{
8479
return value * size() + min;

src/chart/generator/axis.cpp

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include "axis.h"
22

33
#include <algorithm>
4+
#include <cmath>
5+
#include <limits>
46
#include <map>
57
#include <optional>
68
#include <string>
@@ -42,7 +44,13 @@ MeasureAxis::MeasureAxis(Math::Range<double> interval,
4244
unit(std::string{unit}),
4345
origMeasureName(std::string{measName}),
4446
step(step ? *step : Math::Renard::R5().ceil(range.size() / 5.0))
45-
{}
47+
{
48+
if (Math::Floating::is_zero(range.size()))
49+
this->step->value = 0;
50+
else if (std::signbit(this->step->value)
51+
!= std::signbit(range.size()))
52+
this->step->value *= -1;
53+
}
4654

4755
bool MeasureAxis::operator==(const MeasureAxis &other) const
4856
{
@@ -68,8 +76,66 @@ MeasureAxis interpolate(const MeasureAxis &op0,
6876
interpolate(op0.origMeasureName, op1.origMeasureName, factor);
6977

7078
if (op0.enabled.get() && op1.enabled.get()) {
71-
res.range = Math::interpolate(op0.range, op1.range, factor);
72-
res.step = interpolate(op0.step, op1.step, factor);
79+
constexpr auto MAX = std::numeric_limits<double>::max() / 2;
80+
using Math::Floating::is_zero;
81+
82+
const auto s0 = op0.range.size();
83+
const auto s1 = op1.range.size();
84+
85+
if (auto s0Zero = is_zero(s0); s0Zero || is_zero(s1)) {
86+
res.range = Math::Range<double>::Raw(
87+
Math::interpolate(op0.range.getMin(),
88+
op1.range.getMin(),
89+
factor),
90+
Math::interpolate(op0.range.getMax(),
91+
op1.range.getMax(),
92+
factor));
93+
res.step = s0Zero ? op1.step : op0.step;
94+
}
95+
else {
96+
auto s0Inv = 1 / s0;
97+
auto s1Inv = 1 / s1;
98+
99+
const auto interp =
100+
Math::interpolate(s0Inv, s1Inv, factor);
101+
102+
const auto s = is_zero(interp) ? MAX : 1 / interp;
103+
104+
res.range = Math::Range<double>::Raw(
105+
Math::interpolate(op0.range.getMin() * s0Inv,
106+
op1.range.getMin() * s1Inv,
107+
factor)
108+
* s,
109+
Math::interpolate(op0.range.getMax() * s0Inv,
110+
op1.range.getMax() * s1Inv,
111+
factor)
112+
* s);
113+
114+
auto step = Math::interpolate(op0.step.get() * s0Inv,
115+
op1.step.get() * s1Inv,
116+
factor)
117+
* s;
118+
119+
if (auto op0sign = std::signbit(op0.step.get());
120+
op0sign == std::signbit(op1.step.get()))
121+
res.step = interpolate(op0.step,
122+
op1.step,
123+
Math::Range<double>::Raw(op0.step.get(),
124+
op1.step.get())
125+
.rescale(step));
126+
else if (auto max = std::copysign(MAX, step);
127+
op0sign == std::signbit(step))
128+
res.step = interpolate(op0.step,
129+
Anim::Interpolated{max},
130+
Math::Range<double>::Raw(op0.step.get(), max)
131+
.rescale(step));
132+
else
133+
res.step = interpolate(op1.step,
134+
Anim::Interpolated{max},
135+
Math::Range<double>::Raw(op1.step.get(), max)
136+
.rescale(step));
137+
}
138+
73139
res.unit = interpolate(op0.unit, op1.unit, factor);
74140
}
75141
else if (op0.enabled.get()) {

src/chart/generator/plotbuilder.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -355,23 +355,26 @@ void PlotBuilder::normalizeXY()
355355
}
356356

357357
plot->getOptions()->setAutoRange(
358-
!std::signbit(boundRect.positive().hSize().getMin()),
359-
!std::signbit(boundRect.positive().vSize().getMin()));
358+
!std::signbit(boundRect.hSize().getMin()),
359+
!std::signbit(boundRect.vSize().getMin()));
360360

361361
boundRect.setHSize(xrange.getRange(boundRect.hSize()));
362362
boundRect.setVSize(yrange.getRange(boundRect.vSize()));
363363

364364
for (auto &marker : plot->markers) {
365-
if (!boundRect.intersects(marker.toRectangle().positive()))
365+
if (!boundRect.positive().intersects(
366+
marker.toRectangle().positive()))
366367
marker.enabled = false;
367368

368369
auto rect = marker.toRectangle();
369370
auto newRect = boundRect.normalize(rect);
370371
marker.fromRectangle(newRect);
371372
}
372373

373-
getMeasTrackRange(ChannelId::x) = boundRect.hSize();
374-
getMeasTrackRange(ChannelId::y) = boundRect.vSize();
374+
getMeasTrackRange(ChannelId::x) =
375+
Math::Range<double>::Raw(boundRect.left(), boundRect.right());
376+
getMeasTrackRange(ChannelId::y) =
377+
Math::Range<double>::Raw(boundRect.bottom(), boundRect.top());
375378
}
376379

377380
void PlotBuilder::calcMeasureAxises(const Data::DataTable &dataTable)
@@ -478,7 +481,10 @@ void PlotBuilder::addAlignment(const Buckets &subBuckets) const
478481

479482
if (std::signbit(
480483
plot->axises.at(plot->getOptions()->subAxisType())
481-
.measure.range.getMin()))
484+
.measure.range.getMin())
485+
|| std::signbit(
486+
plot->axises.at(plot->getOptions()->subAxisType())
487+
.measure.range.getMax()))
482488
return;
483489

484490
if (plot->getOptions()->align == Base::Align::Type::none) return;

src/chart/options/channelrange.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ ChannelExtrema::operator std::string() const
2525
Math::Range<double> ChannelRange::getRange(
2626
const Math::Range<double> &original) const
2727
{
28-
return {getExtrema(min, original.getMin(), original),
29-
getExtrema(max, original.getMax(), original)};
28+
return Math::Range<double>::Raw(
29+
getExtrema(min, original.getMin(), original),
30+
getExtrema(max, original.getMax(), original));
3031
}
3132

3233
double ChannelRange::getExtrema(const OptionalChannelExtrema &extrema,

src/chart/rendering/drawaxes.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ void DrawAxes::drawTitle(Gen::ChannelId axisIndex) const
227227
? titleStyle.orientation->get_or_first(index)
228228
.value
229229
== Styles::AxisTitle::Orientation::vertical
230-
: titleStyle.orientation->factor<double>(
230+
: titleStyle.orientation->factor(
231231
Styles::AxisTitle::Orientation::vertical));
232232

233233
auto orientedSize =
@@ -336,7 +336,7 @@ void DrawAxes::drawDimensionLabel(bool horizontal,
336336
labelStyle.position->interpolates()
337337
? labelStyle.side->get_or_first(index).value
338338
== Styles::AxisLabel::Side::negative
339-
: labelStyle.side->factor<double>(
339+
: labelStyle.side->factor(
340340
Styles::AxisLabel::Side::negative);
341341

342342
auto sign = 1 - 2 * under;

src/chart/rendering/drawguides.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ void DrawGuides::draw(bool horizontal)
3434
const auto &axis = axises.at(axisId).dimension;
3535

3636
if (axis.enabled && *guideStyle.lineWidth > 0
37-
&& (static_cast<double>(plot->guides.at(axisId).axisGuides)
38-
> 0)) {
37+
&& plot->guides.at(axisId).axisGuides != false) {
3938
canvas.setLineWidth(*guideStyle.lineWidth);
4039

4140
for (auto it = axis.begin(); it != axis.end(); ++it) {

src/chart/rendering/drawinterlacing.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "base/geom/rect.h"
1111
#include "base/gfx/colortransform.h"
1212
#include "base/gfx/font.h"
13+
#include "base/math/floating.h"
1314
#include "base/math/range.h"
1415
#include "base/math/renard.h"
1516
#include "base/text/smartstring.h"
@@ -79,7 +80,7 @@ void DrawInterlacing::draw(bool horizontal, bool text) const
7980
}
8081
else {
8182
auto highWeight =
82-
Math::Range(stepLow, stepHigh).rescale(step);
83+
Math::Range<double>::Raw(stepLow, stepHigh).rescale(step);
8384

8485
auto lowWeight = (1.0 - highWeight) * enabled;
8586
highWeight *= enabled;
@@ -119,9 +120,8 @@ void DrawInterlacing::draw(
119120

120121
const auto origo = plot->axises.origo();
121122

122-
if (static_cast<double>(enabled.interlacings || enabled.axisSticks
123-
|| enabled.labels)
124-
> 0) {
123+
if ((enabled.interlacings || enabled.axisSticks || enabled.labels)
124+
!= false) {
125125
auto interlaceIntensity = Math::FuzzyBool::And<double>(weight,
126126
enabled.interlacings);
127127
auto interlaceColor =
@@ -133,15 +133,19 @@ void DrawInterlacing::draw(
133133
auto textAlpha =
134134
Math::FuzzyBool::And<double>(weight, enabled.labels);
135135

136-
if (rangeSize <= 0) return;
136+
if (std::signbit(rangeSize) != std::signbit(stepSize)
137+
|| Math::Floating::is_zero(rangeSize))
138+
return;
137139

138140
auto stripWidth = stepSize / rangeSize;
139141

140142
auto axisBottom = axis.origo() + stripWidth;
141143

142-
auto iMin = axisBottom > 0 ? static_cast<int>(
143-
std::floor(-axis.origo() / (2 * stripWidth)))
144-
: 0;
144+
auto iMin =
145+
axisBottom > 0 ? static_cast<int>(
146+
std::floor(-axis.origo() / (2 * stripWidth)))
147+
: static_cast<int>(
148+
(axis.range.getMin() - stepSize) / 2);
145149

146150
if (stripWidth <= 0) return;
147151
auto interlaceCount = 0U;
@@ -270,7 +274,7 @@ void DrawInterlacing::drawDataLabel(
270274
auto under = labelStyle.position->interpolates()
271275
? labelStyle.side->get_or_first(index).value
272276
== Styles::AxisLabel::Side::negative
273-
: labelStyle.side->factor<double>(
277+
: labelStyle.side->factor(
274278
Styles::AxisLabel::Side::negative);
275279

276280
auto &&posDir =

src/chart/rendering/drawlegend.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ void DrawLegend::drawMarker(Info &info,
244244
info.canvas.setLineColor(color);
245245
info.canvas.setLineWidth(0);
246246

247-
auto radius = rootStyle.legend.marker.type->factor<double>(
247+
auto radius = rootStyle.legend.marker.type->factor(
248248
Styles::Legend::Marker::Type::circle)
249249
* rect.size.minSize() / 2.0;
250250

0 commit comments

Comments
 (0)