mirror of
https://github.com/Relintai/pandemonium_engine_easy_charts.git
synced 2024-12-25 13:57:23 +01:00
add BarChart
This commit is contained in:
parent
558e978723
commit
4983f61f5c
184
addons/easy_charts/control_charts/BarChart/bar_chart.gd
Normal file
184
addons/easy_charts/control_charts/BarChart/bar_chart.gd
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
extends Chart
|
||||||
|
class_name BarChart
|
||||||
|
|
||||||
|
signal bar_entered(bar)
|
||||||
|
|
||||||
|
# Size of a horizontal vector, which is calculated by `plot_box.size.x / x.size()`
|
||||||
|
var x_sector_size: float
|
||||||
|
|
||||||
|
# List of all unordered bars belonging to this plot
|
||||||
|
var bars: Array = []
|
||||||
|
|
||||||
|
# List of all bars, grouped by function
|
||||||
|
var function_bars: Array = []
|
||||||
|
|
||||||
|
# Currently focused bar
|
||||||
|
var focused_bar: Bar = null
|
||||||
|
|
||||||
|
func _clear_bars() -> void:
|
||||||
|
bars.clear()
|
||||||
|
function_bars.clear()
|
||||||
|
|
||||||
|
func _clear() -> void:
|
||||||
|
_clear_bars()
|
||||||
|
|
||||||
|
func _calc_x_domain() -> void:
|
||||||
|
pass
|
||||||
|
|
||||||
|
func _sample_x() -> void:
|
||||||
|
### @sampled_domain, which are the domain relative to the sampled values
|
||||||
|
### x (real value) --> sampling --> x_sampled (pixel value in canvas)
|
||||||
|
x_sampled_domain = Pair.new(plot_box.position.x, plot_box.end.x)
|
||||||
|
|
||||||
|
# samples
|
||||||
|
x_sampled = SampledAxis.new(x, x_sampled_domain)
|
||||||
|
|
||||||
|
x_sector_size = (x_sampled_domain.right - x_sampled_domain.left) / x.size()
|
||||||
|
|
||||||
|
func sort_ascending(a: String, b: String):
|
||||||
|
if a.length() < b.length():
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
func _find_longest_x() -> String:
|
||||||
|
var longest_x: String = ""
|
||||||
|
var x_str: Array = x.duplicate(true)
|
||||||
|
x_str.sort_custom(self, "sort_ascending")
|
||||||
|
return x_str.back()
|
||||||
|
|
||||||
|
|
||||||
|
func _draw_bar(bar: Bar, function_index: int) -> void:
|
||||||
|
draw_rect(
|
||||||
|
bar.rect,
|
||||||
|
chart_properties.get_function_color(function_index),
|
||||||
|
true,
|
||||||
|
1,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
func _draw_bars() -> void:
|
||||||
|
for function in function_bars.size():
|
||||||
|
for i in range(0, function_bars[function].size()):
|
||||||
|
_draw_bar(
|
||||||
|
function_bars[function][i],
|
||||||
|
function
|
||||||
|
)
|
||||||
|
|
||||||
|
func _get_tick_label(line_index: int, line_value: float) -> String:
|
||||||
|
return x[line_index]
|
||||||
|
|
||||||
|
func _get_vertical_tick_label_pos(base_position: Vector2, text: String) -> Vector2:
|
||||||
|
return ._get_vertical_tick_label_pos(base_position, text) + Vector2(x_sector_size / 2, 0)
|
||||||
|
|
||||||
|
|
||||||
|
func _draw_vertical_grid() -> void:
|
||||||
|
# draw vertical lines
|
||||||
|
|
||||||
|
# 1. the amount of lines is equals to the X_scale: it identifies in how many sectors the x domain
|
||||||
|
# should be devided
|
||||||
|
# 2. calculate the spacing between each line in pixel. It is equals to x_sampled_domain / x_scale
|
||||||
|
# 3. calculate the offset in the real x domain, which is x_domain / x_scale.
|
||||||
|
for _x in x.size():
|
||||||
|
var top: Vector2 = Vector2(
|
||||||
|
(_x * x_sector_size) + plot_box.position.x,
|
||||||
|
bounding_box.position.y
|
||||||
|
)
|
||||||
|
var bottom: Vector2 = Vector2(
|
||||||
|
(_x * x_sector_size) + plot_box.position.x,
|
||||||
|
bounding_box.end.y
|
||||||
|
)
|
||||||
|
|
||||||
|
_draw_vertical_gridline_component(top, bottom, _x, x_sector_size)
|
||||||
|
|
||||||
|
### Draw last gridline
|
||||||
|
var p1: Vector2 = Vector2(
|
||||||
|
(x.size() * x_sector_size) + plot_box.position.x,
|
||||||
|
bounding_box.position.y
|
||||||
|
)
|
||||||
|
|
||||||
|
var p2: Vector2 = Vector2(
|
||||||
|
(x.size() * x_sector_size) + plot_box.position.x,
|
||||||
|
bounding_box.end.y
|
||||||
|
)
|
||||||
|
|
||||||
|
# Draw V Ticks
|
||||||
|
if chart_properties.ticks:
|
||||||
|
_draw_tick(p2, p2 + Vector2(0, _x_tick_size), chart_properties.colors.bounding_box)
|
||||||
|
|
||||||
|
# Draw V Grid Lines
|
||||||
|
if chart_properties.grid:
|
||||||
|
draw_line(p1, p2, chart_properties.colors.grid, 1, true)
|
||||||
|
|
||||||
|
func _calculate_bars() -> void:
|
||||||
|
var validation: int = _validate_sampled_axis(x_sampled, y_sampled)
|
||||||
|
if not validation == OK:
|
||||||
|
printerr("Cannot plot bars for invalid dataset! Error: %s" % validation)
|
||||||
|
return
|
||||||
|
|
||||||
|
if y_sampled.values[0] is Array:
|
||||||
|
for yxi in y_sampled.values.size():
|
||||||
|
var _function_bars: Array = []
|
||||||
|
for i in y_sampled.values[yxi].size():
|
||||||
|
var real_bar_value: Pair = Pair.new(x[i], y[yxi][i])
|
||||||
|
var sampled_bar_pos: Vector2 = Vector2(
|
||||||
|
(x_sector_size * i) + x_sampled_domain.left + (x_sector_size / 2) - (chart_properties.bar_width / 2),
|
||||||
|
y_sampled.values[yxi][i]
|
||||||
|
)
|
||||||
|
var sampled_bar_size: Vector2 = Vector2(
|
||||||
|
chart_properties.bar_width,
|
||||||
|
y_sampled_domain.left - y_sampled.values[yxi][i]
|
||||||
|
)
|
||||||
|
var bar: Bar = Bar.new(Rect2(sampled_bar_pos, sampled_bar_size), real_bar_value)
|
||||||
|
_function_bars.append(bar)
|
||||||
|
bars.append(bar)
|
||||||
|
function_bars.append(_function_bars)
|
||||||
|
else:
|
||||||
|
for i in y_sampled.values.size():
|
||||||
|
var real_bar_value: Pair = Pair.new(x[i], y[i])
|
||||||
|
var sampled_bar_pos: Vector2 = Vector2(
|
||||||
|
(x_sector_size * i) + x_sampled_domain.left + (x_sector_size / 2) - chart_properties.bar_width,
|
||||||
|
y_sampled.values[i]
|
||||||
|
)
|
||||||
|
var sampled_bar_size: Vector2 = Vector2(
|
||||||
|
chart_properties.bar_width,
|
||||||
|
y_sampled_domain.left - y_sampled.values[i]
|
||||||
|
)
|
||||||
|
var bar: Bar = Bar.new(Rect2(sampled_bar_pos, sampled_bar_size), real_bar_value)
|
||||||
|
bars.append(bar)
|
||||||
|
function_bars.append(bars)
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
_calculate_bars()
|
||||||
|
|
||||||
|
_draw_bars()
|
||||||
|
|
||||||
|
func _get_function_bar(bar: Bar) -> int:
|
||||||
|
var bar_f_index: int = -1
|
||||||
|
for f_bar in function_bars.size():
|
||||||
|
var found: int = function_bars[f_bar].find(bar)
|
||||||
|
if found != -1:
|
||||||
|
bar_f_index = f_bar
|
||||||
|
break
|
||||||
|
return bar_f_index
|
||||||
|
|
||||||
|
func _input(event: InputEvent) -> void:
|
||||||
|
if event is InputEventMouse:
|
||||||
|
for bar in bars:
|
||||||
|
if bar.rect.abs().has_point(event.position):
|
||||||
|
if focused_bar == bar:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
focused_bar = bar
|
||||||
|
var func_index: int = _get_function_bar(focused_bar)
|
||||||
|
$Tooltip.update_values(
|
||||||
|
str(focused_bar.value.left),
|
||||||
|
str(focused_bar.value.right),
|
||||||
|
_get_function_name(func_index),
|
||||||
|
_get_function_color(func_index)
|
||||||
|
)
|
||||||
|
$Tooltip.show()
|
||||||
|
emit_signal("bar_entered", bar)
|
||||||
|
return
|
||||||
|
# Mouse is not in any bar's box
|
||||||
|
focused_bar = null
|
||||||
|
$Tooltip.hide()
|
14
addons/easy_charts/control_charts/BarChart/bar_chart.tscn
Normal file
14
addons/easy_charts/control_charts/BarChart/bar_chart.tscn
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[gd_scene load_steps=3 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/easy_charts/control_charts/BarChart/bar_chart.gd" type="Script" id=1]
|
||||||
|
[ext_resource path="res://addons/easy_charts/control_charts/chart.tscn" type="PackedScene" id=2]
|
||||||
|
|
||||||
|
[node name="BarChart" instance=ExtResource( 2 )]
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
|
[node name="Tooltip" parent="." index="1"]
|
||||||
|
margin_right = 20.0
|
||||||
|
margin_bottom = 16.0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": true
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user