immersive-home/app/content/ui/components/line_chart/line_chart.gd
2024-04-10 20:23:19 +02:00

89 lines
1.9 KiB
GDScript

@tool
extends Node3D
@onready var mesh: MeshInstance3D = $Line
@onready var plane: MeshInstance3D = $Plane
@onready var x_axis: Sprite3D = $XAxis
const RADIUS = 0.005
const STEPS = 5
@export var size: Vector2 = Vector2(0.5, 0.3)
var points = R.state([])
var minmax = R.computed(func(_arg):
if points.value.size() == 0:
return [Vector2(0, 0), Vector2(0, 0)]
var min=points.value[0]
var max=points.value[0]
for point in points.value:
min.x=min(min.x, point.x)
min.y=min(min.y, point.y)
max.x=max(max.x, point.x)
max.y=max(max.y, point.y)
return [min, max]
)
var relative_points = R.computed(func(_arg):
var min=minmax.value[0]
var max=minmax.value[1]
return points.value.map(func(point):
return Vector2(inverse_lerp(min.x, max.x, point.x), inverse_lerp(min.y, max.y, point.y))
)
)
func _ready():
for i in range(100):
points.value.append(Vector2(i, sin(i / 10.0)))
R.effect(func(_arg):
mesh.mesh=generate_mesh(relative_points.value)
)
plane.position = Vector3(size.x / 2, size.y / 2, -0.001)
plane.mesh.size = size
func generate_mesh(points: Array):
if points.size() < 2:
return null
var sf = SurfaceTool.new()
sf.begin(Mesh.PRIMITIVE_TRIANGLE_STRIP)
for i in range(points.size() - 1):
var point = points[i]
var next_point = points[i + 1]
var angle = (next_point - point).angle_to(Vector2(1, 0))
var up = Vector2(0, 1).rotated( - angle)
var p0 = point + up * RADIUS * 2
var p1 = point + up * - RADIUS * 2
sf.add_vertex(Vector3(p0.x * size.x, p0.y * size.y, 0))
sf.add_vertex(Vector3(p1.x * size.x, p1.y * size.y, 0))
sf.index()
sf.generate_normals()
var _mesh = sf.commit()
sf.clear()
sf.begin(Mesh.PRIMITIVE_TRIANGLE_STRIP)
for i in range(points.size() - 1):
var point = points[i]
sf.add_vertex(Vector3(point.x * size.x, point.y * size.y, RADIUS))
sf.add_vertex(Vector3(point.x * size.x, point.y * size.y, -RADIUS))
return sf.commit(_mesh)