Skip to documentation
SLOP

tiny.zen.diagram.bounds

Reference tiny.zen diagram bounds

Defined in diagram.

API (7)

Actions

Public operations.

Types and contracts

Public types and contracts.

No direct callersNo direct callsdiagrambounds
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsAsciiRenderPlaninspectdiagram.boundscomputediagram.boundscomputeIntest sourcelib.zen.src.diagram.boundstest: bounds scratch plan counts uniq...private sourcelib.zen.src.diagram.boundscategoryValueprivate sourcelib.zen.src.diagram.boundshasBarprivate sourcelib.zen.src.diagram.boundshasCategorydiagram.stackhasdiagram.bounds.ScratchPlaninspect
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersdiagram.bounds.ScratchPlaninspectprivate sourcelib.zen.src.diagram.boundscomputePrepareddiagram.boundscompute
Static calls · unresolved targets: 2 · external targets: 2.
Called byCallstiny.zenrenderAsciiDocumentdiagram.bounds.ScratchPlaninspectprivate sourcelib.zen.src.diagram.boundscomputePrepareddiagram.boundscomputeIn
Static calls · unresolved targets: 0 · external targets: 0.

Source: lib/zen/src/diagram/bounds.zig

zig
const std = @import("std");const category = @import("category.zig");const domain = @import("domain.zig");const model = @import("model.zig");const root = @import("root.zig");const stack = @import("stack.zig");const spec = root.spec;pub const Bounds = model.Bounds;pub const StackTotal = struct {    x: []const u8,    positive: f64 = 0,    negative: f64 = 0,};const StackSpan = struct {    start: f64,    end: f64,};pub const ScratchPlan = struct {    categories: usize,    stack_totals: usize,    pub fn inspect(document: *const spec.Document) ScratchPlan {        var categories: usize = 0;        var stack_totals: usize = 0;        const stacked = stack.has(document);        for (document.marks.items, 0..) |mark, index| {            if (categoryValue(mark)) |label_value| {                if (!hasCategory(document.marks.items[0..index], label_value)) categories += 1;            }            if (stacked) switch (mark) {                .bar => |bar| if (!hasBar(document.marks.items[0..index], bar.x)) {                    stack_totals += 1;                },                else => {},            };        }        return .{            .categories = categories,            .stack_totals = stack_totals,        };    }};pub fn compute(allocator: std.mem.Allocator, document: *const spec.Document) !Bounds {    const plan = ScratchPlan.inspect(document);    var bounds = Bounds{};    errdefer bounds.deinit(allocator);    try bounds.categories.ensureTotalCapacityPrecise(allocator, plan.categories);    var stack_totals: std.ArrayList(StackTotal) = .empty;    defer stack_totals.deinit(allocator);    try stack_totals.ensureTotalCapacityPrecise(allocator, plan.stack_totals);    return computePrepared(&bounds, &stack_totals, document);}pub fn computeIn(    categories: [][]const u8,    stack_totals: []StackTotal,    document: *const spec.Document,) !Bounds {    const plan = ScratchPlan.inspect(document);    std.debug.assert(categories.len >= plan.categories);    std.debug.assert(stack_totals.len >= plan.stack_totals);    var bounds = Bounds{        .categories = .{            .items = categories[0..0],            .capacity = categories.len,        },        .category_slots_owned = false,    };    var totals = std.ArrayList(StackTotal){        .items = stack_totals[0..0],        .capacity = stack_totals.len,    };    return computePrepared(&bounds, &totals, document);}fn computePrepared(    bounds: *Bounds,    stack_totals: *std.ArrayList(StackTotal),    document: *const spec.Document,) !Bounds {    bounds.x_kind = document.scales.x.kind;    bounds.y_kind = document.scales.y.kind;    bounds.x_base = document.scales.x.base;    bounds.y_base = document.scales.y.base;    const x_min = document.scales.x.min orelse document.frame.x_min;    const x_max = document.scales.x.max orelse document.frame.x_max;    const y_min = document.scales.y.min orelse document.frame.y_min;    const y_max = document.scales.y.max orelse document.frame.y_max;    bounds.y_min = y_min orelse if (bounds.y_kind == .log) 1 else 0;    bounds.y_max = y_max orelse if (bounds.y_kind == .log) 10 else 1;    bounds.x_min = x_min orelse if (bounds.x_kind == .log) 1 else 0;    bounds.x_max = x_max orelse if (bounds.x_kind == .log) 10 else 1;    var saw_y = y_min != null or y_max != null;    var saw_x = x_min != null or x_max != null;    const stack_bars = stack.has(document);    if (stack_bars and bounds.y_kind == .log) return error.InvalidScale;    for (document.marks.items) |mark| switch (mark) {        .bar => |bar| {            bounds.categorical = true;            category.appendAssumeCapacity(bounds, bar.x);            if (stack_bars) {                const span = advanceStack(stack_totals, bar.x, bar.y);                includeY(bounds, &saw_y, span.start);                includeY(bounds, &saw_y, span.end);            } else {                includeY(bounds, &saw_y, bar.y);                if (bounds.y_kind == .linear) includeY(bounds, &saw_y, 0);            }        },        .point => |point| {            includeXValue(bounds, &saw_x, point.x);            includeY(bounds, &saw_y, point.y);        },        .rule => |rule| {            includeX(bounds, &saw_x, rule.x1);            includeX(bounds, &saw_x, rule.x2);            includeY(bounds, &saw_y, rule.y1);            includeY(bounds, &saw_y, rule.y2);        },        .text => |text| {            includeXValue(bounds, &saw_x, text.x);            includeY(bounds, &saw_y, text.y);        },        .box => |box| {            includeX(bounds, &saw_x, box.x - box.width / 2);            includeX(bounds, &saw_x, box.x + box.width / 2);            includeY(bounds, &saw_y, box.y - box.height / 2);            includeY(bounds, &saw_y, box.y + box.height / 2);        },        .edge => |edge| {            includeX(bounds, &saw_x, edge.x1);            includeX(bounds, &saw_x, edge.x2);            includeY(bounds, &saw_y, edge.y1);            includeY(bounds, &saw_y, edge.y2);        },    };    if (!saw_y) {        bounds.y_min = if (bounds.y_kind == .log) 1 else 0;        bounds.y_max = if (bounds.y_kind == .log) 10 else 1;    }    if (!saw_x) {        bounds.x_min = if (bounds.x_kind == .log) 1 else 0;        bounds.x_max = if (bounds.x_kind == .log) 10 else 1;    }    domain.expand(&bounds.y_min, &bounds.y_max, bounds.y_kind, bounds.y_base);    domain.expand(&bounds.x_min, &bounds.x_max, bounds.x_kind, bounds.x_base);    try domain.validate(bounds.*);    return bounds.*;}fn advanceStack(    totals: *std.ArrayList(StackTotal),    x: []const u8,    y: f64,) StackSpan {    for (totals.items) |*total| {        if (!std.mem.eql(u8, total.x, x)) continue;        return advanceTotal(total, y);    }    totals.appendAssumeCapacity(.{ .x = x });    return advanceTotal(&totals.items[totals.items.len - 1], y);}fn advanceTotal(total: *StackTotal, y: f64) StackSpan {    if (y >= 0) {        const start = total.positive;        total.positive += y;        return .{ .start = start, .end = total.positive };    }    const start = total.negative;    total.negative += y;    return .{ .start = start, .end = total.negative };}fn includeXValue(bounds: *Bounds, saw_x: *bool, value: spec.XValue) void {    switch (value) {        .number => |number| includeX(bounds, saw_x, number),        .text => |text| {            bounds.categorical = true;            category.appendAssumeCapacity(bounds, text);        },    }}fn includeX(bounds: *Bounds, saw_x: *bool, value: f64) void {    if (!saw_x.*) {        bounds.x_min = value;        bounds.x_max = value;        saw_x.* = true;        return;    }    bounds.x_min = @min(bounds.x_min, value);    bounds.x_max = @max(bounds.x_max, value);}fn includeY(bounds: *Bounds, saw_y: *bool, value: f64) void {    if (!saw_y.*) {        bounds.y_min = value;        bounds.y_max = value;        saw_y.* = true;        return;    }    bounds.y_min = @min(bounds.y_min, value);    bounds.y_max = @max(bounds.y_max, value);}fn categoryValue(mark: spec.Mark) ?[]const u8 {    return switch (mark) {        .bar => |bar| bar.x,        .point => |point| switch (point.x) {            .text => |text| text,            .number => null,        },        .text => |text_mark| switch (text_mark.x) {            .text => |text| text,            .number => null,        },        else => null,    };}fn hasCategory(marks: []const spec.Mark, label_value: []const u8) bool {    for (marks) |mark| {        const candidate = categoryValue(mark) orelse continue;        if (std.mem.eql(u8, candidate, label_value)) return true;    }    return false;}fn hasBar(marks: []const spec.Mark, x: []const u8) bool {    for (marks) |mark| switch (mark) {        .bar => |bar| if (std.mem.eql(u8, bar.x, x)) return true,        else => {},    };    return false;}pub fn barBaseline(bounds: Bounds) f64 {    return if (bounds.y_kind == .log) bounds.y_min else 0;}test "bounds scratch plan counts unique categories and stacked totals" {    const marks = [_]spec.Mark{        .{ .bar = .{ .x = @constCast("a"), .y = 1 } },        .{ .bar = .{ .x = @constCast("a"), .y = 2 } },        .{ .point = .{ .x = .{ .text = @constCast("b") }, .y = 3 } },    };    var transforms = [_]spec.Transform{        .{ .stack = .{} },    };    var document = spec.Document{        .allocator = std.testing.allocator,        .marks = .{ .items = @constCast(&marks), .capacity = marks.len },        .transforms = .{ .items = &transforms, .capacity = transforms.len },    };    const plan = ScratchPlan.inspect(&document);    try std.testing.expectEqual(@as(usize, 2), plan.categories);    try std.testing.expectEqual(@as(usize, 1), plan.stack_totals);}

Source: lib/zen/src/diagram/root.zig:2

zig
pub const bounds = @import("bounds.zig");

Audit

Definitions7
Public names7
Members5
Version26.7.0
Revisiondaab053ee433