wcl_wdoc 0.11.2-alpha

WCL documentation format — build structured docs with WCL, render to HTML
    export let chart_points = (b) => {
        let points = filter(children(b), (item) => item.kind == "wdoc::draw::chart_point")
        points
    }

    export let chart_point_value = (point) => {
        let value = attr_or(point, "value", 0)
        value
    }

    export let chart_point_label = (point) => {
        let label = attr_or(point, "label", point.id)
        label
    }

    export let chart_color = (point, i) => {
        let color = attr_or(point, "color", "")
        let palette = ["#2563eb", "#16a34a", "#f97316", "#dc2626", "#7c3aed", "#0891b2", "#ca8a04", "#64748b"]
        let palette_i = min(i, len(palette) - 1)
        let result = color != "" ? color : palette[palette_i]
        result
    }

    export let chart_safe_span = (lo, hi) => {
        let span = hi == lo ? 1 : hi - lo
        span
    }

    export let chart_unit_y = (value, y_min, y_max) => {
        let unit = max(0, min(1, ((value - y_min) * 1.0) / wdoc::chart_safe_span(y_min, y_max)))
        unit
    }

    export let chart_plot_y = (value, y_min, y_max, plot_y, plot_h) => {
        let y = plot_y + plot_h - (wdoc::chart_unit_y(value, y_min, y_max) * plot_h)
        y
    }

    export let chart_tick_shapes = (i, tick_count, x, y, w, h, y_min, y_max, grid_stroke, axis_stroke, label_fill) => {
        let denom = max(1, tick_count - 1)
        let t = (i * 1.0) / denom
        let ty = y + h - (t * h)
        let value = y_min + (t * wdoc::chart_safe_span(y_min, y_max))
        [
            { kind = "line", x1 = x, y1 = ty, x2 = x + w, y2 = ty,
              stroke = i == 0 ? axis_stroke : grid_stroke, stroke_width = i == 0 ? 1.5 : 1, opacity = i == 0 ? 1 : 0.65 },
            { kind = "text", x = 0, y = ty - 7, width = x - 8, height = 14,
              content = to_string(round(value)), font_size = 10, anchor = "end", fill = label_fill, opacity = 0.72 }
        ]
    }

    export let chart_title_shapes = (title, w, title_fill) => {
        let shapes = title != "" ? [
            { kind = "text", x = 0, y = 8, width = w, height = 20,
              content = title, font_size = 14, font_weight = "600", fill = title_fill }
        ] : []
        shapes
    }

    export let chart_surface_shapes = (w, h, radius, surface_fill, border_stroke, border_width) => {
        let shapes = [
            { kind = "rect", id = "surface", x = 0, y = 0, width = w, height = h, rx = radius,
              fill = surface_fill, stroke = border_stroke, stroke_width = border_width,
              _wdoc_full_container = "true" }
        ]
        shapes
    }

    export let bar_chart_bar_shapes = (points, i, x, y, w, h, y_min, y_max, gap, axis_stroke, label_fill) => {
        let n = len(points)
        let point = points[i]
        let value = wdoc::chart_point_value(point)
        let slot_w = w / max(1, n)
        let bar_w = max(2, slot_w - gap)
        let bar_x = x + (i * slot_w) + (gap / 2)
        let zero_y = wdoc::chart_plot_y(0, y_min, y_max, y, h)
        let value_y = wdoc::chart_plot_y(value, y_min, y_max, y, h)
        let bar_y = min(zero_y, value_y)
        let bar_h = max(1, abs(zero_y - value_y))
        [
            { kind = "rect", x = bar_x, y = bar_y, width = bar_w, height = bar_h, rx = 3,
              fill = wdoc::chart_color(point, i), stroke = "none" },
            { kind = "text", x = x + (i * slot_w), y = y + h + 8, width = slot_w, height = 14,
              content = wdoc::chart_point_label(point), font_size = 10, fill = label_fill, opacity = 0.78 }
        ]
    }

    export let widget_bar_chart = (b) => {
        let points = wdoc::chart_points(b)
        let n = len(points)
        let values = n == 0 ? [0] : map(points, (point) => wdoc::chart_point_value(point))
        let w = attr_or(b, "width", 360)
        let h = attr_or(b, "height", 240)
        let title = attr_or(b, "title", "")
        let top_pad = title != "" ? 38 : 18
        let left_pad = attr_or(b, "axis_width", 46)
        let right_pad = attr_or(b, "right_padding", 18)
        let bottom_pad = attr_or(b, "bottom_padding", 34)
        let plot_x = left_pad
        let plot_y = top_pad
        let plot_w = w - left_pad - right_pad
        let plot_h = h - top_pad - bottom_pad
        let y_min = attr_or(b, "y_min", 0)
        let raw_y_max = attr_or(b, "y_max", max(1, max_of(values)))
        let y_max = raw_y_max <= y_min ? y_min + 1 : raw_y_max
        let tick_count = attr_or(b, "tick_count", 5)
        let surface_fill = attr_or(b, "surface_fill", "var(--color-bg)")
        let border_stroke = attr_or(b, "border_stroke", "var(--color-nav-border)")
        let axis_stroke = attr_or(b, "axis_stroke", border_stroke)
        let grid_stroke = attr_or(b, "grid_stroke", border_stroke)
        let label_fill = attr_or(b, "label_fill", "currentColor")
        let title_fill = attr_or(b, "title_fill", label_fill)
        let radius = attr_or(b, "radius", 8)
        let gap = attr_or(b, "bar_gap", 10)
        let ticks = flatten(map(range(0, tick_count), (i) => wdoc::chart_tick_shapes(i, tick_count, plot_x, plot_y, plot_w, plot_h, y_min, y_max, grid_stroke, axis_stroke, label_fill)))
        let bars = flatten(map(range(0, n), (i) => wdoc::bar_chart_bar_shapes(points, i, plot_x, plot_y, plot_w, plot_h, y_min, y_max, gap, axis_stroke, label_fill)))
        concat(concat(concat(concat(wdoc::chart_surface_shapes(w, h, radius, surface_fill, border_stroke, 1), wdoc::chart_title_shapes(title, w, title_fill)), ticks), [
            { kind = "line", x1 = plot_x, y1 = plot_y, x2 = plot_x, y2 = plot_y + plot_h,
              stroke = axis_stroke, stroke_width = 1.5 },
            { kind = "line", x1 = plot_x, y1 = plot_y + plot_h, x2 = plot_x + plot_w, y2 = plot_y + plot_h,
              stroke = axis_stroke, stroke_width = 1.5 }
        ]), bars)
    }

    export let line_chart_x_value = (points, i) => {
        let value = has(points[i], "x") ? attr_or(points[i], "x", i) : i
        value
    }

    export let line_chart_path = (points, n, x_min, x_max, y_min, y_max, plot_x, plot_y, plot_w, plot_h) => {
        let d = n == 0 ? "" : join(" ", map(range(0, n), (i) => {
            let px = plot_x + (((wdoc::line_chart_x_value(points, i) - x_min) * 1.0) / wdoc::chart_safe_span(x_min, x_max) * plot_w)
            let py = wdoc::chart_plot_y(wdoc::chart_point_value(points[i]), y_min, y_max, plot_y, plot_h)
            (i == 0 ? "M " : "L ") + to_string(px) + " " + to_string(py)
        }))
        d
    }

    export let line_chart_point_shapes = (points, i, x_min, x_max, y_min, y_max, plot_x, plot_y, plot_w, plot_h, point_radius, fill, label_fill) => {
        let px = plot_x + (((wdoc::line_chart_x_value(points, i) - x_min) * 1.0) / wdoc::chart_safe_span(x_min, x_max) * plot_w)
        let py = wdoc::chart_plot_y(wdoc::chart_point_value(points[i]), y_min, y_max, plot_y, plot_h)
        [
            { kind = "circle", x = px - point_radius, y = py - point_radius, width = point_radius * 2, height = point_radius * 2,
              fill = fill, stroke = "var(--color-bg)", stroke_width = 1.5 },
            { kind = "text", x = px - 30, y = plot_y + plot_h + 8, width = 60, height = 14,
              content = wdoc::chart_point_label(points[i]), font_size = 10, fill = label_fill, opacity = 0.78 }
        ]
    }

    export let widget_line_chart = (b) => {
        let points = wdoc::chart_points(b)
        let n = len(points)
        let values = n == 0 ? [0] : map(points, (point) => wdoc::chart_point_value(point))
        let x_values = n == 0 ? [0] : map(range(0, n), (i) => wdoc::line_chart_x_value(points, i))
        let w = attr_or(b, "width", 380)
        let h = attr_or(b, "height", 240)
        let title = attr_or(b, "title", "")
        let top_pad = title != "" ? 38 : 18
        let left_pad = attr_or(b, "axis_width", 46)
        let right_pad = attr_or(b, "right_padding", 22)
        let bottom_pad = attr_or(b, "bottom_padding", 34)
        let plot_x = left_pad
        let plot_y = top_pad
        let plot_w = w - left_pad - right_pad
        let plot_h = h - top_pad - bottom_pad
        let y_min = attr_or(b, "y_min", 0)
        let raw_y_max = attr_or(b, "y_max", max(1, max_of(values)))
        let y_max = raw_y_max <= y_min ? y_min + 1 : raw_y_max
        let x_min = attr_or(b, "x_min", min_of(x_values))
        let raw_x_max = attr_or(b, "x_max", max_of(x_values))
        let x_max = raw_x_max <= x_min ? x_min + 1 : raw_x_max
        let tick_count = attr_or(b, "tick_count", 5)
        let surface_fill = attr_or(b, "surface_fill", "var(--color-bg)")
        let border_stroke = attr_or(b, "border_stroke", "var(--color-nav-border)")
        let axis_stroke = attr_or(b, "axis_stroke", border_stroke)
        let grid_stroke = attr_or(b, "grid_stroke", border_stroke)
        let label_fill = attr_or(b, "label_fill", "currentColor")
        let title_fill = attr_or(b, "title_fill", label_fill)
        let line_stroke = attr_or(b, "line_stroke", "var(--color-link)")
        let line_width = attr_or(b, "line_width", 2.5)
        let show_points = attr_or(b, "show_points", true)
        let point_radius = attr_or(b, "point_radius", 4)
        let radius = attr_or(b, "radius", 8)
        let ticks = flatten(map(range(0, tick_count), (i) => wdoc::chart_tick_shapes(i, tick_count, plot_x, plot_y, plot_w, plot_h, y_min, y_max, grid_stroke, axis_stroke, label_fill)))
        let point_shapes = show_points ? flatten(map(range(0, n), (i) => wdoc::line_chart_point_shapes(points, i, x_min, x_max, y_min, y_max, plot_x, plot_y, plot_w, plot_h, point_radius, line_stroke, label_fill))) : []
        concat(concat(concat(concat(concat(wdoc::chart_surface_shapes(w, h, radius, surface_fill, border_stroke, 1), wdoc::chart_title_shapes(title, w, title_fill)), ticks), [
            { kind = "line", x1 = plot_x, y1 = plot_y, x2 = plot_x, y2 = plot_y + plot_h,
              stroke = axis_stroke, stroke_width = 1.5 },
            { kind = "line", x1 = plot_x, y1 = plot_y + plot_h, x2 = plot_x + plot_w, y2 = plot_y + plot_h,
              stroke = axis_stroke, stroke_width = 1.5 },
            { kind = "path", x = 0, y = 0, width = w, height = h,
              d = wdoc::line_chart_path(points, n, x_min, x_max, y_min, y_max, plot_x, plot_y, plot_w, plot_h),
              fill = "none", stroke = line_stroke, stroke_width = line_width, stroke_linecap = "round", stroke_linejoin = "round" }
        ]), point_shapes), [])
    }

    export let pie_chart_slice_path = (cx, cy, r, start_angle, end_angle) => {
        let sx = cx + (cos(start_angle) * r)
        let sy = cy + (sin(start_angle) * r)
        let ex = cx + (cos(end_angle) * r)
        let ey = cy + (sin(end_angle) * r)
        let large_arc = end_angle - start_angle > pi() ? 1 : 0
        "M " + to_string(cx) + " " + to_string(cy) +
        " L " + to_string(sx) + " " + to_string(sy) +
        " A " + to_string(r) + " " + to_string(r) + " 0 " + to_string(large_arc) + " 1 " + to_string(ex) + " " + to_string(ey) + " Z"
    }

    export let pie_chart_slice_shapes = (points, i, values, total, cx, cy, r, start_offset, label_fill) => {
        let start_value = sum(map(range(0, i), (j) => values[j]))
        let end_value = start_value + values[i]
        let start_angle = start_offset + (((start_value * 1.0) / total) * pi() * 2)
        let end_angle = start_offset + (((end_value * 1.0) / total) * pi() * 2)
        let point = points[i]
        let mid_angle = (start_angle + end_angle) / 2
        let label_x = cx + (cos(mid_angle) * r * 0.62) - 25
        let label_y = cy + (sin(mid_angle) * r * 0.62) - 7
        [
            { kind = "path", x = 0, y = 0, width = cx * 2, height = cy * 2,
              d = wdoc::pie_chart_slice_path(cx, cy, r, start_angle, end_angle),
              fill = wdoc::chart_color(point, i), stroke = "var(--color-bg)", stroke_width = 1.5 },
            { kind = "text", x = label_x, y = label_y, width = 50, height = 14,
              content = wdoc::chart_point_label(point), font_size = 10, fill = label_fill }
        ]
    }

    export let pie_chart_legend_shapes = (points, i, x, y, label_fill) => {
        let row_y = y + (i * 20)
        [
            { kind = "rect", x = x, y = row_y + 4, width = 10, height = 10, rx = 2,
              fill = wdoc::chart_color(points[i], i), stroke = "none" },
            { kind = "text", x = x + 16, y = row_y, width = 110, height = 18,
              content = wdoc::chart_point_label(points[i]), font_size = 11, anchor = "start", fill = label_fill }
        ]
    }

    export let widget_pie_chart = (b) => {
        let raw_points = wdoc::chart_points(b)
        let points = filter(raw_points, (point) => wdoc::chart_point_value(point) > 0)
        let n = len(points)
        let values = n == 0 ? [0] : map(points, (point) => wdoc::chart_point_value(point))
        let w = attr_or(b, "width", 360)
        let h = attr_or(b, "height", 240)
        let title = attr_or(b, "title", "")
        let top_pad = title != "" ? 38 : 18
        let surface_fill = attr_or(b, "surface_fill", "var(--color-bg)")
        let border_stroke = attr_or(b, "border_stroke", "var(--color-nav-border)")
        let label_fill = attr_or(b, "label_fill", "currentColor")
        let title_fill = attr_or(b, "title_fill", label_fill)
        let show_legend = attr_or(b, "show_legend", true)
        let radius = attr_or(b, "radius", 8)
        let pie_r = attr_or(b, "pie_radius", min((show_legend ? w - 150 : w - 34) / 2, (h - top_pad - 18) / 2))
        let cx = 22 + pie_r
        let cy = top_pad + pie_r
        let total = attr_or(b, "total", max(1, sum(values)))
        let start_offset = attr_or(b, "start_angle", -90) * pi() / 180
        let slices = n == 1 ? [
            { kind = "circle", x = cx - pie_r, y = cy - pie_r, width = pie_r * 2, height = pie_r * 2,
              fill = wdoc::chart_color(points[0], 0), stroke = "var(--color-bg)", stroke_width = 1.5 },
            { kind = "text", x = cx - 30, y = cy - 7, width = 60, height = 14,
              content = wdoc::chart_point_label(points[0]), font_size = 10, fill = label_fill }
        ] : flatten(map(range(0, n), (i) => wdoc::pie_chart_slice_shapes(points, i, values, total, cx, cy, pie_r, start_offset, label_fill)))
        let legend = show_legend ? flatten(map(range(0, n), (i) => wdoc::pie_chart_legend_shapes(points, i, cx + pie_r + 24, top_pad + 6, label_fill))) : []
        concat(concat(concat(wdoc::chart_surface_shapes(w, h, radius, surface_fill, border_stroke, 1), wdoc::chart_title_shapes(title, w, title_fill)), slices), legend)
    }