awesome/tests/examples/wibox/widget/graph/bezier_curve.lua

199 lines
6.7 KiB
Lua

--DOC_GEN_IMAGE --DOC_HIDE
local parent = ... --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
local gears = { --DOC_HIDE
color = require("gears.color"), --DOC_HIDE
math = require("gears.math"), --DOC_HIDE
shape = require("gears.shape"), --DOC_HIDE
} --DOC_HIDE
local data = { --DOC_HIDE
{3, 5, 6}, {4, 11,15}, {19,29,17},{17,14,0}, {0,3,1}, {0,0,22}, {17,7,1}, {0,0,5}, --DOC_HIDE
{3, 5, 6}, {4, 11,15}, {19,29,17},{17,14,0}, {0,3,1}, {0,0,22}, {17,7,1}, {0,0,5}, --DOC_HIDE
{3, 5, 6}, {4, 11,15}, {19,29,17},{17,14,0}, {0,3,1}, {0,0,22}, {17,7,1}, {0,0,5}, --DOC_HIDE
{3, 5, 6}, {4, 11,15}, {19,29,17},{17,14,0}, {0,3,1}, {0,0,22}, {17,7,1}, {0,0,5}, --DOC_HIDE
{3, 5, 6}, {4, 11,15}, {19,29,17},{17,14,0}, {0,3,1}, {0,0,22}, {17,7,1}, {0,0,5}, --DOC_HIDE
{3, 5, 6}, {4, 11,15}, {19,29,17},{17,14,0}, {0,3,1}, {0,0,22}, {17,7,1}, {0,0,5}, --DOC_HIDE
{3, 5, 6}, {4, 11,15}, {19,29,17},{17,14,0}, {0,3,1}, {0,0,22}, {17,7,1}, {0,0,5}, --DOC_HIDE
{3, 5, 6}, {4, 11,15}, {19,29,17},{17,14,0}, {0,3,1}, {0,0,22}, {17,7,1}, {0,0,5}, --DOC_HIDE
{3, 5, 6}, {4, 11,15}, {19,29,17},{17,14,0}, {0,3,1}, {0,0,22}, {17,7,1}, {0,0,5}, --DOC_HIDE
{3, 5, 6}, {4, 11,15}, {19,29,17},{17,14,0}, {0,3,1}, {0,0,22}, {17,7,1}, {0,0,5}, --DOC_HIDE
{3, 5, 6}, {4, 11,15}, {19,29,17},{17,14,0}, {0,3,1}, {0,0,22}, {17,7,1}, {0,0,5}, --DOC_HIDE
{3, 5, 6}, {4, 11,15}, {19,29,17},{17,14,0}, {0,3,1}, {0,0,22}, {17,7,1}, {0,0,5}, --DOC_HIDE
{3, 5, 6}, {4, 11,15}, {19,29,17},{17,14,0}, {0,3,1}, {0,0,22}, {17,7,1}, {0,0,5}, --DOC_HIDE
{3, 5, 6}, {4, 11,15}, {19,29,17},{17,14,0}, {0,3,1}, {0,0,22}, {17,7,1}, {0,0,5}, --DOC_HIDE
{3, 5, 6}, {4, 11,15}, {19,29,17},{17,14,0}, {0,3,1}, {0,0,22}, {17,7,1}, {0,0,5}, --DOC_HIDE
} --DOC_HIDE
local l = wibox.layout { --DOC_HIDE
forced_height = 100, --DOC_HIDE
forced_width = 330, --DOC_HIDE
spacing = 5, --DOC_HIDE
layout = wibox.layout.flex.horizontal --DOC_HIDE
} --DOC_HIDE
local colors = {
"#ff0000",
"#00ff00",
"#0000ff"
}
local bezier = require("gears.math.bezier")
--DOC_NEWLINE
local function curvaceous(cr, x, y, b, options, draw_line)
local interpolate = bezier.cubic_from_derivative_and_points_min_stretch
local step_width = options.graph.step_width
local state = options.curvaceous_state
if not state or state.last_group ~= options.group_idx then
-- New data series is being drawn, reset state.
state = { last_group = options.group_idx, x = x, y = y, b = b }
options.curvaceous_state = state
return
end
-- Compute if the bar needs to be cut due to spacing and how much
local step_spacing = options.graph.step_spacing
local step_fraction = step_spacing ~= 0 and step_width/(step_width+step_spacing)
-- Get coordinates from the previous step
local x0, y0, b0 = state.x, state.y, state.b
-- Update coordinates in state
state.x, state.y, state.b = x, y, b
-- Get derivatives from the previous step
local y_d, b_d = state.y_d or 0, state.b_d or 0
-- Guard against NaNs in the y coordinate
y0 = (y0 == y0) and y0 or b0
y = (y == y) and y or b
-- Horizontal linear movement of the curves
local x_curve = {bezier.cubic_through_points(x0, x0+step_width)}
-- Vertical movement curve for y
local y_curve = {interpolate(y_d, y0, y)}
state.y_d = bezier.curve_derivative_at_one(y_curve)
if step_fraction then
y_curve = bezier.curve_split_at(y_curve, step_fraction)
end
-- Paint the value curve
cr:move_to(x_curve[1], y_curve[1])
cr:curve_to(
x_curve[2], y_curve[2],
x_curve[3], y_curve[3],
x_curve[4], y_curve[4]
)
if not draw_line then
-- Vertical movement curve for the baseline
local b_curve = {interpolate(b_d, b0, b)}
state.b_d = bezier.curve_derivative_at_one(b_curve)
if step_fraction then
b_curve = bezier.curve_split_at(b_curve, step_fraction)
end
-- Paint the bar bounded by the baseline curve from below
cr:line_to(x_curve[4], b_curve[4])
cr:curve_to(
x_curve[3], b_curve[3],
x_curve[2], b_curve[2],
x_curve[1], b_curve[1]
)
cr:close_path()
end
end
--DOC_NEWLINE
local w1 = --DOC_HIDE
wibox.widget {
stack = true,
group_colors = colors,
step_width = 15,
step_hook = curvaceous,
scale = true, --DOC_HIDE,
border_width = 2, --DOC_HIDE
margins = 5, --DOC_HIDE
widget = wibox.widget.graph,
}
--DOC_NEWLINE
local w2 = --DOC_HIDE
wibox.widget {
stack = true,
group_colors = colors,
step_width = 10,
step_spacing = 5,
step_hook = curvaceous,
group_start = 0.5, -- Make vertical 1px-width lines sharper
group_finish = function(cr)
-- Paint the colored bars
cr:fill_preserve()
-- Paint a semi-black outline around bars
cr:set_line_width(1)
cr:set_source(gears.color("#0000007f"))
cr:stroke()
end,
scale = true, --DOC_HIDE,
border_width = 2, --DOC_HIDE
margins = 5, --DOC_HIDE
widget = wibox.widget.graph,
}
--DOC_NEWLINE
local w3 = --DOC_HIDE
wibox.widget {
stack = false,
group_colors = colors,
step_width = 15,
step_hook = function(cr, x, value_y, baseline_y, options)
-- Draw the curve for the previous step
curvaceous(cr, x, value_y, baseline_y, options, true)
-- Draw a tick for this step
if value_y == value_y then
cr:move_to(x, value_y - 2)
cr:line_to(x, value_y + 2)
end
end,
group_start = 0.5, -- Make vertical 1px-width lines sharper
group_finish = function(cr)
-- Paint all lines
cr:set_line_width(1)
cr:stroke()
end,
scale = true, --DOC_HIDE,
border_width = 2, --DOC_HIDE
margins = 5, --DOC_HIDE
widget = wibox.widget.graph,
}
--DOC_HIDE We need one value more than usual for the best visual result
--DOC_HIDE due to the way interpolation is done
local function cdvn(...) --DOC_HIDE
return wibox.widget.graph.compute_drawn_values_num(...) + 1 --DOC_HIDE
end --DOC_HIDE
w1.compute_drawn_values_num = cdvn --DOC_HIDE
w2.compute_drawn_values_num = cdvn --DOC_HIDE
w3.compute_drawn_values_num = cdvn --DOC_HIDE
for _, v in ipairs(data) do --DOC_HIDE
for group, value in ipairs(v) do --DOC_HIDE
w1:add_value(value, group) --DOC_HIDE
w2:add_value(value, group) --DOC_HIDE
w3:add_value(value, group) --DOC_HIDE
end --DOC_HIDE
end --DOC_HIDE
l:add(w1) --DOC_HIDE
l:add(w2) --DOC_HIDE
l:add(w3) --DOC_HIDE
parent:add(l) --DOC_HIDE
--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80