Created
September 30, 2025 20:21
-
-
Save Mithradates528/0ea694291cc2e447ce4de9181671f15e to your computer and use it in GitHub Desktop.
Pie Chart - Godot 3.5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| extends Node2D | |
| # Data for the pie chart | |
| export var data := [ | |
| {"Name":"Trade", "value": 8.0, "color": Color.burlywood}, | |
| {"Name":"Pupets", "value": 16.0, "color": Color.deeppink}, | |
| {"Name":"Production", "value": 26.0, "color": Color.greenyellow}, | |
| {"Name":"Taxes", "value": 35.0, "color": Color.aqua}, | |
| {"Name":"Occupation", "value": 50.0, "color": Color.cornflower} | |
| ] | |
| # Chart properties | |
| export var radius = 200 | |
| export var center = Vector2(400, 400) | |
| # Animation properties | |
| export var animation_duration = 1.0 # Duration in seconds | |
| export var animation_time = 0.0 | |
| export var is_animating = true | |
| # Customizable properties | |
| var font: Font | |
| export var font_size = 15 | |
| export var line_width = 3.0 | |
| export var line_color = Color(1, 1, 1) | |
| export var use_gradient = false | |
| export var gradient_start_color = Color(0.8, 0.2, 0.2) | |
| export var gradient_end_color = Color(0.2, 0.2, 0.8) | |
| # Hover properties | |
| var hovered_slice = -1 | |
| var hover_scale = 1.1 | |
| var hover_animation_speed = 0.2 | |
| var current_hover_scale = 1.0 | |
| func _ready(): | |
| # Set up custom font | |
| font = DynamicFont.new() | |
| font.font_data = load("res://") | |
| font.size = font_size | |
| font.use_mipmaps = true | |
| font.use_filter = true | |
| set_process(true) | |
| update() | |
| export var UpdateInRealTime := false | |
| func _process(delta): | |
| if is_animating: | |
| animation_time += delta | |
| if animation_time >= animation_duration: | |
| animation_time = animation_duration | |
| is_animating = false | |
| font.size = 15 | |
| update() | |
| elif UpdateInRealTime: | |
| update_data(data) | |
| # Handle hover animation | |
| var target_scale = 1.0 | |
| if hovered_slice != -1: | |
| target_scale = hover_scale | |
| current_hover_scale = lerp(current_hover_scale, target_scale, hover_animation_speed) | |
| if abs(current_hover_scale - target_scale) > 0.01: | |
| update() | |
| func _draw(): | |
| var total = 0.00001 | |
| for item in data: | |
| total += item.value | |
| var current_angle = -PI/2 # Start from the top | |
| var animation_progress = animation_time / animation_duration | |
| for i in range(data.size()): | |
| var item = data[i] | |
| var full_angle = (item.value / total) * PI * 2 | |
| var current_slice_angle = full_angle * animation_progress | |
| # Calculate scale for hover effect | |
| var scale = 1.0 | |
| if i == hovered_slice: | |
| scale = current_hover_scale | |
| draw_slice(current_angle, current_slice_angle, item.color, scale, i, item.value, total) | |
| # Draw labels | |
| if animation_progress > 0.5: # Only show labels after animation is halfway | |
| var label_angle = current_angle + (current_slice_angle / 2) | |
| var OPRM = 1.15 | |
| var inner_point = center + Vector2(cos(label_angle), sin(label_angle)) * (radius * 1.05) | |
| var outer_point = center + Vector2(cos(label_angle), sin(label_angle)) * (radius * OPRM) | |
| # Determine which side of the pie we're on to align text | |
| var is_right_side = cos(label_angle) > 0 | |
| # Draw connecting line | |
| # draw_line(inner_point, outer_point, item.color, 2) | |
| # Calculate the horizontal line endpoint | |
| var horizontal_offset = 0 * (1 if is_right_side else -1) | |
| var horizontal_point = Vector2(outer_point.x + horizontal_offset, outer_point.y) | |
| # Draw percentage text | |
| var percentage = str(round(float((item.value / total) * 100)) + (0 if data.find(data[i]) != (data.size()-1) else 1) | |
| ) + "%" | |
| var text_position = horizontal_point | |
| if is_right_side: | |
| text_position.x += 5 # Add small padding for right-aligned text | |
| else: | |
| text_position.x -= font.get_string_size(percentage).x + 5 # Left-align text | |
| text_position = Vector2(text_position.x, text_position.y + 6) | |
| if int(percentage) != 0: | |
| draw_string(font, text_position, percentage, item.color) | |
| current_angle += current_slice_angle | |
| func draw_slice(start_angle: float, angle: float, color: Color, scale: float = 1.0, slice_index: int = -1, Value := 1, Total := 1): | |
| var points = PoolVector2Array() | |
| points.push_back(center) | |
| if Value == 0 || Total == 0: | |
| return | |
| var nb_points = round(max(float(32) / (float(Total) / (float(Value)*1.44)),3)) | |
| for i in range(nb_points + 1): | |
| var angle_point = start_angle + i * angle / nb_points | |
| var point = center + Vector2(cos(angle_point), sin(angle_point)) * (radius * scale) | |
| points.push_back(point) | |
| # Draw filled slice | |
| var slice_color = color | |
| if use_gradient: | |
| var gradient = Gradient.new() | |
| gradient.add_point(0.0, gradient_start_color) | |
| gradient.add_point(1.0, gradient_end_color) | |
| slice_color = gradient.interpolate(float(slice_index) / (data.size() - 1)) | |
| draw_colored_polygon(points, slice_color,PoolVector2Array(),null,null,true) | |
| # Draw border lines | |
| if line_width > 0: | |
| # Draw outer arc | |
| for i in range(nb_points): | |
| var start_point = points[i + 1] | |
| var end_point = points[i + 2] | |
| draw_line(start_point, end_point, line_color, line_width, true) | |
| # Draw lines to center | |
| draw_line(points[1], center, line_color, line_width, true) | |
| draw_line(points[points.size() - 1], center, line_color, line_width, true) | |
| func _input(event): | |
| if event is InputEventMouse: | |
| var mouse_pos = event.position | |
| check_hover(mouse_pos) | |
| func check_hover(mouse_pos: Vector2): | |
| var total = 0.0 | |
| for item in data: | |
| total += item.value | |
| var current_angle = -PI/2 | |
| var found_hover = false | |
| var previous_hover = hovered_slice # Store the previous hover state | |
| for i in range(data.size()): | |
| var item = data[i] | |
| var angle = (item.value / max(total,1)) * PI * 2 | |
| # Check if mouse is within this slice | |
| var distance = mouse_pos.distance_to(center) | |
| if distance <= radius: | |
| var mouse_angle = (mouse_pos - center).angle() | |
| # Normalize angle to be between -PI/2 and 3PI/2 | |
| if mouse_angle < -PI/2: | |
| mouse_angle += PI * 2 | |
| var slice_start = current_angle | |
| var slice_end = current_angle + angle | |
| if mouse_angle >= slice_start and mouse_angle < slice_end: | |
| if hovered_slice != i: | |
| hovered_slice = i | |
| found_hover = true | |
| break | |
| current_angle += angle | |
| if !found_hover: | |
| hovered_slice = -1 | |
| # Force update if we changed hover states | |
| if previous_hover != hovered_slice: | |
| current_hover_scale = 1.0 # Reset scale when changing slices | |
| update() | |
| # Configuration functions | |
| func set_font(new_font: Font): | |
| font = new_font | |
| update() | |
| func set_font_size(size: int): | |
| font_size = size | |
| if font: | |
| font.size = font_size | |
| update() | |
| func set_line_properties(width: float, color: Color): | |
| line_width = width | |
| line_color = color | |
| update() | |
| func set_gradient_colors(start_color: Color, end_color: Color): | |
| gradient_start_color = start_color | |
| gradient_end_color = end_color | |
| update() | |
| func toggle_gradient(enabled: bool): | |
| use_gradient = enabled | |
| update() | |
| func update_data(new_data): | |
| data = new_data | |
| is_animating = true | |
| animation_time = 0.0 | |
| update() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment