mirror of
https://github.com/Relintai/pandemonium_engine_easy_charts.git
synced 2025-01-10 15:09:45 +01:00
scatter chart freature compleat
This commit is contained in:
parent
d648b5d228
commit
38225536d1
@ -9,12 +9,15 @@ signal point_exited(point)
|
|||||||
func _ready():
|
func _ready():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
func plot(x: Array, y: Array) -> void:
|
func plot(x: Array, y: Array, drawing_options: DrawingOptions = null, chart_properties: ChartProperties = null) -> void:
|
||||||
self.x = x
|
self.x = x
|
||||||
self.y = y
|
self.y = y
|
||||||
|
|
||||||
_clear()
|
if chart_properties != null:
|
||||||
_pre_process()
|
self.chart_properties = chart_properties
|
||||||
|
if drawing_options != null:
|
||||||
|
self.drawing_options = drawing_options
|
||||||
|
|
||||||
update()
|
update()
|
||||||
|
|
||||||
func _draw_point(point: Point, function_index: int) -> void:
|
func _draw_point(point: Point, function_index: int) -> void:
|
||||||
@ -22,8 +25,8 @@ func _draw_point(point: Point, function_index: int) -> void:
|
|||||||
$Points.add_child(point_container)
|
$Points.add_child(point_container)
|
||||||
point_container.set_point(
|
point_container.set_point(
|
||||||
point,
|
point,
|
||||||
drawing_options.colors.functions[function_index],
|
drawing_options.get_function_color(function_index),
|
||||||
drawing_options.shapes[function_index]
|
drawing_options.get_point_shape(function_index)
|
||||||
)
|
)
|
||||||
point_container.connect("point_entered", self, "_on_point_entered")
|
point_container.connect("point_entered", self, "_on_point_entered")
|
||||||
point_container.connect("point_exited", self, "_on_point_exited")
|
point_container.connect("point_exited", self, "_on_point_exited")
|
||||||
|
@ -11,9 +11,12 @@ __meta__ = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[node name="Points" type="Control" parent="."]
|
[node name="Points" type="Control" parent="."]
|
||||||
unique_name_in_owner = true
|
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
__meta__ = {
|
__meta__ = {
|
||||||
"_edit_use_anchors_": true
|
"_edit_use_anchors_": true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[node name="Canvas" type="Control" parent="."]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
@ -4,17 +4,20 @@ class_name Chart
|
|||||||
var x: Array
|
var x: Array
|
||||||
var y: Array
|
var y: Array
|
||||||
|
|
||||||
var x_sampled: SampledAxis
|
var x_min_max: Pair = Pair.new()
|
||||||
var y_sampled: SampledAxis
|
var y_min_max: Pair = Pair.new()
|
||||||
|
|
||||||
|
var x_sampled: SampledAxis = SampledAxis.new()
|
||||||
|
var y_sampled: SampledAxis = SampledAxis.new()
|
||||||
|
|
||||||
#
|
#
|
||||||
var x_scale: float = 5.0
|
var x_scale: float = 5.0
|
||||||
var y_scale: float = 5.0
|
var y_scale: float = 2.0
|
||||||
|
|
||||||
|
|
||||||
###### STYLE
|
###### STYLE
|
||||||
var drawing_options: DrawingOptions = DrawingOptions.new()
|
var drawing_options: DrawingOptions = DrawingOptions.new()
|
||||||
|
var chart_properties: ChartProperties = ChartProperties.new()
|
||||||
|
|
||||||
#### INTERNAL
|
#### INTERNAL
|
||||||
# The bounding_box of the chart
|
# The bounding_box of the chart
|
||||||
@ -23,21 +26,74 @@ var bounding_box: Rect2
|
|||||||
|
|
||||||
# The Reference Rectangle to plot samples
|
# The Reference Rectangle to plot samples
|
||||||
# It is the @bounding_box Rectangle inverted on the Y axis
|
# It is the @bounding_box Rectangle inverted on the Y axis
|
||||||
var ref_x: Pair
|
var x_sampled_domain: Pair
|
||||||
var ref_y: Pair
|
var y_sampled_domain: Pair
|
||||||
var ref_rect: Rect2
|
var sampled_domain_rect: Rect2
|
||||||
|
|
||||||
var _padding_offset: Vector2 = Vector2(70.0, 70.0)
|
var _padding_offset: Vector2 = Vector2(20.0, 20.0)
|
||||||
var _internal_offset: Vector2 = Vector2(15.0, 15.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
|
||||||
|
|
||||||
|
|
||||||
var point_container_scene: PackedScene = preload("res://addons/easy_charts/utilities/containers/point_container/point_container.tscn")
|
var point_container_scene: PackedScene = preload("res://addons/easy_charts/utilities/containers/point_container/point_container.tscn")
|
||||||
|
|
||||||
|
|
||||||
###########
|
###########
|
||||||
func plot(x: Array, y: Array) -> void:
|
func plot(x: Array, y: Array, drawing_options: DrawingOptions = DrawingOptions.new(), chart_properties: ChartProperties = ChartProperties.new()) -> void:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
func _sample_values(values: Array, ref_values: Pair) -> SampledAxis:
|
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 abs(fmod(val, 1)) > 0.0:
|
||||||
|
return true
|
||||||
|
else:
|
||||||
|
for val in temp:
|
||||||
|
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():
|
if values.empty():
|
||||||
printerr("Trying to plot an empty dataset!")
|
printerr("Trying to plot an empty dataset!")
|
||||||
return SampledAxis.new()
|
return SampledAxis.new()
|
||||||
@ -55,65 +111,126 @@ func _sample_values(values: Array, ref_values: Pair) -> SampledAxis:
|
|||||||
|
|
||||||
var rels: Array = []
|
var rels: Array = []
|
||||||
if temp[0] is Array:
|
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()
|
|
||||||
|
|
||||||
for t_dim in temp:
|
for t_dim in temp:
|
||||||
var rels_t: Array = []
|
var rels_t: Array = []
|
||||||
for val in t_dim:
|
for val in t_dim:
|
||||||
rels_t.append(range_lerp(val, _min, _max, ref_values.left, ref_values.right))
|
rels_t.append(_map_pair(val, rel_values, ref_values))
|
||||||
rels.append(rels_t)
|
rels.append(rels_t)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
_min = temp.min()
|
|
||||||
_max = temp.max()
|
|
||||||
|
|
||||||
for val in temp:
|
for val in temp:
|
||||||
rels.append(range_lerp(val, _min, _max, ref_values.left, ref_values.right))
|
rels.append(_map_pair(val, rel_values, ref_values))
|
||||||
|
|
||||||
return SampledAxis.new(rels, Pair.new(_min, _max))
|
return SampledAxis.new(rels, rel_values)
|
||||||
|
|
||||||
func _pre_process() -> void:
|
|
||||||
|
func _pre_process_drawings() -> void:
|
||||||
var t_gr: Rect2 = get_global_rect()
|
var t_gr: Rect2 = get_global_rect()
|
||||||
|
|
||||||
# node box
|
#### @node_box size, which is the whole "frame"
|
||||||
node_box = Rect2(Vector2.ZERO, t_gr.size - t_gr.position)
|
node_box = Rect2(Vector2.ZERO, t_gr.size - t_gr.position)
|
||||||
|
|
||||||
# bounding_box
|
#### drawing size for defining @bounding_box
|
||||||
|
x_min_max = _find_min_max(x)
|
||||||
|
y_min_max = _find_min_max(y)
|
||||||
|
|
||||||
|
#### calculating offset from the @node_box for the @bounding_box.
|
||||||
|
var offset: Vector2 = _padding_offset
|
||||||
|
|
||||||
|
### if @labels drawing is enabled, calcualte offsets
|
||||||
|
if drawing_options.labels:
|
||||||
|
### labels (X, Y, Title)
|
||||||
|
_x_label_size = drawing_options.font.get_string_size(chart_properties.x_label)
|
||||||
|
_y_label_size = drawing_options.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 Y axis.
|
||||||
|
# remember that "-" sign adds additional pixels, and it is relative only to negative numbers!
|
||||||
|
var x_max_formatted: String = ("%.2f" if x_has_decimals else "%s") % x_min_max.right
|
||||||
|
_x_ticklabel_size = drawing_options.font.get_string_size(x_max_formatted)
|
||||||
|
|
||||||
|
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_min_max.right
|
||||||
|
if y_min_max.left < 0:
|
||||||
|
# negative number
|
||||||
|
var y_min_formatted: String = ("%.2f" if y_has_decimals else "%s") % y_min_max.left
|
||||||
|
if y_min_formatted.length() >= y_max_formatted.length():
|
||||||
|
_y_ticklabel_size = drawing_options.font.get_string_size(y_min_formatted)
|
||||||
|
else:
|
||||||
|
_y_ticklabel_size = drawing_options.font.get_string_size(y_max_formatted)
|
||||||
|
else:
|
||||||
|
_y_ticklabel_size = drawing_options.font.get_string_size(y_max_formatted)
|
||||||
|
|
||||||
|
offset.x += _y_label_offset + _y_label_size.y + _y_ticklabel_offset + _y_ticklabel_size.x
|
||||||
|
|
||||||
|
### if @ticks drawing is enabled, calculate offsets
|
||||||
|
if drawing_options.ticks:
|
||||||
|
offset.x += _y_tick_size
|
||||||
|
offset.y += _x_tick_size
|
||||||
|
|
||||||
|
### @bounding_box, where the points will be plotted
|
||||||
bounding_box = Rect2(
|
bounding_box = Rect2(
|
||||||
Vector2.ZERO + _padding_offset,
|
offset,
|
||||||
t_gr.size - t_gr.position - (_padding_offset*2)
|
t_gr.size - (offset * 2)
|
||||||
)
|
)
|
||||||
|
|
||||||
# reference rectangle
|
### @sampled_domain, which are the domain relative to the sampled values
|
||||||
ref_x = Pair.new(bounding_box.position.x + _internal_offset.x, bounding_box.position.x + bounding_box.size.x - _internal_offset.y)
|
### x (real value) --> sampling --> x_sampled (pixel value in canvas)
|
||||||
ref_y = Pair.new(bounding_box.size.y + bounding_box.position.y - _internal_offset.x, bounding_box.position.y + _internal_offset.y)
|
x_sampled_domain = Pair.new(bounding_box.position.x + _internal_offset.x, bounding_box.position.x + bounding_box.size.x - _internal_offset.y)
|
||||||
ref_rect = Rect2(
|
y_sampled_domain = Pair.new(bounding_box.size.y + bounding_box.position.y - _internal_offset.x, bounding_box.position.y + _internal_offset.y)
|
||||||
Vector2(ref_x.left, ref_y.left),
|
sampled_domain_rect = Rect2(
|
||||||
Vector2(ref_x.right, ref_y.right)
|
Vector2(x_sampled_domain.left, y_sampled_domain.left),
|
||||||
|
Vector2(x_sampled_domain.right, y_sampled_domain.right)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func _pre_process_sampling() -> void:
|
||||||
|
|
||||||
# samples
|
# samples
|
||||||
x_sampled = _sample_values(x, ref_x)
|
x_sampled = _sample_values(x, x_min_max, x_sampled_domain)
|
||||||
y_sampled = _sample_values(y, ref_y)
|
y_sampled = _sample_values(y, y_min_max, y_sampled_domain)
|
||||||
|
|
||||||
|
func _pre_process() -> void:
|
||||||
|
_pre_process_drawings()
|
||||||
|
_pre_process_sampling()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func _draw_points() -> void:
|
||||||
|
pass
|
||||||
|
|
||||||
func _draw_borders() -> void:
|
func _draw_borders() -> void:
|
||||||
draw_rect(node_box, Color.red, false, 1, true)
|
draw_rect(node_box, Color.red, false, 1, true)
|
||||||
|
|
||||||
func _draw_bounding_box() -> void:
|
func _draw_bounding_box() -> void:
|
||||||
draw_rect(bounding_box, drawing_options.colors.bounding_box, false, 1, true)
|
draw_rect(bounding_box, drawing_options.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:
|
||||||
func _draw_points() -> void:
|
var xorigin: float = _map_pair(0.0, x_min_max, x_sampled_domain)
|
||||||
pass
|
var yorigin: float = _map_pair(0.0, y_min_max, 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(drawing_options.font, Vector2(xorigin, yorigin) - Vector2(15, -15), "O", drawing_options.colors.bounding_box)
|
||||||
|
|
||||||
func _draw_background() -> void:
|
func _draw_background() -> void:
|
||||||
draw_rect(node_box, Color.white, true, 1.0, false)
|
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_grid() -> void:
|
func _draw_grid() -> void:
|
||||||
var validation: int = _validate_sampled_axis(x_sampled, y_sampled)
|
var validation: int = _validate_sampled_axis(x_sampled, y_sampled)
|
||||||
@ -126,90 +243,142 @@ func _draw_grid() -> void:
|
|||||||
for _x in x_scale+1:
|
for _x in x_scale+1:
|
||||||
var x_val: float = _x * v_lines + x_sampled.min_max.left
|
var x_val: float = _x * v_lines + x_sampled.min_max.left
|
||||||
var p1: Vector2 = Vector2(
|
var p1: Vector2 = Vector2(
|
||||||
range_lerp(x_val, x_sampled.min_max.left, x_sampled.min_max.right, ref_x.left, ref_x.right),
|
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
|
bounding_box.position.y
|
||||||
)
|
)
|
||||||
var p2: Vector2 = Vector2(
|
var p2: Vector2 = Vector2(
|
||||||
range_lerp(x_val, x_sampled.min_max.left, x_sampled.min_max.right, ref_x.left, ref_x.right),
|
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
|
bounding_box.size.y + bounding_box.position.y
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Draw V labels
|
||||||
|
if drawing_options.labels:
|
||||||
|
var tick_lbl: String = ("%.2f" if x_has_decimals else "%s") % x_val
|
||||||
|
|
||||||
|
draw_string(
|
||||||
|
drawing_options.font,
|
||||||
|
p2 + Vector2(
|
||||||
|
- drawing_options.font.get_string_size(tick_lbl).x / 2,
|
||||||
|
_x_label_size.y + _x_tick_size
|
||||||
|
),
|
||||||
|
tick_lbl,
|
||||||
|
drawing_options.colors.bounding_box
|
||||||
|
)
|
||||||
|
|
||||||
|
# Draw V Ticks
|
||||||
|
if drawing_options.ticks:
|
||||||
|
draw_line(p2, p2 + Vector2(0, _x_tick_size), drawing_options.colors.bounding_box, 1, true)
|
||||||
|
|
||||||
# Draw V Grid Lines
|
# Draw V Grid Lines
|
||||||
if drawing_options.grid:
|
if drawing_options.grid:
|
||||||
draw_line(p1, p2, drawing_options.colors.grid, 1, true)
|
draw_line(p1, p2, drawing_options.colors.grid, 1, true)
|
||||||
|
|
||||||
# Draw V Ticks
|
|
||||||
if drawing_options.ticks:
|
|
||||||
p1.y = p2.y
|
|
||||||
p2.y += 8.0
|
|
||||||
draw_line(p1, p2, drawing_options.colors.bounding_box, 1, true)
|
|
||||||
|
|
||||||
# Draw V labels
|
|
||||||
if drawing_options.labels:
|
|
||||||
draw_string(
|
|
||||||
drawing_options.font,
|
|
||||||
p2 + Vector2(-drawing_options.font.get_string_size(str(x_val)).x * 0.5, 15.0),
|
|
||||||
str(x_val),
|
|
||||||
drawing_options.colors.bounding_box
|
|
||||||
)
|
|
||||||
|
|
||||||
# draw horizontal lines
|
# draw horizontal lines
|
||||||
var h_lines: float = (y_sampled.min_max.right - y_sampled.min_max.left) / y_scale
|
var h_lines: float = (y_sampled.min_max.right - y_sampled.min_max.left) / y_scale
|
||||||
for _y in y_scale+1:
|
for _y in y_scale+1:
|
||||||
var y_val: float = _y * h_lines + y_sampled.min_max.left
|
var y_val: float = _y * h_lines + y_sampled.min_max.left
|
||||||
var p1: Vector2 = Vector2(
|
var p1: Vector2 = Vector2(
|
||||||
bounding_box.position.x,
|
bounding_box.position.x,
|
||||||
range_lerp(y_val, y_sampled.min_max.left, y_sampled.min_max.right, ref_y.left, ref_y.right)
|
range_lerp(y_val, y_sampled.min_max.left, y_sampled.min_max.right, y_sampled_domain.left, y_sampled_domain.right)
|
||||||
)
|
)
|
||||||
var p2: Vector2 = Vector2(
|
var p2: Vector2 = Vector2(
|
||||||
bounding_box.size.x + bounding_box.position.x,
|
bounding_box.size.x + bounding_box.position.x,
|
||||||
range_lerp(y_val, y_sampled.min_max.left, y_sampled.min_max.right, ref_y.left, ref_y.right)
|
range_lerp(y_val, y_sampled.min_max.left, y_sampled.min_max.right, y_sampled_domain.left, y_sampled_domain.right)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Draw H labels
|
||||||
|
if drawing_options.labels:
|
||||||
|
var tick_lbl: String = ("%.2f" if y_has_decimals else "%s") % y_val
|
||||||
|
var tick_lbl_size: Vector2 = drawing_options.font.get_string_size(tick_lbl)
|
||||||
|
|
||||||
|
draw_string(
|
||||||
|
drawing_options.font,
|
||||||
|
p1 - Vector2(tick_lbl_size.x + _y_ticklabel_offset + _y_tick_size, - _y_ticklabel_size.y * 0.35),
|
||||||
|
tick_lbl,
|
||||||
|
drawing_options.colors.bounding_box
|
||||||
|
)
|
||||||
|
|
||||||
|
# Draw H Ticks
|
||||||
|
if drawing_options.ticks:
|
||||||
|
draw_line(
|
||||||
|
p1,
|
||||||
|
p1 - Vector2(_y_tick_size, 0),
|
||||||
|
drawing_options.colors.bounding_box, 1, true)
|
||||||
|
|
||||||
# Draw H Grid Lines
|
# Draw H Grid Lines
|
||||||
if drawing_options.grid:
|
if drawing_options.grid:
|
||||||
draw_line(p1, p2, drawing_options.colors.grid, 1, true)
|
draw_line(p1, p2, drawing_options.colors.grid, 1, true)
|
||||||
|
|
||||||
# Draw H Ticks
|
|
||||||
if drawing_options.ticks:
|
|
||||||
p2.x = p1.x - 8.0
|
|
||||||
draw_line(p1, p2, drawing_options.colors.bounding_box, 1, true)
|
|
||||||
|
|
||||||
# Draw H labels
|
|
||||||
if drawing_options.labels:
|
|
||||||
draw_string(
|
|
||||||
drawing_options.font,
|
|
||||||
p2 - Vector2(drawing_options.font.get_string_size(str(y_val)).x + 5.0, -drawing_options.font.get_string_size(str(y_val)).y * 0.35),
|
|
||||||
str(y_val),
|
|
||||||
drawing_options.colors.bounding_box
|
|
||||||
)
|
|
||||||
|
|
||||||
|
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", drawing_options.font)
|
||||||
|
lbl.set_text(text)
|
||||||
|
lbl.modulate = drawing_options.colors.bounding_box
|
||||||
|
lbl.rect_rotation = rotation
|
||||||
|
lbl.rect_position = position
|
||||||
|
return lbl
|
||||||
|
|
||||||
|
func _draw_yaxis_label() -> void:
|
||||||
|
_create_canvas_label(
|
||||||
|
chart_properties.y_label,
|
||||||
|
Vector2(_padding_offset.x, (node_box.size.y / 2) + (_y_label_size.x / 2)),
|
||||||
|
-90
|
||||||
|
)
|
||||||
|
|
||||||
|
func _draw_xaxis_label() -> void:
|
||||||
|
_create_canvas_label(
|
||||||
|
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:
|
||||||
|
_create_canvas_label(
|
||||||
|
chart_properties.title,
|
||||||
|
Vector2(node_box.size.x / 2, _padding_offset.y*2) - (drawing_options.font.get_string_size(chart_properties.title) / 2)
|
||||||
|
)
|
||||||
|
|
||||||
func _clear_points() -> void:
|
func _clear_points() -> void:
|
||||||
for point in $Points.get_children():
|
for point in $Points.get_children():
|
||||||
point.queue_free()
|
point.queue_free()
|
||||||
|
|
||||||
|
func _clear_canvas_labels() -> void:
|
||||||
|
for label in $Canvas.get_children():
|
||||||
|
label.queue_free()
|
||||||
|
|
||||||
func _clear() -> void:
|
func _clear() -> void:
|
||||||
_clear_points()
|
_clear_points()
|
||||||
|
_clear_canvas_labels()
|
||||||
|
|
||||||
func _draw():
|
func _draw():
|
||||||
|
_clear()
|
||||||
|
_pre_process()
|
||||||
|
|
||||||
if drawing_options.background:
|
if drawing_options.background:
|
||||||
_draw_background()
|
_draw_background()
|
||||||
|
|
||||||
if drawing_options.borders:
|
if drawing_options.borders:
|
||||||
_draw_borders()
|
_draw_borders()
|
||||||
|
|
||||||
|
if drawing_options.labels:
|
||||||
|
_draw_xaxis_label()
|
||||||
|
_draw_yaxis_label()
|
||||||
|
_draw_title()
|
||||||
|
|
||||||
if drawing_options.grid or drawing_options.ticks or drawing_options.labels:
|
if drawing_options.grid or drawing_options.ticks or drawing_options.labels:
|
||||||
_draw_grid()
|
_draw_grid()
|
||||||
|
|
||||||
if drawing_options.bounding_box:
|
if drawing_options.bounding_box:
|
||||||
_draw_bounding_box()
|
_draw_bounding_box()
|
||||||
|
|
||||||
|
if drawing_options.origin:
|
||||||
|
_draw_origin()
|
||||||
|
|
||||||
if drawing_options.points:
|
if drawing_options.points:
|
||||||
_draw_points()
|
_draw_points()
|
||||||
|
|
||||||
# if drawing_options.labels:
|
|
||||||
# _draw_labels()
|
|
||||||
|
|
||||||
func _validate_sampled_axis(x_data: SampledAxis, y_data: SampledAxis) -> int:
|
func _validate_sampled_axis(x_data: SampledAxis, y_data: SampledAxis) -> int:
|
||||||
var error: int = 0 # OK
|
var error: int = 0 # OK
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
extends Reference
|
||||||
|
class_name ChartProperties
|
||||||
|
|
||||||
|
var title: String
|
||||||
|
var x_label: String
|
||||||
|
var y_label: String
|
@ -8,13 +8,20 @@ var background: bool = true
|
|||||||
var borders: bool = false
|
var borders: bool = false
|
||||||
var ticks: bool = true
|
var ticks: bool = true
|
||||||
var labels: bool = true
|
var labels: bool = true
|
||||||
|
var origin: bool = true
|
||||||
|
|
||||||
var colors: Dictionary = {
|
var colors: Dictionary = {
|
||||||
bounding_box = Color.black,
|
bounding_box = Color.black,
|
||||||
grid = Color.gray,
|
grid = Color.gray,
|
||||||
functions = [Color.red, Color.green, Color.blue]
|
functions = [Color.red, Color.green, Color.blue, Color.black]
|
||||||
}
|
}
|
||||||
|
|
||||||
var shapes: Array = [PointContainer.PointShape.CIRCLE, PointContainer.PointShape.SQUARE, PointContainer.PointShape.SQUARE]
|
var shapes: Array = [PointContainer.PointShape.CIRCLE, PointContainer.PointShape.SQUARE, PointContainer.PointShape.TRIANGLE, PointContainer.PointShape.CROSS]
|
||||||
var point_radius: float = 3.0
|
var point_radius: float = 3.0
|
||||||
var font: Font = Label.new().get_font("")
|
var font: BitmapFont = Label.new().get_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 PointContainer.PointShape.CIRCLE
|
||||||
|
@ -49,6 +49,25 @@ func _draw_point() -> void:
|
|||||||
draw_circle(point_rel_pos, self.radius, self.color)
|
draw_circle(point_rel_pos, self.radius, self.color)
|
||||||
PointShape.SQUARE:
|
PointShape.SQUARE:
|
||||||
draw_rect(Rect2(point_rel_pos * 0.5, point_rel_pos), self.color, true, 1.0, false)
|
draw_rect(Rect2(point_rel_pos * 0.5, point_rel_pos), self.color, true, 1.0, false)
|
||||||
|
PointShape.TRIANGLE:
|
||||||
|
draw_colored_polygon(
|
||||||
|
PoolVector2Array([
|
||||||
|
point_rel_pos + (Vector2.UP * self.radius * 1.5),
|
||||||
|
point_rel_pos + (Vector2.ONE * self.radius * 1.5),
|
||||||
|
point_rel_pos - (Vector2(1, -1) * self.radius * 1.5)
|
||||||
|
]), self.color, [], null, null, false
|
||||||
|
)
|
||||||
|
PointShape.CROSS:
|
||||||
|
draw_line(
|
||||||
|
point_rel_pos - (Vector2.ONE * self.radius),
|
||||||
|
point_rel_pos + (Vector2.ONE * self.radius),
|
||||||
|
self.color, self.radius, true
|
||||||
|
)
|
||||||
|
draw_line(
|
||||||
|
point_rel_pos + (Vector2(1, -1) * self.radius),
|
||||||
|
point_rel_pos + (Vector2(-1, 1) * self.radius),
|
||||||
|
self.color, self.radius / 2, true
|
||||||
|
)
|
||||||
|
|
||||||
func _draw():
|
func _draw():
|
||||||
# _draw_bounding_box()
|
# _draw_bounding_box()
|
||||||
|
Loading…
Reference in New Issue
Block a user