From d8f971ffb5c00b30af0160ebed7d446d56d2e54c Mon Sep 17 00:00:00 2001 From: playX Date: Sun, 7 Nov 2021 11:06:28 +0300 Subject: [PATCH] jsdom: add Path2D API, All CanvasRenderingContext2D methods (except image methods) (#12404) --- examples/js_dom_draw/draw.js.v | 2 +- vlib/jsdom/context_2d.js.v | 256 +++++++++++++++++++++++++++- vlib/jsdom/dom.js.v | 16 ++ vlib/jsdom/html_canvas_element.js.v | 9 + vlib/jsdom/path2d.js.v | 63 +++++++ vlib/jsdom/point.js.v | 71 ++++++++ 6 files changed, 413 insertions(+), 4 deletions(-) create mode 100644 vlib/jsdom/path2d.js.v create mode 100644 vlib/jsdom/point.js.v diff --git a/examples/js_dom_draw/draw.js.v b/examples/js_dom_draw/draw.js.v index 6a4abb970f..41d62aee88 100644 --- a/examples/js_dom_draw/draw.js.v +++ b/examples/js_dom_draw/draw.js.v @@ -40,7 +40,7 @@ fn main() { elemc := document.get_element_by_id('myCanvas') or { panic('no canvas') } canv := jsdom.get_html_canvas_element(elemc) or { panic('expected canvas') } - context := get_2dcontext(canv) or { panic('wow') } + context := canv.get_context_2d() mut state := DrawState{} canv.add_event_listener('mousedown', fn [mut state] (_ jsdom.IEventTarget, event jsdom.IEvent) { state.drawing = true diff --git a/vlib/jsdom/context_2d.js.v b/vlib/jsdom/context_2d.js.v index 6455964cad..d48070dd54 100644 --- a/vlib/jsdom/context_2d.js.v +++ b/vlib/jsdom/context_2d.js.v @@ -27,6 +27,14 @@ pub enum LineJoin { miter } +pub enum TextAlign { + left + right + center + start + end +} + pub struct CanvasRenderingContext2D { mut: ctx JS.CanvasRenderingContext2D [noinit] @@ -38,16 +46,54 @@ pub fn (ctx CanvasRenderingContext2D) begin_path() { #ctx.ctx.beginPath(); } +pub fn (ctx CanvasRenderingContext2D) set_line_dash(arr []f64) { + #let tmp = [] + + for x in arr { + #tmp.push(x.val); + + _ := x + } + #ctx.ctx.setLineDash(tmp); +} + +pub fn (ctx CanvasRenderingContext2D) get_line_dash() []f64 { + arr := []f64{} + #for (elem of ctx.ctx.getLineDash()) { array_push(arr,elem); } + + return arr +} + +pub fn (ctx CanvasRenderingContext2D) set_text_align(align TextAlign) { + match align { + .left { + #ctx.ctx.textAlign = 'start'; + } + .right { + #ctx.ctx.textAlign = 'right'; + } + .center { + #ctx.ctx.textAlign = 'center'; + } + .start { + #ctx.ctx.textAlign = 'start'; + } + .end { + #ctx.ctx.textAlign = 'end'; + } + } +} + pub fn (ctx CanvasRenderingContext2D) set_line_join(j LineJoin) { match j { .bevel { - #ctx.ctx.lineJoin = 'bevel'.str + #ctx.ctx.lineJoin = 'bevel' } .round { - #ctx.ctx.lineJoin = 'round'.str + #ctx.ctx.lineJoin = 'round' } .miter { - #ctx.ctx.lineJoin = 'miter'.str + #ctx.ctx.lineJoin = 'miter' } } } @@ -150,6 +196,10 @@ pub fn (ctx CanvasRenderingContext2D) draw_focus_if_needed(el IElement) { #ctx.ctx.drawFocusIfNeeded(el.val.node); } +pub fn (ctx CanvasRenderingContext2D) draw_focus_if_needed_wpath(path Path2D, el IElement) { + #ctx.ctx.drawFocusIfNeeded(path.path, el.val.node); +} + fn (ctx JS.CanvasRenderingContext2D) createRadialGradient(x0 f64, y0 f64, r0 f64, x1 f64, y1 f64, r1 f64) JS.CanvasGradient fn (ctx JS.CanvasRenderingContext2D) createConicGradient(startAngle f64, x f64, y f64) JS.CanvasGradient @@ -157,3 +207,203 @@ fn (ctx JS.CanvasRenderingContext2D) createConicGradient(startAngle f64, x f64, fn (ctx JS.CanvasRenderingContext2D) createLinearGradient(x0 f64, y0 f64, x1 f64, y1 f64) JS.CanvasGradient pub fn (gradient JS.CanvasGradient) addColorStop(x f64, color string) + +/// fill_text draws a text string at the specified coordinates. `max_width` allows specifying a maximum +/// width for the rendered text, set max_width to -1.0 to automatically adjust text width. +pub fn (ctx CanvasRenderingContext2D) fill_text(text string, x f64, y f64, max_width f64) { + if max_width == -1.0 { + #ctx.ctx.fillText(text.str,x.val,y.val,max_width.val) + } else { + #ctx.ctx.fillText(text.str,x.val,y.val) + } +} + +/// stoke_text strokes — that is, draws the outlines of — the characters of a text string at the specified coordinates. +/// `max_width` allows specifying a maximum width for the rendered text, set max_width to -1.0 to automatically adjust text width. +pub fn (ctx CanvasRenderingContext2D) stroke_text(text string, x f64, y f64, max_width f64) { + if max_width == -1.0 { + #ctx.ctx.stokeText(text.str,x.val,y.val,max_width.val) + } else { + #ctx.ctx.stokeText(text.str,x.val,y.val) + } +} + +pub fn (ctx CanvasRenderingContext2D) measure_text(text string) TextMetrics { + metrics := TextMetrics{} + #let tmp = ctx.ctx.measureText(text.str); + #metrics.width = new f64(tmp.width); + #metrics.actual_bounding_box_left = new f64(tmp.actualBoundingBoxLeft); + #metrics.actual_bounding_box_right = new f64(tmp.actualBoundingBoxRight); + #metrics.actual_bounding_box_ascent = new f64(tmp.actualBoundingBoxAscent); + #metrics.actual_bounding_box_descent = new f64(tmp.actualBoundingBoxDescent); + #metrics.font_bounding_box_ascent = new f64(tmp.fontBoundingBoxAscent); + #metrics.font_bounding_box_descent = new f64(tmp.fontBoundingBoxDescent); + #metrics.em_height_ascent = new f64(tmp.emHeightAscent); + #metrics.em_height_descent = new f64(tmp.emHeightDescent); + #metrics.hanging_baseline = new f64(tmp.hangingBaseline); + #metrics.alphabetic_baseline = new f64(tmp.alphabeticBaseline); + #metrics.ideographic_baseline = new f64(tmp.ideographicBaseline); + + return metrics +} + +pub fn (ctx CanvasRenderingContext2D) fill_path(p Path2D) { + #ctx.ctx.fill(p.path); +} + +pub enum FillRule { + nonzero + evenodd +} + +pub fn (ctx CanvasRenderingContext2D) clip_rule(rule FillRule) { + match rule { + .nonzero { + #ctx.ctx.clip('nonzero') + } + .evenodd { + #ctx.ctx.clip('evenodd') + } + } +} + +pub fn (ctx CanvasRenderingContext2D) clip() { + #ctx.ctx.clip(); +} + +pub fn (ctx CanvasRenderingContext2D) clip_path(path Path2D) { + #ctx.ctx.clip(path.path); +} + +pub fn (ctx CanvasRenderingContext2D) clip_path_rule(path Path2D, rule FillRule) { + match rule { + .nonzero { + #ctx.ctx.clip(path.path, 'nonzero') + } + .evenodd { + #ctx.ctx.clip(path.path,'evenodd') + } + } +} + +pub fn (ctx CanvasRenderingContext2D) is_point_in_path(x f64, y f64) bool { + res := false + #res.val = ctx.ctx.isPointInPath(x.val,y.val); + + return res +} + +pub fn (ctx CanvasRenderingContext2D) is_point_in_path_2(path Path2D, x f64, y f64) bool { + res := false + #res.val = ctx.ctx.isPointInPath(path.path,x.val,y.val); + + return res +} + +pub fn (ctx CanvasRenderingContext2D) is_point_in_path_3(path Path2D, x f64, y f64, rule FillRule) bool { + res := false + match rule { + .nonzero { + #res.val = ctx.ctx.isPointInPath(path.path,x.val,y.val,'nonzero'); + } + .evenodd { + #res.val = ctx.ctx.isPointInPath(path.path,x.val,y.val,'evenadd'); + } + } + return res +} + +pub fn (ctx CanvasRenderingContext2D) is_point_in_path_4(x f64, y f64, rule FillRule) bool { + res := false + match rule { + .nonzero { + #res.val = ctx.ctx.isPointInPath(x.val,y.val,'nonzero'); + } + .evenodd { + #res.val = ctx.ctx.isPointInPath(x.val,y.val,'evenadd'); + } + } + return res +} + +pub fn (ctx CanvasRenderingContext2D) is_point_in_stroke(x f64, y f64) bool { + res := false + #res.val = ctx.ctx.isPointInStroke(x.val,y.val); + + return res +} + +pub fn (ctx CanvasRenderingContext2D) is_point_in_stroke_path(path Path2D, x f64, y f64) bool { + res := false + #res.val = ctx.ctx.isPointInStroke(path.path, x.val,y.val); + + return res +} + +pub fn (ctx CanvasRenderingContext2D) get_transform() DOMMatrix { + m := DOMMatrix{} + #m.matrix = ctx.ctx.getTransform(); + + return m +} + +pub fn (ctx CanvasRenderingContext2D) rotate(angle f64) { + #ctx.ctx.rotate(angle.val); +} + +pub fn (ctx CanvasRenderingContext2D) scale(x f64, y f64) { + #ctx.ctx.scale(x.val,y.val); +} + +pub fn (ctx CanvasRenderingContext2D) translate(x f64, y f64) { + #ctx.ctx.translate(x.val,y.val) +} + +pub fn (ctx CanvasRenderingContext2D) transform(a f64, b f64, c f64, d f64, e f64, f f64) { + #ctx.ctx.transform(a.val,b.val,c.val,d.val,e.val,f.val); +} + +pub fn (ctx CanvasRenderingContext2D) set_transform_matrix(m DOMMatrix) { + #ctx.ctx.setTransform(m.matrix); +} + +pub fn (ctx CanvasRenderingContext2D) set_transform(a f64, b f64, c f64, d f64, e f64, f f64) { + #ctx.ctx.setTransform(a.val,b.val,c.val,d.val,e.val,f.val); +} + +pub fn (ctx CanvasRenderingContext2D) global_alpha() f64 { + res := 0.0 + #res.val = ctx.ctx.globalAlpha + + return res +} + +pub fn (ctx CanvasRenderingContext2D) set_global_alpha(alpha f64) { + #ctx.ctx.globalAlpha = alpha.val; +} + +pub fn (ctx CanvasRenderingContext2D) global_composite_operation() string { + res := '' + #res.str = ctx.ctx.globalCompositeOperation + + return res +} + +pub fn (ctx CanvasRenderingContext2D) set_global_composite_operation(typ string) { + #ctx.ctx.globalCompositeOperation = typ.str; +} + +pub fn (ctx CanvasRenderingContext2D) save() { + #ctx.ctx.save(); +} + +pub fn (ctx CanvasRenderingContext2D) restore() { + #ctx.ctx.restore() +} + +pub fn (ctx CanvasRenderingContext2D) canvas() HTMLCanvasElement { + elem := HTMLCanvasElement{} + #elem.node = ctx.ctx.canvas() + + return elem +} diff --git a/vlib/jsdom/dom.js.v b/vlib/jsdom/dom.js.v index 419102696b..24c8287590 100644 --- a/vlib/jsdom/dom.js.v +++ b/vlib/jsdom/dom.js.v @@ -184,3 +184,19 @@ fn init() { #jsdom__document.node = document; #jsdom__window.node = window; } + +pub struct TextMetrics { +pub: + width f64 + actual_bounding_box_left f64 + actual_bounding_box_right f64 + font_bounding_box_ascent f64 + font_bounding_box_descent f64 + actual_bounding_box_ascent f64 + actual_bounding_box_descent f64 + em_height_ascent f64 + em_height_descent f64 + hanging_baseline f64 + alphabetic_baseline f64 + ideographic_baseline f64 +} diff --git a/vlib/jsdom/html_canvas_element.js.v b/vlib/jsdom/html_canvas_element.js.v index 708a3d1a54..06079dc913 100644 --- a/vlib/jsdom/html_canvas_element.js.v +++ b/vlib/jsdom/html_canvas_element.js.v @@ -36,3 +36,12 @@ pub fn (elem HTMLCanvasElement) get_context(ctx_ string) ContextResult { return res } + +pub fn (elem HTMLCanvasElement) get_context_2d() CanvasRenderingContext2D { + mut res := CanvasRenderingContext2D{} + #let ctx = elem.node.getContext('2d'); + #res = new jsdom__CanvasRenderingContext2D(ctx); + #res.ctx = ctx; + + return res +} diff --git a/vlib/jsdom/path2d.js.v b/vlib/jsdom/path2d.js.v new file mode 100644 index 0000000000..1fd64f6fd0 --- /dev/null +++ b/vlib/jsdom/path2d.js.v @@ -0,0 +1,63 @@ +module jsdom + +pub struct JS.Path2D {} + +pub fn (p JS.Path2D) addPath(JS.Path2D, JS.DOMMatrix) +pub fn (p JS.Path2D) closePath() +pub fn (p JS.Path2D) moveTo(x JS.Number, y JS.Number) +pub fn (p JS.Path2D) lineTo(x JS.Number, y JS.Number) +pub fn (p JS.Path2D) bezierCurveTo(cp1x JS.Number, cp1y JS.Number, cp2x JS.Number, cp2y JS.Number, x JS.Number, y JS.Number) +pub fn (p JS.Path2D) quadraticCurveTo(cpx JS.Number, cpy JS.Number, x JS.Number, y JS.Number) +pub fn (p JS.Path2D) arc(x JS.Number, y JS.Number, radius JS.Number, startAngle JS.Number, endAngle JS.Number, counter_clockwise JS.Boolean) +pub fn (p JS.Path2D) arcTo(x1 JS.Number, y1 JS.Number, x2 JS.Number, y2 JS.Number, radius JS.Number) +pub fn (p JS.Path2D) ellipse(x JS.Number, y JS.Number, radius_x JS.Number, radius_y JS.Number, rotation JS.Number, start_angle JS.Number, end_angle JS.Number, counter_clockwise JS.Boolean) +pub fn (p JS.Path2D) rect(x JS.Number, y JS.Number, width JS.Number, height JS.Number) + +pub struct Path2D { +mut: + path JS.Path2D [noinit] +} + +pub fn (p Path2D) add_path(p2 Path2D) { + #p.path.addPath(p2.path); +} + +pub fn (p Path2D) add_path_with_transform(p2 Path2D, m DOMMatrix) { + p.path.addPath(p2.path, m.matrix) +} + +pub fn (path Path2D) bezier_curve_to(cp1x f64, cp1y f64, cp2x f64, cp2y f64, x f64, y f64) { + #path.path.bezierCurveTo(cp1x.val,cp1y.val,cp2x.val,cp2y.val, x.val,y.val); +} + +pub fn (path Path2D) quadratic_curve_to(cpx f64, cpy f64, x f64, y f64) { + #path.path.quadraticCurveTo(cpx.val,cpy.val,x.val,y.val); +} + +pub fn (path Path2D) arc(x f64, y f64, radius f64, start_angle f64, end_angle f64, counter_clockwise bool) { + #path.path.arc(x.val,y.val,radius.val,start_angle.val,end_angle.val,counter_clockwise.val) +} + +pub fn (path Path2D) arc_to(x1 f64, y1 f64, x2 f64, y2 f64, radius f64) { + #path.path.arcTo(x1.val,y1.val,x2.val,y2.val,radius.val); +} + +pub fn (path Path2D) ellipse(x f64, y f64, radius_x f64, radius_y f64, rotation f64, start_angle f64, end_angle f64, counter_clockwise bool) { + #path.path.ellipse(x.val,y.val,radius_x.val,radius_y.val,rotation.val,start_angle.val,end_angle.val,counter_clockwise.val); +} + +pub fn (path Path2D) rect(x f64, y f64, width f64, height f64) { + #path.path.rect(x.val,y.val,widht.val,height.val); +} + +pub fn (path Path2D) line_to(x f64, y f64) { + path.path.lineTo(f64tonum(x), f64tonum(y)) +} + +pub fn (path Path2D) move_to(x f64, y f64) { + path.path.lineTo(f64tonum(x), f64tonum(y)) +} + +pub fn (path Path2D) close_path() { + path.path.closePath() +} diff --git a/vlib/jsdom/point.js.v b/vlib/jsdom/point.js.v new file mode 100644 index 0000000000..eb7704c323 --- /dev/null +++ b/vlib/jsdom/point.js.v @@ -0,0 +1,71 @@ +module jsdom + +pub struct JS.DOMPoint { +pub mut: + x JS.Number [noinit] + y JS.Number [noinit] + z JS.Number [noinit] + w JS.Number [noinit] +} + +pub struct DOMPoint { +mut: + point JS.DOMPoint +} + +pub fn new_dompoint(x f64, y f64, z f64, w f64) DOMPoint { + mut point := DOMPoint{} + + point.point.x = f64tonum(x) + point.point.y = f64tonum(y) + point.point.z = f64tonum(z) + point.point.w = f64tonum(w) + + return point +} + +pub fn (p DOMPoint) x() f64 { + return tof64(p.point.x) +} + +pub fn (p DOMPoint) y() f64 { + return tof64(p.point.y) +} + +pub fn (p DOMPoint) z() f64 { + return tof64(p.point.z) +} + +pub fn (p DOMPoint) w() f64 { + return tof64(p.point.w) +} + +pub fn (mut p DOMPoint) set_x(x f64) { + p.point.x = f64tonum(x) +} + +pub fn (mut p DOMPoint) set_y(y f64) { + p.point.y = f64tonum(y) +} + +pub fn (mut p DOMPoint) set_z(z f64) { + p.point.z = f64tonum(z) +} + +pub fn (mut p DOMPoint) set_w(w f64) { + p.point.w = f64tonum(w) +} + +pub fn (p DOMPoint) matrix_transform(matrix DOMMatrix) DOMPoint { + mut point := DOMPoint{} + #point.point = p.point.matrixTransform(matrix.matrix); + + return point +} + +pub fn (p DOMPoint) matrix_transform_2() DOMPoint { + mut point := DOMPoint{} + #point.point = p.point.matrixTransform(); + + return point +}