// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
let element_cache : Map[String, @dom.HTMLImageElement] = Map::new()
///|
fn get_image_element(png : String) -> @dom.HTMLImageElement {
if element_cache.get(png) is Some(element) {
return element
}
let element = @dom.HTMLImageElement::new()
element.set_src(png)
element_cache.set(png, element)
return element
}
///|
pub fn preload_img(path : String) -> Unit {
get_image_element(path) |> ignore
}
///|
pub fn draw_picture(
png~ : String,
x~ : Double,
y~ : Double,
width~ : Double,
height~ : Double,
transform~ : @smath.Transform,
repeat~ : @smath.RepeatMode,
) -> Unit {
let element = get_image_element(png)
let repeat_mode = match repeat {
NoRepeat => "no-repeat"
RepeatY => "repeat-y"
RepeatX => "repeat-x"
Repeat => "repeat"
}
let context = canvas_backend.context
let pattern = context.create_pattern(@js.Union7::from0(element), repeat_mode)
context.save()
context.set_fill_style(@js.Union3::from2(pattern))
context.translate(x, y)
context.transform(
transform.a,
transform.b,
transform.c,
transform.d,
transform.tx,
transform.ty,
)
context.fill_rect(0, 0, width, height)
context.restore()
}
///|
pub fn draw_sprite(
sprite_path~ : String,
x~ : Double,
y~ : Double,
offset_x~ : Double,
offset_y~ : Double,
width~ : Double,
height~ : Double,
transform~ : @smath.Transform,
) -> Unit {
let context = canvas_backend.context
context.save()
context.translate(x, y)
context.transform(
transform.a,
transform.b,
transform.c,
transform.d,
transform.tx,
transform.ty,
)
let element = get_image_element(sprite_path)
context.draw_image_with_src_and_dst_size(
element |> @js.Value::cast_from |> @js.Value::cast,
offset_x,
offset_y,
width,
height,
0,
0,
width,
height,
)
context.restore()
}
///|
pub fn draw_text(
text~ : String,
x~ : Double,
y~ : Double,
font~ : String,
color~ : String,
align~ : @smath.HAlign,
baseline~ : @smath.VAlign,
) -> Unit {
let context = canvas_backend.context
context.save()
context.set_font(font)
let align = match align {
Left => "left"
Center => "center"
Right => "right"
}
set_text_align(context, align)
let baseline = match baseline {
Top => "top"
Center => "center"
Bottom => "bottom"
}
set_text_baseline(context, baseline)
context.set_fill_style(@js.Union3::from0(color))
context.fill_text(text, x, y)
context.restore()
}
///|
pub fn draw_color_rect(
x~ : Double,
y~ : Double,
width~ : Double,
height~ : Double,
color~ : String,
stroke_color~ : String,
) -> Unit {
let context = canvas_backend.context
context.save()
context.set_stroke_style(@js.Union3::from0(stroke_color))
context.stroke_rect(x, y, width, height)
context.set_fill_style(@js.Union3::from0(color))
context.fill_rect(x, y, width, height)
context.restore()
}
///|
pub fn draw_color_circle(
x~ : Double,
y~ : Double,
radius~ : Double,
color~ : String,
stroke_color~ : String,
) -> Unit {
let context = canvas_backend.context
begin_path(context)
context.arc(x, y, radius, 0, @math.PI * 2)
context.set_fill_style(@js.Union3::from0(color))
context.fill()
context.set_stroke_style(@js.Union3::from0(stroke_color))
context.stroke()
context.restore()
}
///|
pub fn draw_gradient_rect(
x~ : Double,
y~ : Double,
width~ : Double,
height~ : Double,
color_start~ : String,
color_end~ : String,
) -> Unit {
let context = canvas_backend.context
context.save()
let gradient = context.create_linear_gradient(x, y, x + width, y + height)
gradient.add_color_stop(0.0, color_start)
gradient.add_color_stop(1.0, color_end)
context.set_fill_style(@js.Union3::from1(gradient))
context.fill_rect(x, y, width, height)
context.restore()
}