Skip to content

Commit a87fefc

Browse files
authored
Merge pull request #613 from vizzuhq/axis_refactor_v12
Axis refactor v12 - Separate AxisChannel properties from Channel properties
2 parents af94f9f + 3145013 commit a87fefc

File tree

11 files changed

+92
-41
lines changed

11 files changed

+92
-41
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@
66

77
- Fix invalid read/write when animation is contiguous (onFinish callback calls setKeyframe).
88
- Waterfall chart preset not aligned.
9-
- Split chart count negative values too.
9+
- Split chart count negative values too.
10+
11+
### Changed
12+
13+
- Separate Channel properties to AxisChannel properties at config.
14+
- Channels 'set' rewrite doesn't clear AxisChannel properties.
1015

1116
## [0.16.0] - 2024-11-28
1217

src/apps/weblib/typeschema-api/config.yaml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ definitions:
7676
oneOf:
7777
- type: number
7878
- { type: string, enum: [auto] }
79+
80+
AxisChannel:
81+
description: |
82+
AxisChannels are special channel settings for the positional channels.
83+
type: object
84+
properties:
7985
axis:
8086
description: Enables the axis line on axis channels.
8187
$ref: AutoBool
@@ -109,14 +115,18 @@ definitions:
109115
type: object
110116
properties:
111117
x:
112-
$ref: Channel
118+
allOf:
119+
- $ref: Channel
120+
- $ref: AxisChannel
113121
description: |
114122
Parameters for the X-axis, determining the position of the markers on the
115123
x-axis - or their angle when using polar coordinates.
116124
Note: leaving x and y channels empty will result in a
117125
chart "without coordinates" like a Treemap or a Bubble Chart.
118126
y:
119-
$ref: Channel
127+
allOf:
128+
- $ref: Channel
129+
- $ref: AxisChannel
120130
description: |
121131
Parameters for the Y-axis, determining the position of the markers on the
122132
y-axis - or their radius when using polar coordinates) .

src/chart/generator/guides.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,19 @@ bool GuidesByAxis::operator==(const GuidesByAxis &other) const
2020

2121
Guides::Guides(const Options &options)
2222
{
23-
const auto &xOpt = options.getChannels().at(AxisId::x);
24-
const auto &yOpt = options.getChannels().at(AxisId::y);
25-
if (xOpt.isEmpty() && yOpt.isEmpty()) return;
23+
const auto &xChannel = options.getChannels().at(AxisId::x);
24+
const auto &yChannel = options.getChannels().at(AxisId::y);
25+
if (xChannel.isEmpty() && yChannel.isEmpty()) return;
2626

2727
auto xIsMeasure = options.isMeasure(ChannelId::x);
2828
auto yIsMeasure = options.isMeasure(ChannelId::y);
2929
auto isPolar = options.coordSystem.get() == CoordSystem::polar;
3030
auto isCircle = options.geometry.get() == ShapeType::circle;
3131
auto isHorizontal = options.isHorizontal();
3232

33+
const auto &xOpt = options.getChannels().axisPropsAt(AxisId::x);
34+
const auto &yOpt = options.getChannels().axisPropsAt(AxisId::y);
35+
3336
x.axis = xOpt.axis.getValue(yIsMeasure);
3437
y.axis = yOpt.axis.getValue(xIsMeasure && !isPolar);
3538

@@ -58,7 +61,7 @@ Guides::Guides(const Options &options)
5861
x.labels = xOpt.labels.getValue(
5962
(!isPolar || yIsMeasure)
6063
&& ((xIsMeasure && (x.axisSticks || x.interlacings))
61-
|| (!xIsMeasure && !xOpt.isEmpty())));
64+
|| (!xIsMeasure && !xChannel.isEmpty())));
6265

6366
auto stretchedPolar =
6467
isPolar && !yIsMeasure
@@ -67,7 +70,7 @@ Guides::Guides(const Options &options)
6770
y.labels = yOpt.labels.getValue(
6871
!stretchedPolar
6972
&& ((yIsMeasure && (y.axisSticks || y.interlacings))
70-
|| (!yIsMeasure && !yOpt.isEmpty())));
73+
|| (!yIsMeasure && !yChannel.isEmpty())));
7174
}
7275

7376
GuidesByAxis &Guides::at(AxisId channel)

src/chart/generator/plotbuilder.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ void PlotBuilder::calcLegendAndLabel(const Data::DataTable &dataTable)
358358
calcLegend.measure = {std::get<0>(stats.at(type)),
359359
meas->getColIndex(),
360360
dataTable.getUnit(meas->getColIndex()),
361-
scale.step.getValue()};
361+
{1}};
362362
}
363363
}
364364
else if (!scale.isEmpty()) {
@@ -409,6 +409,9 @@ void PlotBuilder::calcAxis(const Data::DataTable &dataTable,
409409
const auto &scale = plot->getOptions()->getChannels().at(type);
410410
if (scale.isEmpty()) return;
411411

412+
auto &axisProps =
413+
plot->getOptions()->getChannels().axisPropsAt(type);
414+
412415
auto &axis = plot->axises.at(type);
413416

414417
auto isAutoTitle = scale.title.isAuto();
@@ -424,12 +427,12 @@ void PlotBuilder::calcAxis(const Data::DataTable &dataTable,
424427
axis.measure = {{0, 100},
425428
meas.getColIndex(),
426429
"%",
427-
scale.step.getValue()};
430+
axisProps.step.getValue()};
428431
else
429432
axis.measure = {std::get<0>(stats.at(type)),
430433
meas.getColIndex(),
431434
dataTable.getUnit(meas.getColIndex()),
432-
scale.step.getValue()};
435+
axisProps.step.getValue()};
433436
}
434437
else {
435438
for (auto merge =
@@ -454,7 +457,7 @@ void PlotBuilder::calcAxis(const Data::DataTable &dataTable,
454457
merge);
455458
}
456459
if (auto &&series = plot->getOptions()->labelSeries(type);
457-
!axis.dimension.setLabels(scale.step.getValue(1.0))
460+
!axis.dimension.setLabels(axisProps.step.getValue(1.0))
458461
&& series && isAutoTitle)
459462
axis.title = series.value().getColIndex();
460463
for (std::uint32_t pos{};

src/chart/options/channel.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,7 @@ void Channel::reset()
148148
set = {};
149149
labelLevel = {};
150150
title = {};
151-
axis = Base::AutoBool();
152-
labels = Base::AutoBool();
153-
ticks = Base::AutoBool();
154-
guides = Base::AutoBool();
155-
markerGuides = Base::AutoBool();
156-
interlacing = Base::AutoBool();
151+
range = {};
157152
}
158153

159154
bool Channel::isEmpty() const

src/chart/options/channel.h

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,22 @@ struct ChannelSeriesList
118118
bool removeSeries(const Data::SeriesIndex &index);
119119
};
120120

121-
class Channel
121+
struct AxisChannelProperties
122+
{
123+
Base::AutoBool axis{};
124+
Base::AutoBool labels{};
125+
Base::AutoBool ticks{};
126+
Base::AutoBool interlacing{};
127+
Base::AutoBool guides{};
128+
Base::AutoBool markerGuides{};
129+
Base::AutoParam<double> step{};
130+
131+
[[nodiscard]] bool operator==(
132+
const AxisChannelProperties &) const = default;
133+
};
134+
135+
struct Channel
122136
{
123-
public:
124137
using OptionalIndex = ChannelSeriesList::OptionalIndex;
125138
using IndexSet = std::set<Data::SeriesIndex>;
126139
using DimensionIndices = ChannelSeriesList::DimensionIndices;
@@ -161,13 +174,6 @@ class Channel
161174
ChannelRange range{};
162175
Base::AutoParam<std::size_t> labelLevel{};
163176
Base::AutoParam<std::string, true> title{};
164-
Base::AutoBool axis{};
165-
Base::AutoBool labels{};
166-
Base::AutoBool ticks{};
167-
Base::AutoBool guides{};
168-
Base::AutoBool markerGuides{};
169-
Base::AutoBool interlacing{};
170-
Base::AutoParam<double> step{};
171177
};
172178

173179
[[nodiscard]] constexpr ChannelId operator+(const AxisId &axis)

src/chart/options/channels.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ namespace Vizzu::Gen
1515
struct Channels : Refl::EnumArray<ChannelId, Channel>
1616
{
1717
using IndexSet = std::set<Data::SeriesIndex>;
18+
EnumArray<AxisId, AxisChannelProperties> axisProps;
1819

1920
[[nodiscard]] bool anyAxisSet() const;
2021
[[nodiscard]] bool isEmpty() const;
@@ -37,6 +38,17 @@ struct Channels : Refl::EnumArray<ChannelId, Channel>
3738
return at(+id);
3839
}
3940

41+
[[nodiscard]] const AxisChannelProperties &axisPropsAt(
42+
const AxisId &id) const
43+
{
44+
return axisProps[id];
45+
}
46+
47+
[[nodiscard]] AxisChannelProperties &axisPropsAt(const AxisId &id)
48+
{
49+
return axisProps[id];
50+
}
51+
4052
void removeSeries(const Data::SeriesIndex &index);
4153

4254
[[nodiscard]] bool isSeriesUsed(

src/chart/options/config.cpp

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ std::string Config::paramsJson()
3333
for (const auto &param : channelParams)
3434
arr << "channels." + std::string{channelName} + "."
3535
+ std::string{param};
36+
37+
if (channelName == "x" || channelName == "y")
38+
for (const auto &param :
39+
getAccessorNames<AxisChannelProperties>())
40+
arr << "channels." + std::string{channelName} + "."
41+
+ std::string{param};
3642
}
3743
return res;
3844
}
@@ -83,35 +89,39 @@ void Config::setChannelParam(const std::string &path,
8389

8490
if (property == "set") {
8591
if (parts.size() == 3) {
86-
channel.reset();
92+
channel.set = {};
8793
options.markersInfo.clear();
8894
return;
8995
}
9096

91-
if (auto &listParser = ChannelSeriesList::Parser::instance();
92-
parts.size() == 4) {
97+
auto &listParser = ChannelSeriesList::Parser::instance();
98+
if (parts.size() == 4) {
9399
if (parts[3] == "begin") {
94-
if (parts[2] == "set") channel.reset();
95-
100+
if (parts[2] == "set") channel.set = {};
96101
options.markersInfo.clear();
97102
listParser.table = &table.get();
98103
listParser.channels.resize(std::stoull(value));
99104
return;
100105
}
101-
102106
listParser.current = std::nullopt;
103-
listParser.path = parts;
104107
}
105-
else {
108+
else
106109
listParser.current = std::stoull(parts.at(3));
107-
listParser.path = parts;
108-
}
110+
listParser.path = parts;
109111
}
110112

111113
if (property == "range") property += "." + parts.at(3);
112114

113115
if (auto &&accessor = getAccessor<Channel>(property).set)
114116
accessor(channel, value);
117+
else if (auto &&axisAccessor =
118+
getAccessor<AxisChannelProperties>(property).set;
119+
(channelId == AxisId::x || channelId == AxisId::y)
120+
&& axisAccessor)
121+
axisAccessor(
122+
options.getChannels().axisPropsAt(
123+
channelId == AxisId::x ? AxisId::x : AxisId::y),
124+
value);
115125
else
116126
throw std::logic_error(
117127
path + "/" + value
@@ -130,6 +140,11 @@ std::string Config::getChannelParam(const std::string &path) const
130140

131141
if (auto &&accessor = getAccessor<Channel>(property).get)
132142
return accessor(channel);
143+
if (auto &&axisAccessor =
144+
getAccessor<AxisChannelProperties>(property).get;
145+
(id == AxisId::x || id == AxisId::y) && axisAccessor)
146+
return axisAccessor(options.get().getChannels().axisPropsAt(
147+
id == AxisId::x ? AxisId::x : AxisId::y));
133148

134149
throw std::logic_error(path + ": invalid channel parameter");
135150
}

src/chart/options/options.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,9 @@ class Options : public OptionProperties
206206
[]<std::size_t... Ix>(std::index_sequence<Ix...>)
207207
{
208208
return decltype(channels){
209-
Channel::makeChannel(static_cast<ChannelId>(Ix))...};
209+
{{Channel::makeChannel(
210+
static_cast<ChannelId>(Ix))...}},
211+
{}};
210212
}(std::make_index_sequence<
211213
std::tuple_size_v<decltype(channels)::base_array>>{})};
212214

test/e2e/tests/config_tests.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"refs": ["2ac83c5"]
4242
},
4343
"dimension_axis_title": {
44-
"refs": ["33278a6"]
44+
"refs": ["0f4b203"]
4545
},
4646
"dimension_axis_density": {
4747
"refs": ["0de86a3"]

0 commit comments

Comments
 (0)