mirror of
https://github.com/Relintai/pmlpp_sample.git
synced 2024-12-21 13:47:52 +01:00
Added the easy charts addon.
This commit is contained in:
parent
987f923346
commit
952078279a
184
game/addons/easy_charts/control_charts/BarChart/bar_chart.gd
Normal file
184
game/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()
|
@ -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
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
extends ScatterChart
|
||||
class_name LineChart
|
||||
|
||||
func _draw_line(from: Point, to: Point, function_index: int) -> void:
|
||||
draw_line(
|
||||
from.position,
|
||||
to.position,
|
||||
chart_properties.get_function_color(function_index),
|
||||
chart_properties.line_width,
|
||||
true
|
||||
)
|
||||
|
||||
func _draw_spline(points: Array, function: int, density: float = 10.0, tension: float = 1) -> void:
|
||||
var spline_points: Array = []
|
||||
|
||||
var augmented: Array = points.duplicate(true)
|
||||
var pi: Point = Point.new(points.front().position - Vector2(10, -10), Pair.new())
|
||||
var pf: Point = Point.new(points.back().position + Vector2(10, 10), Pair.new())
|
||||
|
||||
augmented.insert(0, pi)
|
||||
augmented.append(pf)
|
||||
|
||||
for p in range(1, augmented.size() - 2, 1) : #(inclusive)
|
||||
|
||||
for f in range(0, density + 1, 1):
|
||||
spline_points.append(
|
||||
augmented[p].position.cubic_interpolate(
|
||||
augmented[p + 1].position,
|
||||
augmented[p - 1].position,
|
||||
augmented[p + 2].position,
|
||||
f / density)
|
||||
)
|
||||
|
||||
for i in range(1, spline_points.size()):
|
||||
draw_line(spline_points[i-1], spline_points[i], chart_properties.get_function_color(function), chart_properties.line_width, true)
|
||||
|
||||
func _draw_lines() -> void:
|
||||
for function in function_points.size():
|
||||
if chart_properties.use_splines:
|
||||
_draw_spline(function_points[function], function)
|
||||
else:
|
||||
for i in range(1, function_points[function].size()):
|
||||
_draw_line(function_points[function][i - 1], function_points[function][i], function)
|
||||
|
||||
func _draw() -> void:
|
||||
_draw_lines()
|
@ -0,0 +1,7 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://addons/easy_charts/control_charts/LineChart/line_chart.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/easy_charts/control_charts/chart.tscn" type="PackedScene" id=2]
|
||||
|
||||
[node name="LineChart" instance=ExtResource( 2 )]
|
||||
script = ExtResource( 1 )
|
@ -0,0 +1,124 @@
|
||||
extends Chart
|
||||
class_name ScatterChart
|
||||
|
||||
signal point_entered(point)
|
||||
|
||||
var _point_box_rad: int = 10
|
||||
|
||||
# List of all unordered points belonging to this plot
|
||||
var points: Array = []
|
||||
|
||||
# List of all points, grouped by function
|
||||
var function_points: Array = []
|
||||
|
||||
# Currently focused point
|
||||
var focused_point: Point = null
|
||||
|
||||
func _clear_points() -> void:
|
||||
points.clear()
|
||||
function_points.clear()
|
||||
|
||||
func _clear() -> void:
|
||||
_clear_points()
|
||||
|
||||
func _get_point_box(point: Point, rad: int) -> Rect2:
|
||||
return Rect2(point.position - (Vector2.ONE * rad), (Vector2.ONE * rad * 2))
|
||||
|
||||
func _get_function_point(point: Point) -> int:
|
||||
var point_f_index: int = -1
|
||||
for f_point in function_points.size():
|
||||
var found: int = function_points[f_point].find(point)
|
||||
if found != -1:
|
||||
point_f_index = f_point
|
||||
break
|
||||
return point_f_index
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event is InputEventMouse:
|
||||
for point in points:
|
||||
if _get_point_box(point, _point_box_rad).abs().has_point(event.position):
|
||||
if focused_point == point:
|
||||
return
|
||||
else:
|
||||
focused_point = point
|
||||
var func_index: int = _get_function_point(focused_point)
|
||||
$Tooltip.update_values(
|
||||
str(point.value.left),
|
||||
str(point.value.right),
|
||||
_get_function_name(func_index),
|
||||
_get_function_color(func_index)
|
||||
)
|
||||
$Tooltip.show()
|
||||
emit_signal("point_entered", point)
|
||||
return
|
||||
# Mouse is not in any point's box
|
||||
focused_point = null
|
||||
$Tooltip.hide()
|
||||
|
||||
func _draw_point(point: Point, function_index: int) -> void:
|
||||
match chart_properties.get_point_shape(function_index):
|
||||
Point.Shape.CIRCLE:
|
||||
draw_circle(point.position, chart_properties.point_radius, chart_properties.get_function_color(function_index))
|
||||
Point.Shape.SQUARE:
|
||||
draw_rect(_get_point_box(point, chart_properties.point_radius), chart_properties.get_function_color(function_index), true, 1.0, false)
|
||||
Point.Shape.TRIANGLE:
|
||||
draw_colored_polygon(
|
||||
PoolVector2Array([
|
||||
point.position + (Vector2.UP * chart_properties.point_radius * 1.3),
|
||||
point.position + (Vector2.ONE * chart_properties.point_radius * 1.3),
|
||||
point.position - (Vector2(1, -1) * chart_properties.point_radius * 1.3)
|
||||
]), chart_properties.get_function_color(function_index), [], null, null, false
|
||||
)
|
||||
Point.Shape.CROSS:
|
||||
draw_line(
|
||||
point.position - (Vector2.ONE * chart_properties.point_radius),
|
||||
point.position + (Vector2.ONE * chart_properties.point_radius),
|
||||
chart_properties.get_function_color(function_index), chart_properties.point_radius, true
|
||||
)
|
||||
draw_line(
|
||||
point.position + (Vector2(1, -1) * chart_properties.point_radius),
|
||||
point.position + (Vector2(-1, 1) * chart_properties.point_radius),
|
||||
chart_properties.get_function_color(function_index), chart_properties.point_radius / 2, true
|
||||
)
|
||||
|
||||
# # (debug)
|
||||
# draw_rect(
|
||||
# _get_point_box(point, _point_box_rad),
|
||||
# Color.red,
|
||||
# false, 1, true
|
||||
# )
|
||||
|
||||
func _draw_points() -> void:
|
||||
for function in function_points.size():
|
||||
for point in function_points[function]:
|
||||
_draw_point(point, function)
|
||||
|
||||
func _calculate_points() -> void:
|
||||
var validation: int = _validate_sampled_axis(x_sampled, y_sampled)
|
||||
if not validation == OK:
|
||||
printerr("Cannot plot points for invalid dataset! Error: %s" % validation)
|
||||
return
|
||||
|
||||
if y_sampled.values[0] is Array:
|
||||
for yxi in y_sampled.values.size():
|
||||
var _function_points: Array = []
|
||||
for i in y_sampled.values[yxi].size():
|
||||
var real_point_val: Pair = Pair.new(x[i], y[yxi][i])
|
||||
var sampled_point_pos: Vector2 = Vector2(x_sampled.values[i], y_sampled.values[yxi][i])
|
||||
var point: Point = Point.new(sampled_point_pos, real_point_val)
|
||||
_function_points.append(point)
|
||||
points.append(point)
|
||||
function_points.append(_function_points)
|
||||
else:
|
||||
for i in y_sampled.values.size():
|
||||
var real_point_val: Pair = Pair.new(x[i], y[i])
|
||||
var sampled_point_pos: Vector2 = Vector2(x_sampled.values[i], y_sampled.values[i])
|
||||
var point: Point = Point.new(sampled_point_pos, real_point_val)
|
||||
points.append(point)
|
||||
function_points.append(points)
|
||||
|
||||
func _draw() -> void:
|
||||
_calculate_points()
|
||||
|
||||
if chart_properties.points:
|
||||
_draw_points()
|
@ -0,0 +1,7 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://addons/easy_charts/control_charts/ScatterChart/scatter_chart.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/easy_charts/control_charts/chart.tscn" type="PackedScene" id=2]
|
||||
|
||||
[node name="ScatterChart" instance=ExtResource( 2 )]
|
||||
script = ExtResource( 1 )
|
503
game/addons/easy_charts/control_charts/chart.gd
Normal file
503
game/addons/easy_charts/control_charts/chart.gd
Normal file
@ -0,0 +1,503 @@
|
||||
extends Control
|
||||
class_name Chart
|
||||
|
||||
var x: Array
|
||||
var y: Array
|
||||
|
||||
var x_min_max: Pair = Pair.new() # Min and Max values of @x
|
||||
var x_domain: Pair = Pair.new() # Rounded domain of values of @x
|
||||
var y_min_max: Pair = Pair.new() # Min and Max values of @y
|
||||
var y_domain: Pair = Pair.new() # Rounded domain of values of @x
|
||||
|
||||
var x_sampled: SampledAxis = SampledAxis.new()
|
||||
var y_sampled: SampledAxis = SampledAxis.new()
|
||||
|
||||
var x_labels: Array = []
|
||||
var y_labels: Array = []
|
||||
var functions_names: Array = []
|
||||
|
||||
###### STYLE
|
||||
var chart_properties: ChartProperties = ChartProperties.new()
|
||||
|
||||
#### INTERNAL
|
||||
# The bounding_box of the chart
|
||||
var node_box: Rect2
|
||||
var bounding_box: Rect2
|
||||
var plot_offset: Vector2
|
||||
var plot_box: Rect2
|
||||
|
||||
# The Reference Rectangle to plot samples
|
||||
# It is the @bounding_box Rectangle inverted on the Y axis
|
||||
var x_sampled_domain: Pair
|
||||
var y_sampled_domain: Pair
|
||||
|
||||
var _padding_offset: Vector2 = Vector2(20.0, 20.0)
|
||||
var _internal_offset: Vector2 = Vector2(15.0, 15.0)
|
||||
|
||||
var y_has_decimals: bool
|
||||
var _y_label_size: Vector2 = Vector2.ZERO # offset only on the X axis
|
||||
var _y_label_offset: int = 15 # offset only on the X axis
|
||||
var _y_ticklabel_size: Vector2 # offset only on the X axis
|
||||
var _y_ticklabel_offset: int = 5 # offset only on the X axis
|
||||
var _y_tick_size: int = 7
|
||||
|
||||
var x_has_decimals: bool
|
||||
var _x_label_size: Vector2 = Vector2.ZERO # offset only on the X axis
|
||||
var _x_label_offset: int = 15 # offset only on the X axis
|
||||
var _x_ticklabel_size: Vector2 # offset only on the X axis
|
||||
var _x_ticklabel_offset: int = 5 # offset only on the X axis
|
||||
var _x_tick_size: int = 7
|
||||
|
||||
###########
|
||||
func _ready() -> void:
|
||||
set_process_input(false)
|
||||
set_process(false)
|
||||
|
||||
func validate_input_samples(samples: Array) -> bool:
|
||||
if samples.size() > 1 and samples[0] is Array:
|
||||
for sample in samples:
|
||||
if (not sample is Array) or sample.size() != samples[0].size():
|
||||
return false
|
||||
return true
|
||||
|
||||
func plot(x: Array, y: Array, properties: ChartProperties = self.chart_properties) -> void:
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
if properties != null:
|
||||
self.chart_properties = properties
|
||||
|
||||
set_process_input(chart_properties.interactive)
|
||||
|
||||
update()
|
||||
|
||||
func _map_pair(val: float, rel: Pair, ref: Pair) -> float:
|
||||
return range_lerp(val, rel.left, rel.right, ref.left, ref.right)
|
||||
|
||||
func _has_decimals(values: Array) -> bool:
|
||||
var temp: Array = values.duplicate(true)
|
||||
|
||||
if temp[0] is Array:
|
||||
for dim in temp:
|
||||
for val in dim:
|
||||
if val is String:
|
||||
return false
|
||||
if abs(fmod(val, 1)) > 0.0:
|
||||
return true
|
||||
else:
|
||||
for val in temp:
|
||||
if val is String:
|
||||
return false
|
||||
if abs(fmod(val, 1)) > 0.0:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
func _find_min_max(values: Array) -> Pair:
|
||||
var temp: Array = values.duplicate(true)
|
||||
var _min: float
|
||||
var _max: float
|
||||
|
||||
if temp[0] is Array:
|
||||
var min_ts: Array
|
||||
var max_ts: Array
|
||||
for dim in temp:
|
||||
min_ts.append(dim.min())
|
||||
max_ts.append(dim.max())
|
||||
_min = min_ts.min()
|
||||
_max = max_ts.max()
|
||||
else:
|
||||
_min = temp.min()
|
||||
_max = temp.max()
|
||||
|
||||
return Pair.new(_min, _max)
|
||||
|
||||
func _sample_values(values: Array, rel_values: Pair, ref_values: Pair) -> SampledAxis:
|
||||
if values.empty():
|
||||
printerr("Trying to plot an empty dataset!")
|
||||
return SampledAxis.new()
|
||||
|
||||
if values[0] is Array:
|
||||
if values.size() > 1:
|
||||
for dim in values:
|
||||
if values[0].size() != dim.size():
|
||||
printerr("Cannot plot a dataset with dimensions of different size!")
|
||||
return SampledAxis.new()
|
||||
|
||||
var temp: Array = values.duplicate(true)
|
||||
|
||||
var rels: Array = []
|
||||
var division_size: float
|
||||
if temp[0] is Array:
|
||||
for t_dim in temp:
|
||||
var rels_t: Array = []
|
||||
for val in t_dim:
|
||||
rels_t.append(_map_pair(val, rel_values, ref_values))
|
||||
rels.append(rels_t)
|
||||
|
||||
else:
|
||||
division_size = (ref_values.right - ref_values.left) / values.size()
|
||||
for val_i in temp.size():
|
||||
if temp[val_i] is String:
|
||||
rels.append(val_i * division_size)
|
||||
else:
|
||||
rels.append(_map_pair(temp[val_i], rel_values, ref_values))
|
||||
|
||||
return SampledAxis.new(rels, rel_values)
|
||||
|
||||
func _round_min(val: float) -> float:
|
||||
return round(val) if abs(val) < 10 else floor(val / 10.0) * 10.0
|
||||
|
||||
func _round_max(val: float) -> float:
|
||||
return round(val) if abs(val) < 10 else ceil(val / 10.0) * 10.0
|
||||
|
||||
|
||||
func _calc_x_domain() -> void:
|
||||
x_min_max = _find_min_max(x)
|
||||
x_domain = Pair.new(_round_min(x_min_max.left), _round_max(x_min_max.right))
|
||||
|
||||
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 = _sample_values(x, x_min_max, x_sampled_domain)
|
||||
|
||||
func _calc_y_domain() -> void:
|
||||
y_min_max = _find_min_max(y)
|
||||
y_domain = Pair.new(_round_min(y_min_max.left), _round_max(y_min_max.right))
|
||||
|
||||
func _sample_y() -> void:
|
||||
### @sampled_domain, which are the domain relative to the sampled values
|
||||
### x (real value) --> sampling --> x_sampled (pixel value in canvas)
|
||||
y_sampled_domain = Pair.new(plot_box.end.y, plot_box.position.y)
|
||||
|
||||
# samples
|
||||
y_sampled = _sample_values(y, y_domain, y_sampled_domain)
|
||||
|
||||
|
||||
func _find_longest_x() -> String:
|
||||
return ("%.2f" if x_has_decimals else "%s") % x_domain.right
|
||||
|
||||
func _pre_process() -> void:
|
||||
_calc_x_domain()
|
||||
_calc_y_domain()
|
||||
|
||||
var frame: Rect2 = get_global_rect()
|
||||
|
||||
|
||||
#### @node_box size, which is the whole "frame"
|
||||
node_box = Rect2(Vector2.ZERO, frame.size - frame.position)
|
||||
|
||||
#### calculating offset from the @node_box for the @bounding_box.
|
||||
plot_offset = _padding_offset
|
||||
|
||||
### if @labels drawing is enabled, calcualte offsets
|
||||
if chart_properties.labels:
|
||||
### labels (X, Y, Title)
|
||||
_x_label_size = chart_properties.font.get_string_size(chart_properties.x_label)
|
||||
_y_label_size = chart_properties.font.get_string_size(chart_properties.y_label)
|
||||
|
||||
### tick labels
|
||||
|
||||
###### --- X
|
||||
x_has_decimals = _has_decimals(x)
|
||||
# calculate the string length of the largest value on the X axis.
|
||||
# remember that "-" sign adds additional pixels, and it is relative only to negative numbers!
|
||||
var x_max_formatted: String = _find_longest_x()
|
||||
_x_ticklabel_size = chart_properties.font.get_string_size(x_max_formatted)
|
||||
|
||||
plot_offset.y += _x_label_offset + _x_label_size.y + _x_ticklabel_offset + _x_ticklabel_size.y
|
||||
|
||||
###### --- Y
|
||||
y_has_decimals = _has_decimals(y)
|
||||
# calculate the string length of the largest value on the Y axis.
|
||||
# remember that "-" sign adds additional pixels, and it is relative only to negative numbers!
|
||||
var y_max_formatted: String = ("%.2f" if y_has_decimals else "%s") % y_domain.right
|
||||
if y_domain.left < 0:
|
||||
# negative number
|
||||
var y_min_formatted: String = ("%.2f" if y_has_decimals else "%s") % y_domain.left
|
||||
if y_min_formatted.length() >= y_max_formatted.length():
|
||||
_y_ticklabel_size = chart_properties.font.get_string_size(y_min_formatted)
|
||||
else:
|
||||
_y_ticklabel_size = chart_properties.font.get_string_size(y_max_formatted)
|
||||
else:
|
||||
_y_ticklabel_size = chart_properties.font.get_string_size(y_max_formatted)
|
||||
|
||||
plot_offset.x += _y_label_offset + _y_label_size.y + _y_ticklabel_offset + _y_ticklabel_size.x
|
||||
|
||||
### if @ticks drawing is enabled, calculate offsets
|
||||
if chart_properties.ticks:
|
||||
plot_offset.x += _y_tick_size
|
||||
plot_offset.y += _x_tick_size
|
||||
|
||||
### @bounding_box, where the points will be plotted
|
||||
bounding_box = Rect2(
|
||||
plot_offset,
|
||||
frame.size - (plot_offset * 2)
|
||||
)
|
||||
|
||||
plot_box = Rect2(
|
||||
bounding_box.position + _internal_offset,
|
||||
bounding_box.size - (_internal_offset * 2)
|
||||
)
|
||||
|
||||
_sample_x()
|
||||
_sample_y()
|
||||
|
||||
func _draw_borders() -> void:
|
||||
draw_rect(node_box, Color.red, false, 1, true)
|
||||
|
||||
func _draw_bounding_box() -> void:
|
||||
draw_rect(bounding_box, chart_properties.colors.bounding_box, false, 1, true)
|
||||
|
||||
# # (debug)
|
||||
# var half: Vector2 = (bounding_box.size) / 2
|
||||
# draw_line(bounding_box.position + Vector2(half.x, 0), bounding_box.position + Vector2(half.x, bounding_box.size.y), Color.red, 3, false)
|
||||
# draw_line(bounding_box.position + Vector2(0, half.y), bounding_box.position + Vector2(bounding_box.size.x, half.y), Color.red, 3, false)
|
||||
|
||||
func _draw_origin() -> void:
|
||||
var xorigin: float = _map_pair(0.0, x_min_max, x_sampled_domain)
|
||||
var yorigin: float = _map_pair(0.0, y_domain, y_sampled_domain)
|
||||
draw_line(Vector2(xorigin, bounding_box.position.y), Vector2(xorigin, bounding_box.position.y + bounding_box.size.y), Color.black, 1, 0)
|
||||
draw_line(Vector2(bounding_box.position.x, yorigin), Vector2(bounding_box.position.x + bounding_box.size.x, yorigin), Color.black, 1, 0)
|
||||
draw_string(chart_properties.font, Vector2(xorigin, yorigin) - Vector2(15, -15), "O", chart_properties.colors.bounding_box)
|
||||
|
||||
func _draw_background() -> void:
|
||||
draw_rect(node_box, Color.white, true, 1.0, false)
|
||||
|
||||
# # (debug)
|
||||
# var half: Vector2 = node_box.size / 2
|
||||
# draw_line(Vector2(half.x, node_box.position.y), Vector2(half.x, node_box.size.y), Color.red, 3, false)
|
||||
# draw_line(Vector2(node_box.position.x, half.y), Vector2(node_box.size.x, half.y), Color.red, 3, false)
|
||||
|
||||
func _draw_tick(from: Vector2, to: Vector2, color: Color) -> void:
|
||||
draw_line(from, to, color, 1, true)
|
||||
|
||||
|
||||
func _get_vertical_tick_label_pos(base_position: Vector2, text: String) -> Vector2:
|
||||
return base_position + Vector2(
|
||||
- chart_properties.font.get_string_size(text).x / 2,
|
||||
_x_label_size.y + _x_tick_size
|
||||
)
|
||||
|
||||
func _get_tick_label(line_index: int, line_value: float) -> String:
|
||||
var tick_lbl: String = ""
|
||||
if x_labels.empty():
|
||||
tick_lbl = ("%.2f" if x_has_decimals else "%s") % [x_min_max.left + (line_index * line_value)]
|
||||
else:
|
||||
tick_lbl = x_labels[clamp(line_value * line_index, 0, x_labels.size() - 1)]
|
||||
|
||||
return tick_lbl
|
||||
|
||||
func _draw_vertical_gridline_component(p1: Vector2, p2: Vector2, line_index: int, line_value: float) -> void:
|
||||
if chart_properties.labels:
|
||||
var tick_lbl: String = _get_tick_label(line_index, line_value)
|
||||
draw_string(
|
||||
chart_properties.font,
|
||||
_get_vertical_tick_label_pos(p2, tick_lbl),
|
||||
tick_lbl,
|
||||
chart_properties.colors.bounding_box
|
||||
)
|
||||
|
||||
# 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 _draw_horizontal_tick_label(font: Font, position: Vector2, color: Color, line_index: int, line_value: float) -> void:
|
||||
var tick_lbl: String = ""
|
||||
if y_labels.empty():
|
||||
tick_lbl = ("%.2f" if y_has_decimals else "%s") % [y_domain.left + (line_index * line_value)]
|
||||
else:
|
||||
tick_lbl = y_labels[clamp(y_labels.size() * line_index, 0, y_labels.size() - 1)]
|
||||
|
||||
draw_string(
|
||||
chart_properties.font,
|
||||
position - Vector2(
|
||||
chart_properties.font.get_string_size(tick_lbl).x + _y_ticklabel_offset + _y_tick_size,
|
||||
- _y_ticklabel_size.y * 0.35
|
||||
),
|
||||
tick_lbl,
|
||||
chart_properties.colors.bounding_box
|
||||
)
|
||||
|
||||
|
||||
func _draw_horizontal_gridline_component(p1: Vector2, p2: Vector2, line_index: int, line_value: float) -> void:
|
||||
# Draw H labels
|
||||
if chart_properties.labels:
|
||||
_draw_horizontal_tick_label(
|
||||
chart_properties.font,
|
||||
p1,
|
||||
chart_properties.colors.bounding_box,
|
||||
line_index,
|
||||
line_value
|
||||
)
|
||||
|
||||
# Draw H Ticks
|
||||
if chart_properties.ticks:
|
||||
_draw_tick(p1, p1 - Vector2(_y_tick_size, 0), chart_properties.colors.bounding_box)
|
||||
|
||||
# Draw H Grid Lines
|
||||
if chart_properties.grid:
|
||||
draw_line(p1, p2, chart_properties.colors.grid, 1, true)
|
||||
|
||||
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.
|
||||
var x_pixel_dist: float = (x_sampled.min_max.right - x_sampled.min_max.left) / (chart_properties.x_scale)
|
||||
var x_lbl_val: float = (x_min_max.right - x_min_max.left) / (chart_properties.x_scale)
|
||||
for _x in chart_properties.x_scale + 1:
|
||||
var x_val: float = _x * x_pixel_dist + x_sampled.min_max.left
|
||||
var top: Vector2 = Vector2(
|
||||
range_lerp(x_val, x_sampled.min_max.left, x_sampled.min_max.right, x_sampled_domain.left, x_sampled_domain.right),
|
||||
bounding_box.position.y
|
||||
)
|
||||
var bottom: Vector2 = Vector2(
|
||||
range_lerp(x_val, x_sampled.min_max.left, x_sampled.min_max.right, x_sampled_domain.left, x_sampled_domain.right),
|
||||
bounding_box.size.y + bounding_box.position.y
|
||||
)
|
||||
|
||||
_draw_vertical_gridline_component(top, bottom, _x, x_lbl_val)
|
||||
|
||||
func _draw_horizontal_grid() -> void:
|
||||
# 1. the amount of lines is equals to the y_scale: it identifies in how many sectors the y domain
|
||||
# should be devided
|
||||
# 2. calculate the spacing between each line in pixel. It is equals to y_sampled_domain / y_scale
|
||||
# 3. calculate the offset in the real y domain, which is y_domain / y_scale.
|
||||
var y_pixel_dist: float = (y_sampled.min_max.right - y_sampled.min_max.left) / (chart_properties.y_scale)
|
||||
var y_lbl_val: float = (y_domain.right - y_domain.left) / (chart_properties.y_scale)
|
||||
for _y in chart_properties.y_scale + 1:
|
||||
var y_val: float = (_y * y_pixel_dist) + y_sampled.min_max.left
|
||||
var left: Vector2 = Vector2(
|
||||
bounding_box.position.x,
|
||||
range_lerp(y_val, y_sampled.min_max.left, y_sampled.min_max.right, y_sampled_domain.left, y_sampled_domain.right)
|
||||
)
|
||||
var right: Vector2 = Vector2(
|
||||
bounding_box.size.x + bounding_box.position.x,
|
||||
range_lerp(y_val, y_sampled.min_max.left, y_sampled.min_max.right, y_sampled_domain.left, y_sampled_domain.right)
|
||||
)
|
||||
|
||||
_draw_horizontal_gridline_component(left, right, _y, y_lbl_val)
|
||||
|
||||
func _draw_grid() -> void:
|
||||
var validation: int = _validate_sampled_axis(x_sampled, y_sampled)
|
||||
if not validation == OK:
|
||||
printerr("Cannot draw grid for invalid dataset! Error: %s" % validation)
|
||||
return
|
||||
|
||||
_draw_vertical_grid()
|
||||
_draw_horizontal_grid()
|
||||
|
||||
func _create_canvas_label(text: String, position: Vector2, rotation: float = 0.0) -> Label:
|
||||
var lbl: Label = Label.new()
|
||||
$Canvas.add_child(lbl)
|
||||
lbl.set("custom_fonts/font", chart_properties.font)
|
||||
lbl.set_text(text)
|
||||
lbl.modulate = chart_properties.colors.bounding_box
|
||||
lbl.rect_rotation = rotation
|
||||
lbl.rect_position = position
|
||||
return lbl
|
||||
|
||||
func _update_canvas_label(canvas_label: Label, text: String, position: Vector2, rotation: float = 0.0) -> void:
|
||||
canvas_label.set_text(text)
|
||||
canvas_label.modulate = chart_properties.colors.bounding_box
|
||||
canvas_label.rect_rotation = rotation
|
||||
canvas_label.rect_position = position
|
||||
|
||||
func _draw_yaxis_label() -> void:
|
||||
_update_canvas_label(
|
||||
$Canvas/YLabel,
|
||||
chart_properties.y_label,
|
||||
Vector2(_padding_offset.x, (node_box.size.y / 2) + (_y_label_size.x / 2)),
|
||||
-90
|
||||
)
|
||||
|
||||
func _draw_xaxis_label() -> void:
|
||||
_update_canvas_label(
|
||||
$Canvas/XLabel,
|
||||
chart_properties.x_label,
|
||||
Vector2(
|
||||
node_box.size.x/2 - (_x_label_size.x / 2),
|
||||
node_box.size.y - _padding_offset.y - _x_label_size.y
|
||||
)
|
||||
)
|
||||
|
||||
func _draw_title() -> void:
|
||||
_update_canvas_label(
|
||||
$Canvas/Title,
|
||||
chart_properties.title,
|
||||
Vector2(node_box.size.x / 2, _padding_offset.y*2) - (chart_properties.font.get_string_size(chart_properties.title) / 2)
|
||||
)
|
||||
|
||||
func _clear_canvas_labels() -> void:
|
||||
for label in $Canvas.get_children():
|
||||
label.queue_free()
|
||||
|
||||
func _clear() -> void:
|
||||
_clear_canvas_labels()
|
||||
|
||||
# Draw Loop:
|
||||
# the drow loop gives order to what thigs will be drawn
|
||||
# each chart specifies its own draw loop that inherits from this one.
|
||||
# The draw loop also contains the "processing loop" which is where
|
||||
# everything is calculated in a separated function.
|
||||
func _draw():
|
||||
if not (validate_input_samples(x) and validate_input_samples(y)):
|
||||
printerr("Input samples are invalid!")
|
||||
return
|
||||
|
||||
_clear()
|
||||
_pre_process()
|
||||
|
||||
if chart_properties.background:
|
||||
_draw_background()
|
||||
|
||||
if chart_properties.borders:
|
||||
_draw_borders()
|
||||
|
||||
if chart_properties.grid or chart_properties.ticks or chart_properties.labels:
|
||||
_draw_grid()
|
||||
|
||||
if chart_properties.bounding_box:
|
||||
_draw_bounding_box()
|
||||
|
||||
if chart_properties.origin:
|
||||
_draw_origin()
|
||||
|
||||
if chart_properties.labels:
|
||||
_draw_xaxis_label()
|
||||
_draw_yaxis_label()
|
||||
_draw_title()
|
||||
|
||||
func _validate_sampled_axis(x_data: SampledAxis, y_data: SampledAxis) -> int:
|
||||
var error: int = 0 # OK
|
||||
if x_data.values.empty() or y_data.values.empty():
|
||||
# Either there are no X or Y
|
||||
error = 1
|
||||
elif y_data.values[0] is Array:
|
||||
for dim in y_data.values:
|
||||
if dim.size() != x_data.values.size():
|
||||
error = 3 # one of Y dim has not X length
|
||||
break
|
||||
else:
|
||||
if y_data.values.size() != x_data.values.size():
|
||||
# X and Y samples don't have same length
|
||||
error = 2
|
||||
return error
|
||||
|
||||
# ----- utilities
|
||||
func _get_function_name(function_idx: int) -> String:
|
||||
return functions_names[function_idx] if functions_names.size() > 0 else "Function %s" % function_idx
|
||||
|
||||
func _get_function_color(function_idx: int) -> Color:
|
||||
return chart_properties.colors.functions[function_idx] if chart_properties.colors.functions.size() > 0 else Color.black
|
30
game/addons/easy_charts/control_charts/chart.tscn
Normal file
30
game/addons/easy_charts/control_charts/chart.tscn
Normal file
@ -0,0 +1,30 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://addons/easy_charts/control_charts/chart.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/easy_charts/utilities/containers/data_tooltip/data_tooltip.tscn" type="PackedScene" id=2]
|
||||
|
||||
[node name="Chart" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Canvas" type="Control" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="Title" type="Label" parent="Canvas"]
|
||||
margin_right = 40.0
|
||||
margin_bottom = 14.0
|
||||
|
||||
[node name="XLabel" type="Label" parent="Canvas"]
|
||||
margin_right = 40.0
|
||||
margin_bottom = 14.0
|
||||
|
||||
[node name="YLabel" type="Label" parent="Canvas"]
|
||||
margin_right = 40.0
|
||||
margin_bottom = 14.0
|
||||
|
||||
[node name="Tooltip" parent="." instance=ExtResource( 2 )]
|
||||
visible = false
|
||||
margin_right = 20.0
|
||||
margin_bottom = 16.0
|
50
game/addons/easy_charts/examples/bar_chart/Control.gd
Normal file
50
game/addons/easy_charts/examples/bar_chart/Control.gd
Normal file
@ -0,0 +1,50 @@
|
||||
extends Control
|
||||
|
||||
onready var chart: BarChart = $BarChart
|
||||
|
||||
func _ready():
|
||||
# Let's create our @x values
|
||||
var x: Array = ["Day 1", "Day 2", "Day 3", "Day 4", "Day 5"]
|
||||
# And our y values. It can be an n-size array of arrays.
|
||||
# NOTE: `x.size() == y.size()` or `x.size() == y[n].size()`
|
||||
var y: Array = [
|
||||
20, 10, -15, 30, 42
|
||||
]
|
||||
|
||||
# Add some labels for the x axis, we don't want to use our x values array
|
||||
# they will be printed on the chart ticks instead of the value of the x axis.
|
||||
var x_labels: Array = ArrayOperations.suffix(x, "s")
|
||||
|
||||
# Let's customize the chart properties, which specify how the chart
|
||||
# should look, plus some additional elements like labels, the scale, etc...
|
||||
var cp: ChartProperties = ChartProperties.new()
|
||||
cp.grid = true
|
||||
cp.title = "Air Quality Monitoring"
|
||||
cp.x_label = ("Days")
|
||||
cp.x_scale = 20
|
||||
cp.y_label = ("Sensor values")
|
||||
cp.y_scale = 10
|
||||
cp.points = false
|
||||
cp.interactive = true # false by default, it allows the chart to create a tooltip to show point values
|
||||
# and interecept clicks on the plot
|
||||
|
||||
# Set the x_labels
|
||||
# $LineChart.x_labels = x_labels
|
||||
|
||||
# Plot our data
|
||||
chart.plot(x, y, cp)
|
||||
|
||||
# Uncommenting this line will show how real time data plotting works
|
||||
set_process(false)
|
||||
|
||||
func _process(delta: float):
|
||||
# This function updates the values of chart x, y, and x_labels array
|
||||
# and updaptes the plot
|
||||
var new_val: String = "Day %s" % (chart.x.size() + 1)
|
||||
chart.x.append(new_val)
|
||||
chart.y.append(randi() % 40)
|
||||
chart.update()
|
||||
|
||||
|
||||
func _on_CheckButton_pressed():
|
||||
set_process(not is_processing())
|
49
game/addons/easy_charts/examples/bar_chart/Control.tscn
Normal file
49
game/addons/easy_charts/examples/bar_chart/Control.tscn
Normal file
@ -0,0 +1,49 @@
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://addons/easy_charts/control_charts/BarChart/bar_chart.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://addons/easy_charts/examples/bar_chart/Control.gd" type="Script" id=2]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id=1]
|
||||
content_margin_right = 5.0
|
||||
content_margin_bottom = 5.0
|
||||
draw_center = false
|
||||
border_width_right = 2
|
||||
border_width_bottom = 2
|
||||
border_color = Color( 0, 0, 0, 1 )
|
||||
|
||||
[node name="Control" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": true
|
||||
}
|
||||
|
||||
[node name="BarChart" parent="." instance=ExtResource( 1 )]
|
||||
|
||||
[node name="CheckButton" type="CheckButton" parent="."]
|
||||
margin_right = 223.0
|
||||
margin_bottom = 40.0
|
||||
custom_colors/font_color = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_pressed = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_hover = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_hover_pressed = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_focus = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_disabled = Color( 0, 0, 0, 1 )
|
||||
text = "Start Relatime Plotting"
|
||||
|
||||
[node name="Label" type="Label" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -159.0
|
||||
margin_top = -19.0
|
||||
custom_colors/font_color = Color( 0, 0, 0, 1 )
|
||||
custom_styles/normal = SubResource( 1 )
|
||||
text = "Try to scale the window!"
|
||||
__meta__ = {
|
||||
"_edit_lock_": true
|
||||
}
|
||||
|
||||
[connection signal="pressed" from="CheckButton" to="." method="_on_CheckButton_pressed"]
|
55
game/addons/easy_charts/examples/line_chart/Control.gd
Normal file
55
game/addons/easy_charts/examples/line_chart/Control.gd
Normal file
@ -0,0 +1,55 @@
|
||||
extends Control
|
||||
|
||||
func _ready():
|
||||
# Let's create our @x values
|
||||
var x: Array = ArrayOperations.multiply_float(range(-2*PI, +2*PI, 1), 0.5)
|
||||
# And our y values. It can be an n-size array of arrays.
|
||||
# NOTE: `x.size() == y.size()` or `x.size() == y[n].size()`
|
||||
var y: Array = [
|
||||
ArrayOperations.multiply_float(ArrayOperations.cos(x), 1.0),
|
||||
ArrayOperations.multiply_float(ArrayOperations.sin(x), 1.0)
|
||||
]
|
||||
|
||||
# Add some labels for the x axis, we don't want to use our x values array
|
||||
# they will be printed on the chart ticks instead of the value of the x axis.
|
||||
var x_labels: Array = ArrayOperations.suffix(x, "s")
|
||||
|
||||
# Let's customize the chart properties, which specify how the chart
|
||||
# should look, plus some additional elements like labels, the scale, etc...
|
||||
var cp: ChartProperties = ChartProperties.new()
|
||||
cp.grid = false
|
||||
cp.origin = true
|
||||
cp.title = "Air Quality Monitoring"
|
||||
cp.x_label = ("Time")
|
||||
cp.x_scale = 10
|
||||
cp.y_label = ("Sensor values")
|
||||
cp.y_scale = 10
|
||||
cp.points = true
|
||||
cp.line_width = 2.0
|
||||
cp.point_radius = 2.5
|
||||
cp.use_splines = true
|
||||
cp.interactive = false # false by default, it allows the chart to create a tooltip to show point values
|
||||
# and interecept clicks on the plot
|
||||
|
||||
# Set the x_labels
|
||||
# $LineChart.x_labels = x_labels
|
||||
|
||||
# Plot our data
|
||||
$LineChart.plot(x, y, cp)
|
||||
|
||||
# Uncommenting this line will show how real time data plotting works
|
||||
set_process(false)
|
||||
|
||||
func _process(delta: float):
|
||||
# This function updates the values of chart x, y, and x_labels array
|
||||
# and updaptes the plot
|
||||
var new_val: float = $LineChart.x.back() + 1
|
||||
$LineChart.x.append(new_val)
|
||||
$LineChart.y[0].append(cos(new_val))
|
||||
$LineChart.y[1].append(2 + sin(new_val))
|
||||
$LineChart.x_labels.append(str(new_val) + "s")
|
||||
$LineChart.update()
|
||||
|
||||
|
||||
func _on_CheckButton_pressed():
|
||||
set_process(not is_processing())
|
49
game/addons/easy_charts/examples/line_chart/Control.tscn
Normal file
49
game/addons/easy_charts/examples/line_chart/Control.tscn
Normal file
@ -0,0 +1,49 @@
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://addons/easy_charts/control_charts/LineChart/line_chart.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://addons/easy_charts/examples/line_chart/Control.gd" type="Script" id=2]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id=1]
|
||||
content_margin_right = 5.0
|
||||
content_margin_bottom = 5.0
|
||||
draw_center = false
|
||||
border_width_right = 2
|
||||
border_width_bottom = 2
|
||||
border_color = Color( 0, 0, 0, 1 )
|
||||
|
||||
[node name="Control" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": true
|
||||
}
|
||||
|
||||
[node name="LineChart" parent="." instance=ExtResource( 1 )]
|
||||
|
||||
[node name="CheckButton" type="CheckButton" parent="."]
|
||||
margin_right = 223.0
|
||||
margin_bottom = 40.0
|
||||
custom_colors/font_color = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_pressed = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_hover = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_hover_pressed = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_focus = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_disabled = Color( 0, 0, 0, 1 )
|
||||
text = "Start Relatime Plotting"
|
||||
|
||||
[node name="Label" type="Label" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -159.0
|
||||
margin_top = -19.0
|
||||
custom_colors/font_color = Color( 0, 0, 0, 1 )
|
||||
custom_styles/normal = SubResource( 1 )
|
||||
text = "Try to scale the window!"
|
||||
__meta__ = {
|
||||
"_edit_lock_": true
|
||||
}
|
||||
|
||||
[connection signal="pressed" from="CheckButton" to="." method="_on_CheckButton_pressed"]
|
50
game/addons/easy_charts/examples/scatter_chart/Control.gd
Normal file
50
game/addons/easy_charts/examples/scatter_chart/Control.gd
Normal file
@ -0,0 +1,50 @@
|
||||
extends Control
|
||||
|
||||
func _ready():
|
||||
# Let's create our @x values
|
||||
var x: Array = ArrayOperations.multiply_float(range(-10, 10, 1), 0.5)
|
||||
# And our y values. It can be an n-size array of arrays.
|
||||
# NOTE: `x.size() == y.size()` or `x.size() == y[n].size()`
|
||||
var y: Array = [
|
||||
ArrayOperations.multiply_int(ArrayOperations.cos(x), 20),
|
||||
ArrayOperations.add_float(ArrayOperations.multiply_int(ArrayOperations.sin(x), 20), 20)
|
||||
]
|
||||
# Add some labels for the x axis, we don't want to use our x values array
|
||||
# they will be printed on the chart ticks instead of the value of the x axis.
|
||||
var x_labels: Array = ArrayOperations.suffix(x, "s")
|
||||
|
||||
# Let's customize the chart properties, which specify how the chart
|
||||
# should look, plus some additional elements like labels, the scale, etc...
|
||||
var cp: ChartProperties = ChartProperties.new()
|
||||
cp.grid = true
|
||||
cp.origin = false
|
||||
cp.title = "Air Quality Monitoring"
|
||||
cp.x_label = ("Time")
|
||||
cp.x_scale = 10
|
||||
cp.y_label = ("Sensor values")
|
||||
cp.y_scale = 30
|
||||
cp.interactive = true # false by default, it allows the chart to create a tooltip to show point values
|
||||
# and interecept clicks on the plot
|
||||
|
||||
# Set the x_labels
|
||||
# $ScatterChart.x_labels = x_labels
|
||||
|
||||
# Plot our data
|
||||
$ScatterChart.plot(x, y, cp)
|
||||
|
||||
# Uncommenting this line will show how real time data plotting works
|
||||
set_process(false)
|
||||
|
||||
func _process(delta: float):
|
||||
# This function updates the values of chart x, y, and x_labels array
|
||||
# and updaptes the plot
|
||||
var new_val: float = $ScatterChart.x.back() + 1
|
||||
$ScatterChart.x.append(new_val)
|
||||
$ScatterChart.y[0].append(cos(new_val) * 20)
|
||||
$ScatterChart.y[1].append(20 + sin(new_val) * 20)
|
||||
$ScatterChart.x_labels.append(str(new_val) + "s")
|
||||
$ScatterChart.update()
|
||||
|
||||
|
||||
func _on_CheckButton_pressed():
|
||||
set_process(not is_processing())
|
49
game/addons/easy_charts/examples/scatter_chart/Control.tscn
Normal file
49
game/addons/easy_charts/examples/scatter_chart/Control.tscn
Normal file
@ -0,0 +1,49 @@
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://addons/easy_charts/control_charts/ScatterChart/scatter_chart.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://addons/easy_charts/examples/scatter_chart/Control.gd" type="Script" id=2]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id=1]
|
||||
content_margin_right = 5.0
|
||||
content_margin_bottom = 5.0
|
||||
draw_center = false
|
||||
border_width_right = 2
|
||||
border_width_bottom = 2
|
||||
border_color = Color( 0, 0, 0, 1 )
|
||||
|
||||
[node name="Control" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": true
|
||||
}
|
||||
|
||||
[node name="ScatterChart" parent="." instance=ExtResource( 1 )]
|
||||
|
||||
[node name="CheckButton" type="CheckButton" parent="."]
|
||||
margin_right = 223.0
|
||||
margin_bottom = 40.0
|
||||
custom_colors/font_color = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_pressed = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_hover = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_hover_pressed = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_focus = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_disabled = Color( 0, 0, 0, 1 )
|
||||
text = "Start Relatime Plotting"
|
||||
|
||||
[node name="Label" type="Label" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -159.0
|
||||
margin_top = -19.0
|
||||
custom_colors/font_color = Color( 0, 0, 0, 1 )
|
||||
custom_styles/normal = SubResource( 1 )
|
||||
text = "Try to scale the window!"
|
||||
__meta__ = {
|
||||
"_edit_lock_": true
|
||||
}
|
||||
|
||||
[connection signal="pressed" from="CheckButton" to="." method="_on_CheckButton_pressed"]
|
BIN
game/addons/easy_charts/icon.png
Normal file
BIN
game/addons/easy_charts/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 68 KiB |
35
game/addons/easy_charts/icon.png.import
Normal file
35
game/addons/easy_charts/icon.png.import
Normal file
@ -0,0 +1,35 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/icon.png-85017c6eecaf83ace12c82c530e61e9d.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/easy_charts/icon.png"
|
||||
dest_files=[ "res://.import/icon.png-85017c6eecaf83ace12c82c530e61e9d.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
7
game/addons/easy_charts/plugin.cfg
Normal file
7
game/addons/easy_charts/plugin.cfg
Normal file
@ -0,0 +1,7 @@
|
||||
[plugin]
|
||||
|
||||
name="EasyCharts"
|
||||
description=""
|
||||
author="Nicolò \"fenix\" Santilio"
|
||||
version="2.0.0"
|
||||
script="plugin.gd"
|
9
game/addons/easy_charts/plugin.gd
Normal file
9
game/addons/easy_charts/plugin.gd
Normal file
@ -0,0 +1,9 @@
|
||||
tool
|
||||
extends EditorPlugin
|
||||
|
||||
func _enter_tree():
|
||||
add_autoload_singleton("ECUtilities","res://addons/easy_charts/utilities/scripts/ec_utilities.gd")
|
||||
|
||||
func _exit_tree():
|
||||
remove_autoload_singleton("ECUtilities")
|
||||
|
44
game/addons/easy_charts/templates.json
Normal file
44
game/addons/easy_charts/templates.json
Normal file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"default":
|
||||
{
|
||||
"function_colors" : ["#1e1e1e","#1e1e1e","#1e1e1e","#1e1e1e"],
|
||||
"v_lines_color" : "#cacaca",
|
||||
"h_lines_color" : "#cacaca",
|
||||
"outline_color" : "#1e1e1e",
|
||||
"font_color" : "#1e1e1e"
|
||||
},
|
||||
"clean":
|
||||
{
|
||||
"function_colors" : ["#f7aa29","#f4394a","#5a6b7b","#8fbf59","#504538","#B7A99A","#00D795","#FFECCC","#FF8981"],
|
||||
"v_lines_color" : "#00000000",
|
||||
"h_lines_color" : "#3cffffff",
|
||||
"outline_color" : "#00000000",
|
||||
"font_color" : "#3cffffff"
|
||||
},
|
||||
"gradient":
|
||||
{
|
||||
"function_colors" : ["#F7AA29","#B8A806","#79A117","#2C9433","#00854C","#006571","#2F4858","#2a364f","#27294a"],
|
||||
"v_lines_color" : "#64ffffff",
|
||||
"h_lines_color" : "#64ffffff",
|
||||
"outline_color" : "#64ffffff",
|
||||
"font_color" : "#64ffffff",
|
||||
},
|
||||
"minimal":
|
||||
{
|
||||
"function_colors" : ["#1e1e1e","#1e1e1e","#1e1e1e","#1e1e1e"],
|
||||
"v_lines_color" : "#00000000",
|
||||
"h_lines_color" : "#00000000",
|
||||
"outline_color" : "#00000000",
|
||||
"font_color" : "#00000000"
|
||||
},
|
||||
"invert":
|
||||
{
|
||||
"function_colors" : ["#ffffff","#ffffff","#ffffff","#ffffff"],
|
||||
"v_lines_color" : "#3b3b3b",
|
||||
"h_lines_color" : "#3b3b3b",
|
||||
"outline_color" : "#ffffff",
|
||||
"font_color" : "#ffffff"
|
||||
},
|
||||
}
|
||||
|
||||
|
12
game/addons/easy_charts/utilities/classes/plotting/bar.gd
Normal file
12
game/addons/easy_charts/utilities/classes/plotting/bar.gd
Normal file
@ -0,0 +1,12 @@
|
||||
extends Reference
|
||||
class_name Bar
|
||||
|
||||
var rect: Rect2
|
||||
var value: Pair
|
||||
|
||||
func _init(rect: Rect2, value: Pair = Pair.new()) -> void:
|
||||
self.value = value
|
||||
self.rect = rect
|
||||
|
||||
func _to_string() -> String:
|
||||
return "Value: %s\nRect: %s" % [self.value, self.rect]
|
@ -0,0 +1,43 @@
|
||||
extends Reference
|
||||
class_name ChartProperties
|
||||
|
||||
var title: String
|
||||
var x_label: String
|
||||
var y_label: String
|
||||
|
||||
var x_scale: float = 5.0
|
||||
var y_scale: float = 2.0
|
||||
|
||||
# Scale type, 0 = linear | 1 = logarithmic
|
||||
var x_scale_type: int = 0
|
||||
var y_scale_type: int = 0
|
||||
|
||||
var borders: bool = false
|
||||
var background: bool = true
|
||||
var bounding_box: bool = true
|
||||
var grid: bool = false
|
||||
var ticks: bool = true
|
||||
var labels: bool = true
|
||||
var origin: bool = false
|
||||
var points: bool = true
|
||||
var interactive: bool = false
|
||||
|
||||
var use_splines: bool = false
|
||||
|
||||
var colors: Dictionary = {
|
||||
"bounding_box": Color.black,
|
||||
"grid": Color.gray,
|
||||
"functions": [Color.red, Color.green, Color.blue, Color.black]
|
||||
}
|
||||
|
||||
var point_radius: float = 3.0
|
||||
var line_width: float = 1.0
|
||||
var bar_width: float = 10.0
|
||||
var shapes: Array = [Point.Shape.CIRCLE, Point.Shape.SQUARE, Point.Shape.TRIANGLE, Point.Shape.CROSS]
|
||||
var font: BitmapFont = Label.new().get_theme_font("")
|
||||
|
||||
func get_function_color(function_index: int) -> Color:
|
||||
return colors.functions[function_index] if function_index < colors.functions.size() else Color.black
|
||||
|
||||
func get_point_shape(function_index: int) -> int:
|
||||
return shapes[function_index] if function_index < shapes.size() else Point.Shape.CIRCLE
|
20
game/addons/easy_charts/utilities/classes/plotting/point.gd
Normal file
20
game/addons/easy_charts/utilities/classes/plotting/point.gd
Normal file
@ -0,0 +1,20 @@
|
||||
tool
|
||||
extends Reference
|
||||
class_name Point
|
||||
|
||||
enum Shape {
|
||||
CIRCLE,
|
||||
TRIANGLE,
|
||||
SQUARE,
|
||||
CROSS
|
||||
}
|
||||
|
||||
var position: Vector2
|
||||
var value: Pair
|
||||
|
||||
func _init(position: Vector2, value: Pair = Pair.new()) -> void:
|
||||
self.value = value
|
||||
self.position = position
|
||||
|
||||
func _to_string() -> String:
|
||||
return "Value: %s\nPosition: %s" % [self.value, self.position]
|
@ -0,0 +1,13 @@
|
||||
extends Reference
|
||||
class_name SampledAxis
|
||||
|
||||
var values: Array
|
||||
var min_max: Pair
|
||||
|
||||
func _init(values: Array = [], min_max: Pair = Pair.new()) -> void:
|
||||
self.values = values
|
||||
self.min_max = min_max
|
||||
|
||||
func _to_string() -> String:
|
||||
return "values: %s\nmin: %s, max: %s" % [self.values, self.min_max.left, self.min_max.right]
|
||||
|
@ -0,0 +1,56 @@
|
||||
extends Reference
|
||||
class_name ArrayOperations
|
||||
|
||||
static func add_int(array: Array, _int: int) -> Array:
|
||||
var t: Array = array.duplicate(true)
|
||||
for ti in t.size():
|
||||
t[ti] = int(t[ti] + _int)
|
||||
return t
|
||||
|
||||
static func add_float(array: Array, _float: float) -> Array:
|
||||
var t: Array = array.duplicate(true)
|
||||
for ti in t.size():
|
||||
t[ti] = float(t[ti] + _float)
|
||||
return t
|
||||
|
||||
static func multiply_int(array: Array, _int: int) -> Array:
|
||||
var t: Array = array.duplicate(true)
|
||||
for ti in t.size():
|
||||
t[ti] = int(t[ti] * _int)
|
||||
return t
|
||||
|
||||
static func multiply_float(array: Array, _float: float) -> Array:
|
||||
var t: Array = array.duplicate(true)
|
||||
for ti in t.size():
|
||||
t[ti] = float(t[ti] * _float)
|
||||
return t
|
||||
|
||||
static func pow(array: Array, _int: int) -> Array:
|
||||
var t: Array = array.duplicate(true)
|
||||
for ti in t.size():
|
||||
t[ti] = float(pow(t[ti], _int))
|
||||
return t
|
||||
|
||||
static func cos(array: Array) -> Array:
|
||||
var t: Array = array.duplicate(true)
|
||||
for val in array.size():
|
||||
t[val] = cos(t[val])
|
||||
return t
|
||||
|
||||
static func sin(array: Array) -> Array:
|
||||
var t: Array = array.duplicate(true)
|
||||
for val in array.size():
|
||||
t[val] = sin(t[val])
|
||||
return t
|
||||
|
||||
static func affix(array: Array, _string: String) -> Array:
|
||||
var t: Array = array.duplicate(true)
|
||||
for val in array.size():
|
||||
t[val] = str(t[val]) + _string
|
||||
return t
|
||||
|
||||
static func suffix(array: Array, _string: String) -> Array:
|
||||
var t: Array = array.duplicate(true)
|
||||
for val in array.size():
|
||||
t[val] = _string + str(t[val])
|
||||
return t
|
@ -0,0 +1,191 @@
|
||||
tool
|
||||
extends Resource
|
||||
class_name DataFrame
|
||||
|
||||
var table_name : String = ""
|
||||
var labels : PoolStringArray = []
|
||||
var headers : PoolStringArray = []
|
||||
var datamatrix : Matrix = null
|
||||
var dataset : Array = []
|
||||
|
||||
func _init(datamatrix : Matrix, headers : PoolStringArray = [], labels : PoolStringArray = [] , table_name : String = "") -> void:
|
||||
if datamatrix.empty(): datamatrix.resize(labels.size(), headers.size())
|
||||
if labels.empty() : for label in range(datamatrix.get_size().x) : labels.append(label as String)
|
||||
if headers.empty() : for header in range(datamatrix.get_size().y) : headers.append(MatrixGenerator.get_letter_index(header))
|
||||
build_dataframe(datamatrix, headers, labels, table_name)
|
||||
|
||||
func build_dataframe(datamatrix : Matrix, headers : PoolStringArray = [], labels : PoolStringArray = [] , table_name : String = "") -> void:
|
||||
self.datamatrix = datamatrix
|
||||
self.headers = headers
|
||||
self.labels = labels
|
||||
self.table_name = table_name
|
||||
self.dataset = build_dataset_from_matrix(datamatrix, headers, labels)
|
||||
|
||||
func build_dataset_from_matrix(datamatrix : Matrix, headers : PoolStringArray, labels : PoolStringArray) -> Array:
|
||||
var data : Array = datamatrix.to_array()
|
||||
return build_dataset(data, headers, labels)
|
||||
|
||||
func build_dataset(data : Array, headers : PoolStringArray, labels : PoolStringArray) -> Array:
|
||||
var dataset : Array = [Array([" "]) + Array(headers)]
|
||||
for row_i in range(labels.size()): dataset.append(([labels[row_i]] + data[row_i]) if not data.empty() else [labels[row_i]])
|
||||
return dataset
|
||||
|
||||
func insert_column(column : Array, header : String = "", index : int = dataset[0].size() - 1) -> void:
|
||||
assert(column.size() == (datamatrix.rows() if not datamatrix.empty() else labels.size()), "error: the column size must match the dataset column size")
|
||||
headers.insert(index, header if header != "" else MatrixGenerator.get_letter_index(index))
|
||||
datamatrix.insert_column(column, index)
|
||||
dataset = build_dataset_from_matrix(datamatrix, headers, labels)
|
||||
|
||||
func insert_row(row : Array, label : String = "", index : int = dataset.size() - 1) -> PoolStringArray:
|
||||
assert(row.size() == (datamatrix.columns() if not datamatrix.empty() else headers.size()), "error: the row size must match the dataset row size")
|
||||
labels.insert(index, label if label != "" else str(index))
|
||||
datamatrix.insert_row(row, index)
|
||||
dataset = build_dataset_from_matrix(datamatrix, headers, labels)
|
||||
return PoolStringArray([label] + row)
|
||||
|
||||
func get_datamatrix() -> Matrix:
|
||||
return datamatrix
|
||||
|
||||
func get_dataset() -> Array:
|
||||
return dataset
|
||||
|
||||
func get_labels() -> PoolStringArray:
|
||||
return labels
|
||||
|
||||
func transpose():
|
||||
build_dataframe(MatrixGenerator.transpose(datamatrix), labels, headers, table_name)
|
||||
|
||||
func _to_string() -> String:
|
||||
var last_string_len : int
|
||||
for row in dataset:
|
||||
for column in row:
|
||||
var string_len : int = str(column).length()
|
||||
last_string_len = string_len if string_len > last_string_len else last_string_len
|
||||
var string : String = ""
|
||||
for row_i in dataset.size():
|
||||
for column_i in dataset[row_i].size():
|
||||
string+="%*s" % [last_string_len+1, dataset[row_i][column_i]]
|
||||
string+="\n"
|
||||
string+="\n['{table_name}' : {rows} rows x {columns} columns]\n".format({
|
||||
"rows": datamatrix.rows(),
|
||||
"columns": datamatrix.columns(),
|
||||
"table_name": table_name})
|
||||
return string
|
||||
|
||||
# ...............................................................................
|
||||
|
||||
# Return a list of headers corresponding to a list of indexes
|
||||
func get_headers_names(indexes : PoolIntArray) -> PoolStringArray:
|
||||
var headers : PoolStringArray = []
|
||||
for index in indexes:
|
||||
headers.append(dataset[0][index])
|
||||
return headers
|
||||
|
||||
# Returns the index of an header
|
||||
func get_column_index(header : String) -> int:
|
||||
for headers_ix in range(dataset[0].size()):
|
||||
if dataset[0][headers_ix] == header:
|
||||
return headers_ix
|
||||
return -1
|
||||
|
||||
# Get a column by its header
|
||||
func get_column(header : String) -> Array:
|
||||
var headers_i : int = get_column_index(header)
|
||||
if headers_i!=-1:
|
||||
return datamatrix.get_column(headers_i)
|
||||
else:
|
||||
return []
|
||||
|
||||
# Get a list of columns by their headers
|
||||
func columns(headers : PoolStringArray) -> Matrix:
|
||||
var values : Array = []
|
||||
for header in headers:
|
||||
values.append(get_column(header))
|
||||
return MatrixGenerator.transpose(Matrix.new(values))
|
||||
|
||||
|
||||
# Get a column by its index
|
||||
func get_icolumn(index : int) -> Array:
|
||||
return datamatrix.get_column(index)
|
||||
|
||||
# Get a list of columns by their indexes
|
||||
func get_icolumns(indexes : PoolIntArray) -> Array:
|
||||
var values : Array = []
|
||||
for index in indexes:
|
||||
values.append(datamatrix.get_column(index))
|
||||
return values
|
||||
|
||||
# Returns the list of labels corresponding to the list of indexes
|
||||
func get_labels_names(indexes : PoolIntArray) -> PoolStringArray:
|
||||
var headers : PoolStringArray = []
|
||||
for index in indexes:
|
||||
headers.append(dataset[index][0])
|
||||
return headers
|
||||
|
||||
# Returns the index of a label
|
||||
func get_row_index(label : String) -> int:
|
||||
for row in dataset.size():
|
||||
if dataset[row][0] == label:
|
||||
return row
|
||||
return -1
|
||||
|
||||
# Get a row by its label
|
||||
func get_row(label : String) -> Array:
|
||||
var index : int = get_row_index(label)
|
||||
if index == -1 :
|
||||
return []
|
||||
else:
|
||||
return datamatrix.get_row(index)
|
||||
|
||||
# Get a list of rows by their labels
|
||||
func rows(labels : Array) -> Matrix:
|
||||
var values : Array = []
|
||||
for label in labels:
|
||||
values.append(get_row(label))
|
||||
return Matrix.new(values)
|
||||
|
||||
# Get a row by its index
|
||||
func get_irow(index : int) -> Array:
|
||||
return datamatrix.get_row(index)
|
||||
|
||||
# Get a list of rows by their indexes
|
||||
func get_irows(indexes : PoolIntArray) -> Array:
|
||||
var values : Array = []
|
||||
for index in indexes:
|
||||
values.append(datamatrix.get_row(index))
|
||||
return values
|
||||
|
||||
# Returns a a group of rows or a group of columns, using indexes or names
|
||||
# dataset["0;5"] ---> Returns an array containing all rows from the 1st to the 4th
|
||||
# dataset["0:5"] ---> Returns an array containing all columns from the 1st to the 4th
|
||||
# dataset["label0;label5"] ---> Returns an array containing all row from the one with label == "label0" to the one with label == "label5"
|
||||
# dataset["header0:header0"] ---> Returns an array containing all columns from the one with label == "label0" to the one with label == "label5"
|
||||
func _get(_property : StringName):
|
||||
var propertystr : String = _property
|
||||
# ":" --> Columns
|
||||
if ":" in propertystr:
|
||||
var property : PoolStringArray = propertystr.split(":")
|
||||
if (property[0]).is_valid_integer():
|
||||
if property[1] == "*":
|
||||
return get_icolumns(range(property[0] as int, headers.size()-1))
|
||||
else:
|
||||
return get_icolumns(range(property[0] as int, property[1] as int +1))
|
||||
else:
|
||||
if property[1] == "*":
|
||||
return get_icolumns(range(get_column_index(property[0]), headers.size()-1))
|
||||
else:
|
||||
return get_icolumns(range(get_column_index(property[0]), get_column_index(property[1])))
|
||||
# ";" --> Rows
|
||||
elif ";" in propertystr:
|
||||
var property : PoolStringArray = propertystr.split(";")
|
||||
if (property[0]).is_valid_integer():
|
||||
return get_irows(range(property[0] as int, property[1] as int + 1 ))
|
||||
else:
|
||||
return get_irows(range(get_row_index(property[0]), get_row_index(property[1])))
|
||||
elif "," in propertystr:
|
||||
var property : PoolStringArray = propertystr.split(",")
|
||||
else:
|
||||
if (propertystr as String).is_valid_integer():
|
||||
return get_icolumn(propertystr as int)
|
||||
else:
|
||||
return get_column(propertystr)
|
175
game/addons/easy_charts/utilities/classes/structures/matrix.gd
Normal file
175
game/addons/easy_charts/utilities/classes/structures/matrix.gd
Normal file
@ -0,0 +1,175 @@
|
||||
tool
|
||||
extends Resource
|
||||
class_name Matrix
|
||||
|
||||
var values : Array = []
|
||||
|
||||
func _init(matrix : Array = [], size : int = 0) -> void:
|
||||
values = matrix
|
||||
|
||||
func insert_row(row : Array, index : int = values.size()) -> void:
|
||||
if rows() != 0:
|
||||
assert(row.size() == columns(), "the row size must match matrix row size")
|
||||
values.insert(index, row)
|
||||
|
||||
func update_row(row : Array, index : int) -> void:
|
||||
assert(rows() > index, "the row size must match matrix row size")
|
||||
values[index] = row
|
||||
|
||||
func remove_row(index: int) -> void:
|
||||
assert(rows() > index, "the row size must match matrix row size")
|
||||
values.remove(index)
|
||||
|
||||
func insert_column(column : Array, index : int = values[0].size()) -> void:
|
||||
if columns() != 0:
|
||||
assert(column.size() == rows(), "the column size must match matrix column size")
|
||||
for row_idx in column.size():
|
||||
values[row_idx].insert(index, column[row_idx])
|
||||
|
||||
func update_column(column : Array, index : int) -> void:
|
||||
assert(columns() > index, "the column size must match matrix column size")
|
||||
for row_idx in column.size():
|
||||
values[row_idx][index] = column[row_idx]
|
||||
|
||||
func remove_column(index: int) -> void:
|
||||
assert(columns() > index, "the column index must be at least equals to the rows count")
|
||||
for row in get_rows():
|
||||
row.remove(index)
|
||||
|
||||
func resize(rows: int, columns: int) -> void:
|
||||
for row in range(rows):
|
||||
var row_column: Array = []
|
||||
row_column.resize(columns)
|
||||
values.append(row_column)
|
||||
|
||||
func to_array() -> Array:
|
||||
return values.duplicate(true)
|
||||
|
||||
func get_size() -> Vector2:
|
||||
return Vector2(rows(), columns())
|
||||
|
||||
func rows() -> int:
|
||||
return values.size()
|
||||
|
||||
func columns() -> int:
|
||||
return values[0].size() if rows() != 0 else 0
|
||||
|
||||
func value(row: int, column: int) -> float:
|
||||
return values[row][column]
|
||||
|
||||
func set_value(value: float, row: int, column: int) -> void:
|
||||
values[row][column] = value
|
||||
|
||||
func get_column(column : int) -> Array:
|
||||
assert(column < columns(), "index of the column requested (%s) exceedes matrix columns (%s)"%[column, columns()])
|
||||
var column_array : Array = []
|
||||
for row in values:
|
||||
column_array.append(row[column])
|
||||
return column_array
|
||||
|
||||
func get_columns(from : int = 0, to : int = columns()-1) -> Array:
|
||||
var values : Array = []
|
||||
for column in range(from, to):
|
||||
values.append(get_column(column))
|
||||
return values
|
||||
# return MatrixGenerator.from_array(values)
|
||||
|
||||
func get_row(row : int) -> Array:
|
||||
assert(row < rows(), "index of the row requested (%s) exceedes matrix rows (%s)"%[row, rows()])
|
||||
return values[row]
|
||||
|
||||
func get_rows(from : int = 0, to : int = rows()-1) -> Array:
|
||||
return values.slice(from, to)
|
||||
# return MatrixGenerator.from_array(values)
|
||||
|
||||
func is_empty() -> bool:
|
||||
return rows() == 0 and columns() == 0
|
||||
|
||||
|
||||
func is_square() -> bool:
|
||||
return columns() == rows()
|
||||
|
||||
|
||||
func is_diagonal() -> bool:
|
||||
if not is_square():
|
||||
return false
|
||||
|
||||
for i in rows():
|
||||
for j in columns():
|
||||
if i != j and values[i][j] != 0:
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
|
||||
func is_upper_triangular() -> bool:
|
||||
if not is_square():
|
||||
return false
|
||||
|
||||
for i in rows():
|
||||
for j in columns():
|
||||
if i > j and values[i][j] != 0:
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
|
||||
func is_lower_triangular() -> bool:
|
||||
if not is_square():
|
||||
return false
|
||||
|
||||
for i in rows():
|
||||
for j in columns():
|
||||
if i < j and values[i][j] != 0:
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
|
||||
func is_triangular() -> bool:
|
||||
return is_upper_triangular() or is_lower_triangular()
|
||||
|
||||
|
||||
func is_identity() -> bool:
|
||||
if not is_diagonal():
|
||||
return false
|
||||
|
||||
for i in rows():
|
||||
if values[i][i] != 1:
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
func _to_string() -> String:
|
||||
var last_string_len : int
|
||||
for row in values:
|
||||
for column in row:
|
||||
var string_len : int = str(column).length()
|
||||
last_string_len = string_len if string_len > last_string_len else last_string_len
|
||||
var string : String = "\n"
|
||||
for row_i in values.size():
|
||||
for column_i in values[row_i].size():
|
||||
string+="%*s" % [last_string_len+1 if column_i!=0 else last_string_len, values[row_i][column_i]]
|
||||
string+="\n"
|
||||
return string
|
||||
|
||||
# ----
|
||||
func set(position: String, value) -> void:
|
||||
var t_pos: Array = position.split(",")
|
||||
values[t_pos[0]][t_pos[1]] = value
|
||||
|
||||
# --------------
|
||||
func _get(_property : StringName):
|
||||
var propertystr : String = _property
|
||||
# ":" --> Columns
|
||||
if ":" in propertystr:
|
||||
var property : PoolStringArray = propertystr.split(":")
|
||||
var from : PoolStringArray = property[0].split(",")
|
||||
var to : PoolStringArray = property[1].split(",")
|
||||
elif "," in propertystr:
|
||||
var property : PoolStringArray = propertystr.split(",")
|
||||
if property.size() == 2:
|
||||
return get_row(property[0] as int)[property[1] as int]
|
||||
else:
|
||||
if propertystr.is_valid_integer():
|
||||
return get_row(propertystr as int)
|
@ -0,0 +1,160 @@
|
||||
tool
|
||||
extends Reference
|
||||
class_name MatrixGenerator
|
||||
|
||||
static func zeros(rows: int, columns: int) -> Matrix:
|
||||
var zeros: Array = []
|
||||
var t_rows: Array = []
|
||||
t_rows.resize(columns)
|
||||
t_rows.fill(0.0)
|
||||
for row in rows:
|
||||
zeros.append(t_rows.duplicate())
|
||||
return Matrix.new(zeros)
|
||||
|
||||
# Generates a Matrix with random values between [from; to] with a given @size (rows, columns)
|
||||
static func random_float_range(from : float, to : float, size : Vector2, _seed : int = 1234) -> Matrix:
|
||||
seed(_seed)
|
||||
randomize()
|
||||
var array : Array = []
|
||||
for row in range(size.x):
|
||||
var matrix_row : Array = []
|
||||
for column in range(size.y): matrix_row.append(rand_range(from,to))
|
||||
array.append(matrix_row)
|
||||
return Matrix.new(array)
|
||||
|
||||
# Generates a Matrix giving an Array (Array must by Array[Array])
|
||||
static func from_array(array : Array = []) -> Matrix:
|
||||
var matrix : Array = []
|
||||
matrix.append(array)
|
||||
return Matrix.new(matrix)
|
||||
|
||||
# Generates a sub-Matrix giving a Matrix, a @from Array [row_i, column_i] and a @to Array [row_j, column_j]
|
||||
static func sub_matrix(_matrix : Matrix, from : PoolIntArray, to : PoolIntArray) -> Matrix:
|
||||
assert( not (to[0] > _matrix.rows() or to[1] > _matrix.columns()),
|
||||
"%s is not an acceptable size for the submatrix, giving a matrix of size %s"%[to, _matrix.get_size()])
|
||||
var array : Array = []
|
||||
var rows : Array = _matrix.get_rows(from[0], to[0])
|
||||
for row in rows:
|
||||
array.append(row.slice(from[1], to[1]))
|
||||
return Matrix.new(array)
|
||||
|
||||
# Duplicates a given Matrix
|
||||
static func duplicate(_matrix : Matrix) -> Matrix:
|
||||
return Matrix.new(_matrix.to_array().duplicate())
|
||||
|
||||
# Calculate the determinant of a matrix
|
||||
static func determinant(matrix: Matrix) -> float:
|
||||
assert(matrix.is_square(), "Expected square matrix")
|
||||
|
||||
var determinant: float = 0.0
|
||||
|
||||
if matrix.rows() == 2 :
|
||||
determinant = (matrix.value(0, 0) * matrix.value(1, 1)) - (matrix.value(0, 1) * matrix.value(1, 0))
|
||||
elif matrix.is_diagonal() or matrix.is_triangular() :
|
||||
for i in matrix.rows():
|
||||
determinant *= matrix.value(i, i)
|
||||
elif matrix.is_identity() :
|
||||
determinant = 1.0
|
||||
else:
|
||||
# Laplace expansion
|
||||
var multiplier: float = -1.0
|
||||
var submatrix: Matrix = sub_matrix(matrix, [1, 0], [matrix.rows(), matrix.columns()])
|
||||
for j in matrix.columns() :
|
||||
var cofactor: Matrix = copy(submatrix)
|
||||
cofactor.remove_column(j)
|
||||
multiplier *= -1.0
|
||||
determinant += multiplier * matrix.value(0, j) * determinant(cofactor)
|
||||
|
||||
return determinant
|
||||
|
||||
|
||||
# Calculate the inverse of a Matrix
|
||||
static func inverse(matrix: Matrix) -> Matrix:
|
||||
var inverse: Matrix
|
||||
|
||||
# Minors and Cofactors
|
||||
var minors_cofactors: Matrix = zeros(matrix.rows(), matrix.columns())
|
||||
var multiplier: float = -1.0
|
||||
|
||||
for i in minors_cofactors.rows():
|
||||
for j in minors_cofactors.columns():
|
||||
var t_minor: Matrix = copy(matrix)
|
||||
t_minor.remove_row(i)
|
||||
t_minor.remove_column(j)
|
||||
multiplier *= -1.0
|
||||
minors_cofactors.set_value(multiplier * determinant(t_minor), i, j)
|
||||
|
||||
var transpose: Matrix = transpose(minors_cofactors)
|
||||
var determinant: float = determinant(matrix)
|
||||
|
||||
inverse = multiply_float(transpose, 1 / determinant)
|
||||
|
||||
return inverse
|
||||
|
||||
# Transpose a given Matrix
|
||||
static func transpose(_matrix : Matrix) -> Matrix:
|
||||
var array : Array = []
|
||||
array.resize(_matrix.get_size().y)
|
||||
var row : Array = []
|
||||
row.resize(_matrix.get_size().x)
|
||||
for x in array.size():
|
||||
array[x] = row.duplicate()
|
||||
for i in range(_matrix.get_size().x):
|
||||
for j in range(_matrix.get_size().y):
|
||||
array[j][i] = (_matrix.to_array()[i][j])
|
||||
return Matrix.new(array)
|
||||
|
||||
# Calculates the dot product (A*B) matrix between two Matrixes
|
||||
static func dot(_matrix1 : Matrix, _matrix2 : Matrix) -> Matrix:
|
||||
if _matrix1.get_size().y != _matrix2.get_size().x:
|
||||
printerr("matrix1 number of columns: %s must be the same as matrix2 number of rows: %s"%[_matrix1.get_size().y, _matrix2.get_size().x])
|
||||
return Matrix.new()
|
||||
var array : Array = []
|
||||
for x in range(_matrix1.get_size().x):
|
||||
var row : Array = []
|
||||
for y in range(_matrix2.get_size().y):
|
||||
var sum : float
|
||||
for k in range(_matrix1.get_size().y):
|
||||
sum += (_matrix1.to_array()[x][k]*_matrix2.to_array()[k][y])
|
||||
row.append(sum)
|
||||
array.append(row)
|
||||
return Matrix.new(array)
|
||||
|
||||
# Calculates the hadamard (element-wise product) between two Matrixes
|
||||
static func hadamard(_matrix1 : Matrix, _matrix2 : Matrix) -> Matrix:
|
||||
if _matrix1.get_size() != _matrix2.get_size():
|
||||
printerr("matrix1 size: %s must be the same as matrix2 size: %s"%[_matrix1.get_size(), _matrix2.get_size()])
|
||||
return Matrix.new()
|
||||
var array : Array = []
|
||||
for x in range(_matrix1.to_array().size()):
|
||||
var row : Array = []
|
||||
for y in range(_matrix1.to_array()[x].size()):
|
||||
assert(typeof(_matrix1.to_array()[x][y]) != TYPE_STRING and typeof(_matrix2.to_array()[x][y]) != TYPE_STRING, "can't apply operations over a Matrix of Strings")
|
||||
row.append(_matrix1.to_array()[x][y] * _matrix2.to_array()[x][y])
|
||||
array.append(row)
|
||||
return Matrix.new(array)
|
||||
|
||||
# Multiply a given Matrix for an int value
|
||||
static func multiply_int(_matrix1 : Matrix, _int : int) -> Matrix:
|
||||
var array : Array = _matrix1.to_array().duplicate()
|
||||
for x in range(_matrix1.to_array().size()):
|
||||
for y in range(_matrix1.to_array()[x].size()):
|
||||
array[x][y]*=_int
|
||||
array[x][y] = int(array[x][y])
|
||||
return Matrix.new(array)
|
||||
|
||||
# Multiply a given Matrix for a float value
|
||||
static func multiply_float(_matrix1 : Matrix, _float : float) -> Matrix:
|
||||
var array : Array = _matrix1.to_array().duplicate()
|
||||
for x in range(_matrix1.to_array().size()):
|
||||
for y in range(_matrix1.to_array()[x].size()):
|
||||
array[x][y]*=_float
|
||||
return Matrix.new(array)
|
||||
|
||||
|
||||
static func copy(matrix: Matrix) -> Matrix:
|
||||
return Matrix.new(matrix.values.duplicate(true))
|
||||
|
||||
# ------------------------------------------------------------
|
||||
static func get_letter_index(index : int) -> String:
|
||||
return "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z".split(" ")[index]
|
25
game/addons/easy_charts/utilities/classes/structures/pair.gd
Normal file
25
game/addons/easy_charts/utilities/classes/structures/pair.gd
Normal file
@ -0,0 +1,25 @@
|
||||
"""
|
||||
A class representing a Pair (or Tuple) of values.
|
||||
It is a lightweight class that can easily replace the improper and/or
|
||||
unnecessary usage of a 2d Array (ex. `var arr: Array = [0.5, 0.6]`)
|
||||
or of a Vector2 (ex. `var v2: Vector2 = Vector2(0.6, 0.8)`).
|
||||
"""
|
||||
extends Reference
|
||||
class_name Pair
|
||||
|
||||
var left
|
||||
var right
|
||||
|
||||
func _init(left = null, right = null) -> void:
|
||||
self.left = left
|
||||
self.right = right
|
||||
|
||||
func _format(val) -> String:
|
||||
var format: String = "%s"
|
||||
match typeof(val):
|
||||
TYPE_REAL:
|
||||
"%.2f"
|
||||
return format % val
|
||||
|
||||
func _to_string() -> String:
|
||||
return "[%s, %s]" % [_format(self.left), _format(self.right)]
|
66
game/addons/easy_charts/utilities/components/rect/rect.gd
Normal file
66
game/addons/easy_charts/utilities/components/rect/rect.gd
Normal file
@ -0,0 +1,66 @@
|
||||
extends Control
|
||||
|
||||
var OFFSET : Vector2 = Vector2()
|
||||
var point_value : Array
|
||||
var point_position : Vector2
|
||||
var color : Color
|
||||
var color_outline : Color
|
||||
var function : String
|
||||
|
||||
var mouse_entered : bool = false
|
||||
|
||||
|
||||
signal _mouse_entered()
|
||||
signal _mouse_exited()
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
func _draw():
|
||||
if mouse_entered:
|
||||
draw_rect(Rect2(rect_position - OFFSET,rect_size),color_outline,true,12,true)
|
||||
|
||||
func create_point(color : Color, color_outline : Color, position : Vector2, size : Vector2, value : Array, function : String):
|
||||
|
||||
self.color = color
|
||||
self.color_outline = color_outline
|
||||
self.point_position = position
|
||||
self.rect_position = point_position - OFFSET
|
||||
self.rect_size = size
|
||||
self.point_value = value
|
||||
self.function = function
|
||||
|
||||
func format_value(v : Array, format_x : bool, format_y : bool):
|
||||
var x : String = str(v[0])
|
||||
var y : String = str(v[1])
|
||||
|
||||
if format_x:
|
||||
x = format(v[1])
|
||||
if format_y:
|
||||
y = format(v[1])
|
||||
|
||||
return [x,y]
|
||||
|
||||
func format(n):
|
||||
n = str(n)
|
||||
var size = n.length()
|
||||
var s
|
||||
for i in range(size):
|
||||
if((size - i) % 3 == 0 and i > 0):
|
||||
s = str(s,",", n[i])
|
||||
else:
|
||||
s = str(s,n[i])
|
||||
|
||||
return s.replace("Null","")
|
||||
|
||||
func _on_Rect_mouse_entered():
|
||||
mouse_entered = true
|
||||
emit_signal("_mouse_entered")
|
||||
update()
|
||||
|
||||
func _on_Rect_mouse_exited():
|
||||
mouse_entered = false
|
||||
emit_signal("_mouse_exited")
|
||||
update()
|
12
game/addons/easy_charts/utilities/components/rect/rect.tscn
Normal file
12
game/addons/easy_charts/utilities/components/rect/rect.tscn
Normal file
@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/easy_charts/utilities/components/rect/rect.gd" type="Script" id=1]
|
||||
|
||||
[node name="Rect" type="Control"]
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[connection signal="mouse_entered" from="." to="." method="_on_Rect_mouse_entered"]
|
||||
[connection signal="mouse_exited" from="." to="." method="_on_Rect_mouse_exited"]
|
17
game/addons/easy_charts/utilities/components/slice/slice.gd
Normal file
17
game/addons/easy_charts/utilities/components/slice/slice.gd
Normal file
@ -0,0 +1,17 @@
|
||||
extends Reference
|
||||
class_name Slice
|
||||
|
||||
var x_value : String
|
||||
var y_value : String
|
||||
var from_angle : float
|
||||
var to_angle : float
|
||||
var function : String
|
||||
var color : Color
|
||||
|
||||
func _init(x : String, y : String, from : float, to : float, fun : String, col : Color):
|
||||
x_value = x
|
||||
y_value = y
|
||||
from_angle = from
|
||||
to_angle = to
|
||||
function = fun
|
||||
color = col
|
@ -0,0 +1,36 @@
|
||||
tool
|
||||
extends PanelContainer
|
||||
class_name DataTooltip
|
||||
|
||||
var value : String = ""
|
||||
var position : Vector2 = Vector2()
|
||||
|
||||
onready var x_lbl : Label = $PointData/x
|
||||
onready var y_lbl : Label = $PointData/Value/y
|
||||
onready var func_lbl : Label = $PointData/Value/Function
|
||||
onready var color_rect: Panel = $PointData/Value/Color
|
||||
|
||||
func _ready():
|
||||
hide()
|
||||
update_size()
|
||||
|
||||
func _process(delta):
|
||||
if Engine.editor_hint:
|
||||
return
|
||||
rect_position = get_global_mouse_position() + Vector2(15, - (get_rect().size.y / 2))
|
||||
|
||||
func update_values(x: String, y: String, function: String, color: Color):
|
||||
x_lbl.set_text(x)
|
||||
y_lbl.set_text(y)
|
||||
func_lbl.set_text(function)
|
||||
color_rect.get("custom_styles/panel").set("bg_color", color)
|
||||
|
||||
func update_size():
|
||||
x_lbl.set_text("")
|
||||
y_lbl.set_text("")
|
||||
func_lbl.set_text("")
|
||||
rect_size = Vector2.ZERO
|
||||
|
||||
func _on_DataTooltip_visibility_changed():
|
||||
if not visible:
|
||||
update_size()
|
@ -0,0 +1,116 @@
|
||||
[gd_scene load_steps=5 format=2]
|
||||
|
||||
[ext_resource path="res://addons/easy_charts/utilities/containers/data_tooltip/data_tooltip.gd" type="Script" id=1]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id=1]
|
||||
content_margin_left = 10.0
|
||||
content_margin_right = 10.0
|
||||
content_margin_top = 8.0
|
||||
content_margin_bottom = 8.0
|
||||
bg_color = Color( 0.101961, 0.101961, 0.101961, 0.784314 )
|
||||
border_color = Color( 1, 1, 1, 1 )
|
||||
corner_radius_top_left = 5
|
||||
corner_radius_top_right = 5
|
||||
corner_radius_bottom_right = 5
|
||||
corner_radius_bottom_left = 5
|
||||
corner_detail = 20
|
||||
anti_aliasing_size = 0.9
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id=2]
|
||||
corner_radius_top_left = 5
|
||||
corner_radius_top_right = 5
|
||||
corner_radius_bottom_right = 5
|
||||
corner_radius_bottom_left = 5
|
||||
corner_detail = 20
|
||||
anti_aliasing_size = 0.7
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id=3]
|
||||
|
||||
[node name="DataTooltip" type="PanelContainer"]
|
||||
margin_right = 169.0
|
||||
margin_bottom = 49.0
|
||||
mouse_filter = 2
|
||||
custom_styles/panel = SubResource( 1 )
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="PointData" type="VBoxContainer" parent="."]
|
||||
margin_left = 10.0
|
||||
margin_top = 8.0
|
||||
margin_right = 159.0
|
||||
margin_bottom = 42.0
|
||||
grow_horizontal = 2
|
||||
size_flags_horizontal = 3
|
||||
custom_constants/separation = 6
|
||||
alignment = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="x" type="Label" parent="PointData"]
|
||||
margin_right = 55.0
|
||||
margin_bottom = 14.0
|
||||
size_flags_horizontal = 0
|
||||
custom_colors/font_color = Color( 1, 1, 1, 1 )
|
||||
text = "{x value}"
|
||||
valign = 1
|
||||
|
||||
[node name="Value" type="HBoxContainer" parent="PointData"]
|
||||
margin_top = 20.0
|
||||
margin_right = 149.0
|
||||
margin_bottom = 34.0
|
||||
grow_horizontal = 2
|
||||
size_flags_horizontal = 7
|
||||
custom_constants/separation = 1
|
||||
|
||||
[node name="Color" type="Panel" parent="PointData/Value"]
|
||||
margin_top = 2.0
|
||||
margin_right = 10.0
|
||||
margin_bottom = 12.0
|
||||
rect_min_size = Vector2( 10, 10 )
|
||||
size_flags_horizontal = 4
|
||||
size_flags_vertical = 4
|
||||
custom_styles/panel = SubResource( 2 )
|
||||
|
||||
[node name="VSeparator" type="VSeparator" parent="PointData/Value"]
|
||||
margin_left = 11.0
|
||||
margin_right = 15.0
|
||||
margin_bottom = 14.0
|
||||
custom_constants/separation = 4
|
||||
custom_styles/separator = SubResource( 3 )
|
||||
|
||||
[node name="Function" type="Label" parent="PointData/Value"]
|
||||
margin_left = 16.0
|
||||
margin_right = 78.0
|
||||
margin_bottom = 14.0
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 5
|
||||
text = "{function}"
|
||||
valign = 1
|
||||
|
||||
[node name="sep" type="Label" parent="PointData/Value"]
|
||||
margin_left = 79.0
|
||||
margin_right = 83.0
|
||||
margin_bottom = 14.0
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 5
|
||||
text = ":"
|
||||
valign = 1
|
||||
|
||||
[node name="VSeparator2" type="VSeparator" parent="PointData/Value"]
|
||||
margin_left = 84.0
|
||||
margin_right = 88.0
|
||||
margin_bottom = 14.0
|
||||
custom_constants/separation = 4
|
||||
custom_styles/separator = SubResource( 3 )
|
||||
|
||||
[node name="y" type="Label" parent="PointData/Value"]
|
||||
margin_left = 89.0
|
||||
margin_right = 144.0
|
||||
margin_bottom = 14.0
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 5
|
||||
custom_colors/font_color = Color( 1, 1, 1, 1 )
|
||||
text = "{y value}"
|
||||
valign = 1
|
||||
|
||||
[connection signal="visibility_changed" from="." to="." method="_on_DataTooltip_visibility_changed"]
|
@ -0,0 +1,41 @@
|
||||
tool
|
||||
extends VBoxContainer
|
||||
class_name LegendElement
|
||||
|
||||
onready var Function : Label = $Function
|
||||
onready var FunctionColor : ColorRect = $Color
|
||||
|
||||
var function : String setget set_function, get_function
|
||||
var color : Color setget set_function_color, get_function_color
|
||||
var font_color : Color
|
||||
var font : Font
|
||||
|
||||
func _ready():
|
||||
Function.set("custom_fonts/font",font)
|
||||
Function.set("custom_colors/font_color",font_color)
|
||||
Function.set_text(function)
|
||||
FunctionColor.set_frame_color(color)
|
||||
|
||||
func create_legend(text : String, color : Color, font : Font, font_color : Color):
|
||||
self.function = text
|
||||
self.color = color
|
||||
self.font_color = font_color
|
||||
self.font = font
|
||||
|
||||
func set_function( t : String ):
|
||||
function = t
|
||||
|
||||
func get_function() -> String:
|
||||
return function
|
||||
|
||||
func set_function_color( c : Color ):
|
||||
color = c
|
||||
|
||||
func get_function_color() -> Color:
|
||||
return color
|
||||
|
||||
func get_class() -> String:
|
||||
return "Legend Element"
|
||||
|
||||
func _to_string() -> String:
|
||||
return "%s (%s, %s) " % [get_class(), get_function(), get_function_color().to_html(true)]
|
@ -0,0 +1,27 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/easy_charts/utilities/containers/legend/function_legend.gd" type="Script" id=1]
|
||||
|
||||
[node name="FunctionLegend" type="VBoxContainer"]
|
||||
margin_right = 80.0
|
||||
margin_bottom = 26.0
|
||||
alignment = 1
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Function" type="Label" parent="."]
|
||||
margin_top = 2.0
|
||||
margin_right = 80.0
|
||||
margin_bottom = 16.0
|
||||
custom_colors/font_color = Color( 0, 0, 0, 1 )
|
||||
align = 1
|
||||
valign = 1
|
||||
|
||||
[node name="Color" type="ColorRect" parent="."]
|
||||
margin_top = 20.0
|
||||
margin_right = 80.0
|
||||
margin_bottom = 23.0
|
||||
rect_min_size = Vector2( 15, 3 )
|
||||
color = Color( 0, 0, 0, 1 )
|
155
game/addons/easy_charts/utilities/icons/linechart.svg
Normal file
155
game/addons/easy_charts/utilities/icons/linechart.svg
Normal file
@ -0,0 +1,155 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 3.1749999 3.1750001"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||
sodipodi:docname="linechart.svg">
|
||||
<defs
|
||||
id="defs2">
|
||||
<linearGradient
|
||||
id="linearGradient5569"
|
||||
osb:paint="solid">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5567" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="45.254834"
|
||||
inkscape:cx="7.2321717"
|
||||
inkscape:cy="4.3383636"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:snap-others="true"
|
||||
inkscape:snap-nodes="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:snap-global="false"
|
||||
inkscape:object-nodes="false"
|
||||
inkscape:snap-grids="true"
|
||||
inkscape:snap-to-guides="false"
|
||||
inkscape:object-paths="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1001"
|
||||
inkscape:window-x="2391"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
units="px"
|
||||
scale-x="1e-05">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid1377"
|
||||
empspacing="12" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Livello 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-293.82497)">
|
||||
<rect
|
||||
style="fill:#a5efac;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect1486"
|
||||
width="0.26458332"
|
||||
height="0.26458332"
|
||||
x="-1.0583333"
|
||||
y="293.82498" />
|
||||
<rect
|
||||
style="fill:#a5b7f3;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect1578"
|
||||
width="0.26458332"
|
||||
height="0.26458332"
|
||||
x="-1.0583333"
|
||||
y="294.08954" />
|
||||
<rect
|
||||
style="fill:#a5efac;fill-opacity:1;stroke:none;stroke-width:0.27538645;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect5539"
|
||||
width="0.52916664"
|
||||
height="3.4395685"
|
||||
x="-0.26458332"
|
||||
y="293.82498" />
|
||||
<rect
|
||||
style="fill:#a5efac;fill-opacity:1;stroke:none;stroke-width:0.27634826;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect5541"
|
||||
width="3.175"
|
||||
height="0.52916664"
|
||||
x="1.3907751e-08"
|
||||
y="296.73535" />
|
||||
<rect
|
||||
style="fill:#a5efac;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.29347834;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect7010"
|
||||
width="1.3280054"
|
||||
height="0.39521819"
|
||||
x="264.53415"
|
||||
y="142.6459"
|
||||
transform="matrix(0.48573212,0.87410772,-0.89524404,0.44557615,0,0)"
|
||||
ry="0.1976091" />
|
||||
<rect
|
||||
style="fill:#a5efac;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.29347831;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect7010-8"
|
||||
width="1.3280054"
|
||||
height="0.39521819"
|
||||
x="262.32922"
|
||||
y="146.91296"
|
||||
transform="matrix(-0.49326555,0.86987878,0.89136123,0.45329367,0,0)"
|
||||
ry="0.1976091" />
|
||||
<rect
|
||||
style="fill:#a5efac;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.29347828;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect7010-8-9"
|
||||
width="1.3280054"
|
||||
height="0.39521819"
|
||||
x="261.59872"
|
||||
y="146.90884"
|
||||
transform="matrix(-0.49326555,0.86987878,0.89136123,0.45329367,0,0)"
|
||||
ry="0.1976091" />
|
||||
<rect
|
||||
style="fill:#a5efac;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.29347825;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect7010-8-9-2"
|
||||
width="1.3280054"
|
||||
height="0.39521819"
|
||||
x="263.42633"
|
||||
y="143.44034"
|
||||
transform="matrix(0.49326555,0.86987878,-0.89136123,0.45329367,0,0)"
|
||||
ry="0.1976091" />
|
||||
<path
|
||||
style="fill:#a5efac;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.28821853;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 2.7247357,295.19899 a 0.45017607,0.44140657 0 0 0 -0.4505985,0.44164 0.45017607,0.44140657 0 0 0 0.4505985,0.44163 0.45017607,0.44140657 0 0 0 0.450061,-0.44163 0.45017607,0.44140657 0 0 0 -0.450061,-0.44164 z m 0,0.22824 a 0.2129211,0.21319639 0 0 1 0.2129321,0.2134 0.2129211,0.21319639 0 0 1 -0.2129321,0.21339 0.2129211,0.21319639 0 0 1 -0.2129319,-0.21339 0.2129211,0.21319639 0 0 1 0.2129319,-0.2134 z"
|
||||
id="path7057"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.6 KiB |
35
game/addons/easy_charts/utilities/icons/linechart.svg.import
Normal file
35
game/addons/easy_charts/utilities/icons/linechart.svg.import
Normal file
@ -0,0 +1,35 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/linechart.svg-922834f0462a2c88be644081c47c63ad.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/easy_charts/utilities/icons/linechart.svg"
|
||||
dest_files=[ "res://.import/linechart.svg-922834f0462a2c88be644081c47c63ad.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
155
game/addons/easy_charts/utilities/icons/linechart2d.svg
Normal file
155
game/addons/easy_charts/utilities/icons/linechart2d.svg
Normal file
@ -0,0 +1,155 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 3.1749999 3.1750001"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||
sodipodi:docname="linechart2d.svg">
|
||||
<defs
|
||||
id="defs2">
|
||||
<linearGradient
|
||||
id="linearGradient5569"
|
||||
osb:paint="solid">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5567" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="45.254834"
|
||||
inkscape:cx="7.2321717"
|
||||
inkscape:cy="4.3383636"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:snap-others="true"
|
||||
inkscape:snap-nodes="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:snap-global="false"
|
||||
inkscape:object-nodes="false"
|
||||
inkscape:snap-grids="true"
|
||||
inkscape:snap-to-guides="false"
|
||||
inkscape:object-paths="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1001"
|
||||
inkscape:window-x="2391"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
units="px"
|
||||
scale-x="1e-05">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid1377"
|
||||
empspacing="12" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Livello 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-293.82497)">
|
||||
<rect
|
||||
style="fill:#a5efac;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect1486"
|
||||
width="0.26458332"
|
||||
height="0.26458332"
|
||||
x="-1.0583333"
|
||||
y="293.82498" />
|
||||
<rect
|
||||
style="fill:#a5b7f3;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect1578"
|
||||
width="0.26458332"
|
||||
height="0.26458332"
|
||||
x="-1.0583333"
|
||||
y="294.08954" />
|
||||
<rect
|
||||
style="fill:#a5b7f3;fill-opacity:1;stroke:none;stroke-width:0.27538645;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect5539"
|
||||
width="0.52916664"
|
||||
height="3.4395685"
|
||||
x="-0.26458332"
|
||||
y="293.82498" />
|
||||
<rect
|
||||
style="fill:#a5b7f3;fill-opacity:1;stroke:none;stroke-width:0.27634826;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect5541"
|
||||
width="3.175"
|
||||
height="0.52916664"
|
||||
x="1.3907751e-08"
|
||||
y="296.73535" />
|
||||
<rect
|
||||
style="fill:#a5b7f3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.29347834;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect7010"
|
||||
width="1.3280054"
|
||||
height="0.39521819"
|
||||
x="264.53415"
|
||||
y="142.6459"
|
||||
transform="matrix(0.48573212,0.87410772,-0.89524404,0.44557615,0,0)"
|
||||
ry="0.1976091" />
|
||||
<rect
|
||||
style="fill:#a5b7f3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.29347831;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect7010-8"
|
||||
width="1.3280054"
|
||||
height="0.39521819"
|
||||
x="262.32922"
|
||||
y="146.91296"
|
||||
transform="matrix(-0.49326555,0.86987878,0.89136123,0.45329367,0,0)"
|
||||
ry="0.1976091" />
|
||||
<rect
|
||||
style="fill:#a5b7f3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.29347828;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect7010-8-9"
|
||||
width="1.3280054"
|
||||
height="0.39521819"
|
||||
x="261.59872"
|
||||
y="146.90884"
|
||||
transform="matrix(-0.49326555,0.86987878,0.89136123,0.45329367,0,0)"
|
||||
ry="0.1976091" />
|
||||
<rect
|
||||
style="fill:#a5b7f3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.29347825;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect7010-8-9-2"
|
||||
width="1.3280054"
|
||||
height="0.39521819"
|
||||
x="263.42633"
|
||||
y="143.44034"
|
||||
transform="matrix(0.49326555,0.86987878,-0.89136123,0.45329367,0,0)"
|
||||
ry="0.1976091" />
|
||||
<path
|
||||
style="fill:#a5b7f3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.28821853;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 2.7247357,295.19899 a 0.45017607,0.44140657 0 0 0 -0.4505985,0.44164 0.45017607,0.44140657 0 0 0 0.4505985,0.44163 0.45017607,0.44140657 0 0 0 0.450061,-0.44163 0.45017607,0.44140657 0 0 0 -0.450061,-0.44164 z m 0,0.22824 a 0.2129211,0.21319639 0 0 1 0.2129321,0.2134 0.2129211,0.21319639 0 0 1 -0.2129321,0.21339 0.2129211,0.21319639 0 0 1 -0.2129319,-0.21339 0.2129211,0.21319639 0 0 1 0.2129319,-0.2134 z"
|
||||
id="path7057"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.6 KiB |
@ -0,0 +1,35 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/linechart2d.svg-1067b05eddcc451c2fc80a8734aa8056.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/easy_charts/utilities/icons/linechart2d.svg"
|
||||
dest_files=[ "res://.import/linechart2d.svg-1067b05eddcc451c2fc80a8734aa8056.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
46
game/addons/easy_charts/utilities/scripts/ec_utilities.gd
Normal file
46
game/addons/easy_charts/utilities/scripts/ec_utilities.gd
Normal file
@ -0,0 +1,46 @@
|
||||
tool
|
||||
extends Node
|
||||
|
||||
var alphabet : String = "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
# templates = _load_templates()
|
||||
|
||||
func _print_message(message : String, type : int = 0):
|
||||
pass
|
||||
# match type:
|
||||
# 0:
|
||||
# print("[%s] => %s" % [plugin_name, message])
|
||||
# 1:
|
||||
# printerr("ERROR: [%s] => %s" % [plugin_name, message])
|
||||
|
||||
func _load_templates() -> Dictionary:
|
||||
pass
|
||||
return {}
|
||||
# var template_file : File = File.new()
|
||||
# template_file.open("res://addons/easy_charts/templates.json",File.READ)
|
||||
# var templates = JSON.parse(template_file.get_as_text()).get_result()
|
||||
# template_file.close()
|
||||
# return templates
|
||||
|
||||
func get_template(template_index : int):
|
||||
pass
|
||||
# return templates.get(templates.keys()[template_index])
|
||||
|
||||
func get_chart_type(chart_type : int) -> Array:
|
||||
pass
|
||||
return []
|
||||
# return chart_types.get(chart_types.keys()[chart_type])
|
||||
|
||||
func get_letter_index(index : int) -> String:
|
||||
return alphabet.split(" ")[index]
|
||||
|
||||
func save_dataframe_to_file(dataframe: DataFrame, path: String, delimiter: String = ";") -> void:
|
||||
pass
|
||||
# var file = File.new()
|
||||
# file.open(path, File.WRITE)
|
||||
# for row in dataframe.get_dataset():
|
||||
# file.store_line(PoolStringArray(row).join(delimiter))
|
||||
# file.close()
|
||||
|
@ -8,12 +8,120 @@
|
||||
|
||||
config_version=4
|
||||
|
||||
_global_script_classes=[ {
|
||||
"base": "Reference",
|
||||
"class": @"ArrayOperations",
|
||||
"language": @"GDScript",
|
||||
"path": "res://addons/easy_charts/utilities/classes/structures/array_operations.gd"
|
||||
}, {
|
||||
"base": "Reference",
|
||||
"class": @"Bar",
|
||||
"language": @"GDScript",
|
||||
"path": "res://addons/easy_charts/utilities/classes/plotting/bar.gd"
|
||||
}, {
|
||||
"base": "Chart",
|
||||
"class": @"BarChart",
|
||||
"language": @"GDScript",
|
||||
"path": "res://addons/easy_charts/control_charts/BarChart/bar_chart.gd"
|
||||
}, {
|
||||
"base": "Control",
|
||||
"class": @"Chart",
|
||||
"language": @"GDScript",
|
||||
"path": "res://addons/easy_charts/control_charts/chart.gd"
|
||||
}, {
|
||||
"base": "Reference",
|
||||
"class": @"ChartProperties",
|
||||
"language": @"GDScript",
|
||||
"path": "res://addons/easy_charts/utilities/classes/plotting/chart_properties.gd"
|
||||
}, {
|
||||
"base": "Resource",
|
||||
"class": @"DataFrame",
|
||||
"language": @"GDScript",
|
||||
"path": "res://addons/easy_charts/utilities/classes/structures/data_frame.gd"
|
||||
}, {
|
||||
"base": "PanelContainer",
|
||||
"class": @"DataTooltip",
|
||||
"language": @"GDScript",
|
||||
"path": "res://addons/easy_charts/utilities/containers/data_tooltip/data_tooltip.gd"
|
||||
}, {
|
||||
"base": "VBoxContainer",
|
||||
"class": @"LegendElement",
|
||||
"language": @"GDScript",
|
||||
"path": "res://addons/easy_charts/utilities/containers/legend/function_legend.gd"
|
||||
}, {
|
||||
"base": "ScatterChart",
|
||||
"class": @"LineChart",
|
||||
"language": @"GDScript",
|
||||
"path": "res://addons/easy_charts/control_charts/LineChart/line_chart.gd"
|
||||
}, {
|
||||
"base": "Resource",
|
||||
"class": @"Matrix",
|
||||
"language": @"GDScript",
|
||||
"path": "res://addons/easy_charts/utilities/classes/structures/matrix.gd"
|
||||
}, {
|
||||
"base": "Reference",
|
||||
"class": @"MatrixGenerator",
|
||||
"language": @"GDScript",
|
||||
"path": "res://addons/easy_charts/utilities/classes/structures/matrix_generator.gd"
|
||||
}, {
|
||||
"base": "Reference",
|
||||
"class": @"Pair",
|
||||
"language": @"GDScript",
|
||||
"path": "res://addons/easy_charts/utilities/classes/structures/pair.gd"
|
||||
}, {
|
||||
"base": "Reference",
|
||||
"class": @"Point",
|
||||
"language": @"GDScript",
|
||||
"path": "res://addons/easy_charts/utilities/classes/plotting/point.gd"
|
||||
}, {
|
||||
"base": "Reference",
|
||||
"class": @"SampledAxis",
|
||||
"language": @"GDScript",
|
||||
"path": "res://addons/easy_charts/utilities/classes/plotting/sampled_axis.gd"
|
||||
}, {
|
||||
"base": "Chart",
|
||||
"class": @"ScatterChart",
|
||||
"language": @"GDScript",
|
||||
"path": "res://addons/easy_charts/control_charts/ScatterChart/scatter_chart.gd"
|
||||
}, {
|
||||
"base": "Reference",
|
||||
"class": @"Slice",
|
||||
"language": @"GDScript",
|
||||
"path": "res://addons/easy_charts/utilities/components/slice/slice.gd"
|
||||
} ]
|
||||
_global_script_class_icons={
|
||||
@"Chart": "",
|
||||
@"BarChart": "",
|
||||
@"LineChart": "",
|
||||
@"ScatterChart": "",
|
||||
@"Bar": "",
|
||||
@"ChartProperties": "",
|
||||
@"Point": "",
|
||||
@"SampledAxis": "",
|
||||
@"ArrayOperations": "",
|
||||
@"DataFrame": "",
|
||||
@"Matrix": "",
|
||||
@"MatrixGenerator": "",
|
||||
@"Pair": "",
|
||||
@"Slice": "",
|
||||
@"DataTooltip": "",
|
||||
@"LegendElement": ""
|
||||
}
|
||||
|
||||
[application]
|
||||
|
||||
config/name="PMLPP Sample"
|
||||
run/main_scene="res://Main.tscn"
|
||||
config/icon="res://icon.png"
|
||||
|
||||
[autoload]
|
||||
|
||||
ECUtilities="*res://addons/easy_charts/utilities/scripts/ec_utilities.gd"
|
||||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PoolStringArray( "res://addons/easy_charts/plugin.cfg" )
|
||||
|
||||
[physics]
|
||||
|
||||
common/enable_pause_aware_picking=true
|
||||
|
Loading…
Reference in New Issue
Block a user