pandemonium_engine_easy_charts/addons/easy_charts/PieChart/pie_chart.gd
Nicolò Santilio 624662e8a2
Update 0.4.1
- bugfix
- added PieChart
- implemented real time plotting
- implemented array plotting
2020-11-06 19:32:11 +01:00

220 lines
6.0 KiB
GDScript

tool
extends Chart
var should_draw : bool = false
var area_angles : Array
var slices : Array
var areas : Array
var areas_interacted : Array
class CustomSorter:
static func sort_ascending(a,b):
if a[1] < b[1]:
return true
return false
func _get_property_list():
return [
# Chart Properties
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Properties/are_values_columns",
"type": TYPE_BOOL
},
{
"hint": PROPERTY_HINT_RANGE,
"hint_string": "-1,100,1",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Properties/labels_index",
"type": TYPE_INT
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Properties/show_x_values_as_labels",
"type": TYPE_BOOL
},
# Chart Style
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/function_colors",
"type": TYPE_COLOR_ARRAY
},
{
"class_name": "Font",
"hint": PROPERTY_HINT_RESOURCE_TYPE,
"hint_string": "Font",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/font",
"type": TYPE_OBJECT
},
{
"class_name": "Font",
"hint": PROPERTY_HINT_RESOURCE_TYPE,
"hint_string": "Font",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/bold_font",
"type": TYPE_OBJECT
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/font_color",
"type": TYPE_COLOR
},
{
"hint": PROPERTY_HINT_ENUM,
"hint_string": PoolStringArray(TemplatesNames.keys()).join(","),
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/template",
"type": TYPE_INT
},
# Chart Modifiers
{
"hint": PROPERTY_HINT_RANGE,
"hint_string": "0,360",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Modifiers/rotation",
"type": TYPE_REAL
},
]
# Called when the node enters the scene tree for the first time.
func _ready():
pass
func plot_placeholder() -> void:
datas = [
["United States",46],
["Great Britain",27],
["China",26],
["Russia",19],
["Germany",17]
]
function_colors = [
Color.red,
Color.white,
Color.yellow,
Color.green,
Color.blue
]
plot_from_array(datas)
func structure_datas(database: Array, are_values_columns: bool, x_values_index: int):
# @x_values_index can be either a column or a row relative to x values
clean_variables()
self.are_values_columns = are_values_columns
if are_values_columns:
for row in database.size():
var t_vals: Array
for column in database[row].size():
if column == x_values_index:
var x_data = database[row][column]
if x_data.is_valid_float() or x_data.is_valid_integer():
x_datas.append(x_data as float)
else:
x_datas.append(x_data.replace(",", ".") as float)
else:
if row != 0:
var y_data = database[row][column]
if y_data.is_valid_float() or y_data.is_valid_integer():
t_vals.append(y_data as float)
else:
t_vals.append(y_data.replace(",", ".") as float)
else:
y_labels.append(str(database[row][column]))
if not t_vals.empty():
y_datas.append(t_vals)
x_label = str(x_datas.pop_front())
else:
for row in database.size():
if row == x_values_index:
x_datas = (database[row])
x_label = x_datas.pop_front() as String
else:
var values = database[row] as Array
y_labels.append(values.pop_front() as String)
y_datas.append(values)
for data in y_datas:
for value in data.size():
data[value] = data[value] as float
func build_chart():
SIZE = get_size()
origin = SIZE/2
radius = (SIZE.y/2 - 20) if SIZE.y < SIZE.x else (SIZE.x/2 - 20)
func calculate_pass():
var tot : float
for y_data in y_datas: tot+=y_data[0]
x_pass = 360/tot
func calculate_coordinates():
area_angles.clear()
slices.clear()
areas.clear()
var from : float = 0.0
var to : float = y_datas[0][0]*x_pass
area_angles.append([from,to])
for info in range(y_datas.size()):
slices.append(Slice.new(y_labels[info], str(y_datas[info][0]), from, to, x_label+" : "+x_datas[0], function_colors[info]))
areas.append(calculate_circle_arc_polygon(origin, radius, from + rotation, to + rotation, function_colors[info]))
from = to
to = (y_datas[info+1][0]*x_pass + from) if info < y_datas.size()-1 else (360)
area_angles.append([from, to])
create_legend()
func calculate_circle_arc_polygon(center : Vector2, radius : float, angle_from : float, angle_to : float, color : Color) -> PoolVector2Array:
var nb_points : int = 32
var points_arc : PoolVector2Array = PoolVector2Array()
points_arc.push_back(center)
var colors : PoolColorArray = PoolColorArray([color])
for i in range(nb_points + 1):
var angle_point = deg2rad(angle_from + i * (angle_to - angle_from) / nb_points - 90)
points_arc.push_back(center + Vector2(cos(angle_point), sin(angle_point)) * radius)
return points_arc
func _draw():
_draw_areas()
if mouse_on_slice:
_draw_arc(area_angles[mouse_on_area], mouse_on_area)
mouse_on_slice = false
func _draw_arc(arc : Array, index : int):
var temp_color : Color = function_colors[index]
temp_color.a = 0.7
draw_arc(origin, radius + 6, deg2rad(arc[0]-90 + rotation), deg2rad(arc[1]-90 + rotation), 32, temp_color, 4)
func _draw_areas():
for area_idx in range(areas.size()):
draw_polygon(areas[area_idx], [function_colors[area_idx]])
var mouse_on_area : int
var mouse_on_slice : bool = false
func _input(event):
if event is InputEventMouseMotion:
for area_idx in range(areas.size()):
if Geometry.is_point_in_polygon(event.global_position, areas[area_idx]):
mouse_on_slice = true
mouse_on_area = area_idx
show_slice_data(slices[area_idx])
update()
if not mouse_on_slice:
mouse_on_area = -1
mouse_on_slice = false
hide_data()
update()