| 407 | } |
| 408 | |
| 409 | static ReturnCode plot_axis_horizontal( |
| 410 | Context* ctx, |
| 411 | PlotConfig* plot, |
| 412 | const AxisDefinition& axis_config, |
| 413 | double y, |
| 414 | double x0, |
| 415 | double x1) { |
| 416 | /* draw axis line */ |
| 417 | draw_line(ctx, {x0, y}, {x1, y}, axis_config.border_style); |
| 418 | |
| 419 | /* draw ticks */ |
| 420 | ScaleLayout ticks; |
| 421 | axis_config.tick_placement( |
| 422 | axis_config.scale, |
| 423 | axis_config.label_formatter, |
| 424 | &ticks); |
| 425 | |
| 426 | double tick_position = |
| 427 | std::clamp(axis_config.tick_offset, -1.0, 1.0); |
| 428 | |
| 429 | auto tick_length = measure_or( |
| 430 | axis_config.tick_length, |
| 431 | from_pt(kDefaultTickLengthPT, layer_get_dpi(ctx))); |
| 432 | |
| 433 | for (const auto& tick : ticks.positions) { |
| 434 | auto ty = y - tick_length + tick_length * (tick_position + 1) / 2.0; |
| 435 | auto tx = x0 + (x1 - x0) * tick; |
| 436 | draw_line( |
| 437 | ctx, |
| 438 | {tx, ty}, |
| 439 | {tx, ty + tick_length}, |
| 440 | axis_config.border_style); |
| 441 | } |
| 442 | |
| 443 | /* draw labels */ |
| 444 | ScaleLayout labels; |
| 445 | axis_config.label_placement( |
| 446 | axis_config.scale, |
| 447 | axis_config.label_formatter, |
| 448 | &labels); |
| 449 | |
| 450 | double label_position = |
| 451 | std::clamp(axis_config.label_offset, -1.0, 1.0); |
| 452 | |
| 453 | double label_padding = measure_or( |
| 454 | axis_config.label_padding, |
| 455 | from_em(kDefaultLabelPaddingEM, axis_config.label_font_size)); |
| 456 | |
| 457 | double label_size = 0; |
| 458 | if (auto rc = axis_layout_labels(axis_config, ctx, &label_size); !rc) { |
| 459 | return rc; |
| 460 | } |
| 461 | |
| 462 | for (size_t i = 0; i < labels.positions.size(); ++i) { |
| 463 | auto tick = labels.positions[i]; |
| 464 | auto label_text = labels.labels[i]; |
| 465 | |
| 466 | Point p; |
no test coverage detected