2021-09-07 17:36:50 +03:00
package rui
import (
2022-11-02 20:08:02 +03:00
"math"
2021-09-07 17:36:50 +03:00
"strconv"
"strings"
)
2024-10-28 13:11:43 +03:00
// LineJoin is the type for setting the shape used to join two line segments where they meet.
type LineJoin int
// LineCap is the type for setting the shape used to draw the end points of lines.
type LineCap int
2024-09-12 14:05:11 +03:00
// Constants related to canvas view operations
2021-09-07 17:36:50 +03:00
const (
// MiterJoin - Connected segments are joined by extending their outside edges
// to connect at a single point, with the effect of filling an additional
// lozenge-shaped area. This setting is affected by the miterLimit property
2024-10-28 13:11:43 +03:00
MiterJoin LineJoin = 0
2021-09-07 17:36:50 +03:00
// RoundJoin - rounds off the corners of a shape by filling an additional sector
// of disc centered at the common endpoint of connected segments.
// The radius for these rounded corners is equal to the line width.
2024-10-28 13:11:43 +03:00
RoundJoin LineJoin = 1
2021-09-07 17:36:50 +03:00
// BevelJoin - Fills an additional triangular area between the common endpoint
// of connected segments, and the separate outside rectangular corners of each segment.
2024-10-28 13:11:43 +03:00
BevelJoin LineJoin = 2
2021-09-07 17:36:50 +03:00
// ButtCap - the ends of lines are squared off at the endpoints. Default value.
2024-10-28 13:11:43 +03:00
ButtCap LineCap = 0
2021-09-07 17:36:50 +03:00
// RoundCap - the ends of lines are rounded.
2024-10-28 13:11:43 +03:00
RoundCap LineCap = 1
2021-09-07 17:36:50 +03:00
// SquareCap - the ends of lines are squared off by adding a box with an equal width
// and half the height of the line's thickness.
2024-10-28 13:11:43 +03:00
SquareCap LineCap = 2
2021-09-07 17:36:50 +03:00
// AlphabeticBaseline - the text baseline is the normal alphabetic baseline. Default value.
AlphabeticBaseline = 0
2024-10-28 13:11:43 +03:00
2021-09-07 17:36:50 +03:00
// TopBaseline - the text baseline is the top of the em square.
TopBaseline = 1
2024-10-28 13:11:43 +03:00
2021-09-07 17:36:50 +03:00
// MiddleBaseline - the text baseline is the middle of the em square.
MiddleBaseline = 2
2024-10-28 13:11:43 +03:00
2021-09-07 17:36:50 +03:00
// BottomBaseline - the text baseline is the bottom of the bounding box.
// This differs from the ideographic baseline in that the ideographic baseline doesn't consider descenders.
BottomBaseline = 3
2024-10-28 13:11:43 +03:00
2021-09-07 17:36:50 +03:00
// HangingBaseline - the text baseline is the hanging baseline. (Used by Tibetan and other Indic scripts.)
HangingBaseline = 4
2024-10-28 13:11:43 +03:00
2021-09-07 17:36:50 +03:00
// IdeographicBaseline - the text baseline is the ideographic baseline; this is
// the bottom of the body of the characters, if the main body of characters protrudes
// beneath the alphabetic baseline. (Used by Chinese, Japanese, and Korean scripts.)
IdeographicBaseline = 5
// StartAlign - the text is aligned at the normal start of the line (left-aligned
// for left-to-right locales, right-aligned for right-to-left locales).
StartAlign = 3
2024-10-28 13:11:43 +03:00
2021-09-07 17:36:50 +03:00
// EndAlign - the text is aligned at the normal end of the line (right-aligned
// for left-to-right locales, left-aligned for right-to-left locales).
EndAlign = 4
)
// GradientPoint defined by an offset and a color, to a linear or radial gradient
type GradientPoint struct {
// Offset - a number between 0 and 1, inclusive, representing the position of the color stop
Offset float64
// Color - the color of the stop
Color Color
}
// FontParams defined optionally font properties
type FontParams struct {
// Italic - if true then a font is italic
Italic bool
// SmallCaps - if true then a font uses small-caps glyphs
SmallCaps bool
// Weight - a font weight. Valid values: 0...9, there
// 0 - a weight does not specify;
// 1 - a minimal weight;
// 4 - a normal weight;
// 7 - a bold weight;
// 9 - a maximal weight.
Weight int
// LineHeight - the height (relative to the font size of the element itself) of a line box.
LineHeight SizeUnit
}
2022-10-30 12:35:22 +03:00
// TextMetrics is the result of the Canvas.TextMetrics function
type TextMetrics struct {
// Width is the calculated width of a segment of inline text in pixels
Width float64
// Ascent is the distance from the horizontal baseline to the top of the bounding rectangle used to render the text, in pixels.
Ascent float64
// Descent is the distance from the horizontal baseline to the bottom of the bounding rectangle used to render the text, in pixels.
Descent float64
// Left is the distance to the left side of the bounding rectangle of the given text, in pixels;
// positive numbers indicating a distance going left from the given alignment point.
Left float64
// Right is the distance to the right side of the bounding rectangle of the given text, CSS pixels.
Right float64
}
2024-09-12 14:05:11 +03:00
// Canvas is a drawing interface used by the [CanvasView]
2021-09-07 17:36:50 +03:00
type Canvas interface {
// View return the view for the drawing
View ( ) CanvasView
// Width returns the width in pixels of the canvas area
Width ( ) float64
// Height returns the height in pixels of the canvas area
Height ( ) float64
// Save saves the entire state of the canvas by pushing the current state onto a stack.
Save ( )
// Restore restores the most recently saved canvas state by popping the top entry
// in the drawing state stack. If there is no saved state, this method does nothing.
Restore ( )
// ClipPath turns the rectangle into the current clipping region. It replaces any previous clipping region.
ClipRect ( x , y , width , height float64 )
// ClipPath turns the path into the current clipping region. It replaces any previous clipping region.
ClipPath ( path Path )
// SetScale adds a scaling transformation to the canvas units horizontally and/or vertically.
2024-12-05 20:15:39 +03:00
// * x - scaling factor in the horizontal direction. A negative value flips pixels across
2021-09-07 17:36:50 +03:00
// the vertical axis. A value of 1 results in no horizontal scaling;
2024-12-05 20:15:39 +03:00
// * y - scaling factor in the vertical direction. A negative value flips pixels across
2021-09-07 17:36:50 +03:00
// the horizontal axis. A value of 1 results in no vertical scaling.
SetScale ( x , y float64 )
// SetTranslation adds a translation transformation to the current matrix.
2024-12-05 20:15:39 +03:00
// * x - distance to move in the horizontal direction. Positive values are to the right, and negative to the left;
// * y - distance to move in the vertical direction. Positive values are down, and negative are up.
2021-09-07 17:36:50 +03:00
SetTranslation ( x , y float64 )
// SetRotation adds a rotation to the transformation matrix.
// angle - the rotation angle, clockwise in radians
SetRotation ( angle float64 )
// SetTransformation multiplies the current transformation with the matrix described by the arguments
// of this method. This lets you scale, rotate, translate (move), and skew the context.
// The transformation matrix is described by:
2024-12-05 20:15:39 +03:00
// ⎡ xScale xSkew dx ⎤
// ⎢ ySkew yScale dy ⎥
// ⎣ 0 0 1 ⎦
// where
// * xScale, yScale - horizontal and vertical scaling. A value of 1 results in no scaling;
// * xSkew, ySkew - horizontal and vertical skewing;
// * dx, dy - horizontal and vertical translation (moving).
2021-09-07 17:36:50 +03:00
SetTransformation ( xScale , yScale , xSkew , ySkew , dx , dy float64 )
// ResetTransformation resets the current transform to the identity matrix
ResetTransformation ( )
// SetSolidColorFillStyle sets the color to use inside shapes
SetSolidColorFillStyle ( color Color )
// SetSolidColorStrokeStyle sets color to use for the strokes (outlines) around shapes
SetSolidColorStrokeStyle ( color Color )
// SetLinearGradientFillStyle sets a gradient along the line connecting two given coordinates to use inside shapes
2024-12-05 20:15:39 +03:00
// * x0, y0 - coordinates of the start point;
// * x1, y1 - coordinates of the end point;
// * startColor, endColor - the start and end color
// * stopPoints - the array of stop points
2021-09-07 17:36:50 +03:00
SetLinearGradientFillStyle ( x0 , y0 float64 , color0 Color , x1 , y1 float64 , color1 Color , stopPoints [ ] GradientPoint )
// SetLinearGradientStrokeStyle sets a gradient along the line connecting two given coordinates to use for the strokes (outlines) around shapes
2024-12-05 20:15:39 +03:00
// * x0, y0 - coordinates of the start point;
// * x1, y1 - coordinates of the end point;
// * color0, color1 - the start and end color
// * stopPoints - the array of stop points
2021-09-07 17:36:50 +03:00
SetLinearGradientStrokeStyle ( x0 , y0 float64 , color0 Color , x1 , y1 float64 , color1 Color , stopPoints [ ] GradientPoint )
// SetRadialGradientFillStyle sets a radial gradient using the size and coordinates of two circles
// to use inside shapes
2024-12-05 20:15:39 +03:00
// * x0, y0 - coordinates of the center of the start circle;
// * r0 - the radius of the start circle;
// * x1, y1 - coordinates the center of the end circle;
// * r1 - the radius of the end circle;
// * color0, color1 - the start and end color
// * stopPoints - the array of stop points
2021-09-07 17:36:50 +03:00
SetRadialGradientFillStyle ( x0 , y0 , r0 float64 , color0 Color , x1 , y1 , r1 float64 , color1 Color , stopPoints [ ] GradientPoint )
// SetRadialGradientStrokeStyle sets a radial gradient using the size and coordinates of two circles
// to use for the strokes (outlines) around shapes
2024-12-05 20:15:39 +03:00
// * x0, y0 - coordinates of the center of the start circle;
// * r0 - the radius of the start circle;
// * x1, y1 - coordinates the center of the end circle;
// * r1 - the radius of the end circle;
// * color0, color1 - the start and end color
// * stopPoints - the array of stop points
2021-09-07 17:36:50 +03:00
SetRadialGradientStrokeStyle ( x0 , y0 , r0 float64 , color0 Color , x1 , y1 , r1 float64 , color1 Color , stopPoints [ ] GradientPoint )
2024-12-04 19:27:33 +03:00
// SetConicGradientFillStyle sets a conic gradient around a point
// to use inside shapes
2024-12-05 20:15:39 +03:00
// * x, y - coordinates of the center of the conic gradient in pilels;
// * startAngle - the angle at which to begin the gradient, in radians. The angle starts from a line going horizontally right from the center, and proceeds clockwise.
// * startColor - the start color;
// * endColor - the end color;
// * stopPoints - the array of stop points. The Pos field of GradientPoint, in the range from 0 to 1, specifies the angle in turns.
2024-12-04 19:27:33 +03:00
SetConicGradientFillStyle ( x , y , startAngle float64 , startColor , endColor Color , stopPoints [ ] GradientPoint )
// SetConicGradientFillStyle sets a conic gradient around a point
// to use inside shapes
2024-12-05 20:15:39 +03:00
// * x, y - coordinates of the center of the conic gradient in pilels;
// * startAngle - the angle at which to begin the gradient, in radians. The angle starts from a line going horizontally right from the center, and proceeds clockwise.
// * startColor - the start color;
// * endColor - the end color;
// * stopPoints - the array of stop points. The Pos field of GradientPoint, in the range from 0 to 1, specifies the angle in turns.
2024-12-04 19:27:33 +03:00
SetConicGradientStrokeStyle ( x , y , startAngle float64 , startColor , endColor Color , stopPoints [ ] GradientPoint )
2021-09-07 17:36:50 +03:00
// SetImageFillStyle set the image as the filling pattern.
2024-12-05 20:15:39 +03:00
//
// repeat - indicating how to repeat the pattern's image. Possible values are:
// * NoRepeat (0) - neither direction,
// * RepeatXY (1) - both directions,
// * RepeatX (2) - horizontal only,
// * RepeatY (3) - vertical only.
2021-09-07 17:36:50 +03:00
SetImageFillStyle ( image Image , repeat int )
// SetLineWidth the line width, in coordinate space units. Zero, negative, Infinity, and NaN values are ignored.
SetLineWidth ( width float64 )
// SetLineJoin sets the shape used to join two line segments where they meet.
// Valid values: MiterJoin (0), RoundJoin (1), BevelJoin (2). All other values are ignored.
2024-10-28 13:11:43 +03:00
SetLineJoin ( join LineJoin )
2021-09-07 17:36:50 +03:00
// SetLineJoin sets the shape used to draw the end points of lines.
// Valid values: ButtCap (0), RoundCap (1), SquareCap (2). All other values are ignored.
2024-10-28 13:11:43 +03:00
SetLineCap ( cap LineCap )
2021-09-07 17:36:50 +03:00
// SetLineDash sets the line dash pattern used when stroking lines.
// dash - an array of values that specify alternating lengths of lines and gaps which describe the pattern.
// offset - the line dash offset
SetLineDash ( dash [ ] float64 , offset float64 )
// SetFont sets the current text style to use when drawing text
SetFont ( name string , size SizeUnit )
// SetFontWithParams sets the current text style to use when drawing text
SetFontWithParams ( name string , size SizeUnit , params FontParams )
2022-10-30 12:35:22 +03:00
// TextWidth calculates metrics of the text drawn by a given font
TextMetrics ( text string , fontName string , fontSize SizeUnit , fontParams FontParams ) TextMetrics
2021-09-07 17:36:50 +03:00
// SetTextBaseline sets the current text baseline used when drawing text. Valid values:
// AlphabeticBaseline (0), TopBaseline (1), MiddleBaseline (2), BottomBaseline (3),
// HangingBaseline (4), and IdeographicBaseline (5). All other values are ignored.
SetTextBaseline ( baseline int )
// SetTextAlign sets the current text alignment used when drawing text. Valid values:
// LeftAlign (0), RightAlign (1), CenterAlign (2), StartAlign (3), and EndAlign(4). All other values are ignored.
SetTextAlign ( align int )
// SetShadow sets shadow parameters:
2024-12-05 20:15:39 +03:00
// * offsetX, offsetY - the distance that shadows will be offset horizontally and vertically;
// * blur - the amount of blur applied to shadows. Must be non-negative;
// * color - the color of shadows.
2021-09-07 17:36:50 +03:00
SetShadow ( offsetX , offsetY , blur float64 , color Color )
2024-10-28 13:11:43 +03:00
2021-09-07 17:36:50 +03:00
// ResetShadow sets shadow parameters to default values (invisible shadow)
ResetShadow ( )
// ClearRect erases the pixels in a rectangular area by setting them to transparent black
ClearRect ( x , y , width , height float64 )
2024-10-28 13:11:43 +03:00
2021-09-07 17:36:50 +03:00
// FillRect draws a rectangle that is filled according to the current FillStyle.
FillRect ( x , y , width , height float64 )
2024-10-28 13:11:43 +03:00
2021-09-07 17:36:50 +03:00
// StrokeRect draws a rectangle that is stroked (outlined) according to the current strokeStyle
// and other context settings
StrokeRect ( x , y , width , height float64 )
2024-10-28 13:11:43 +03:00
2021-09-07 17:36:50 +03:00
// FillAndStrokeRect draws a rectangle that is filled according to the current FillStyle and
// is stroked (outlined) according to the current strokeStyle and other context settings
FillAndStrokeRect ( x , y , width , height float64 )
// FillRoundedRect draws a rounded rectangle that is filled according to the current FillStyle.
FillRoundedRect ( x , y , width , height , r float64 )
2024-10-28 13:11:43 +03:00
2021-09-07 17:36:50 +03:00
// StrokeRoundedRect draws a rounded rectangle that is stroked (outlined) according
// to the current strokeStyle and other context settings
StrokeRoundedRect ( x , y , width , height , r float64 )
2024-10-28 13:11:43 +03:00
2021-09-07 17:36:50 +03:00
// FillAndStrokeRoundedRect draws a rounded rectangle that is filled according to the current FillStyle
// and is stroked (outlined) according to the current strokeStyle and other context settings
FillAndStrokeRoundedRect ( x , y , width , height , r float64 )
// FillEllipse draws a ellipse that is filled according to the current FillStyle.
2024-12-05 20:15:39 +03:00
// * x, y - coordinates of the ellipse's center;
// * radiusX - the ellipse's major-axis radius. Must be non-negative;
// * radiusY - the ellipse's minor-axis radius. Must be non-negative;
// * rotation - the rotation of the ellipse, expressed in radians.
2021-09-07 17:36:50 +03:00
FillEllipse ( x , y , radiusX , radiusY , rotation float64 )
2024-10-28 13:11:43 +03:00
2021-09-07 17:36:50 +03:00
// StrokeRoundedRect draws a ellipse that is stroked (outlined) according
// to the current strokeStyle and other context settings
StrokeEllipse ( x , y , radiusX , radiusY , rotation float64 )
2024-10-28 13:11:43 +03:00
2021-09-07 17:36:50 +03:00
// FillAndStrokeEllipse draws a ellipse that is filled according to the current FillStyle
// and is stroked (outlined) according to the current strokeStyle and other context settings
FillAndStrokeEllipse ( x , y , radiusX , radiusY , rotation float64 )
2024-08-20 20:01:26 +03:00
// NewPath creates a new Path object
NewPath ( ) Path
2024-10-28 13:11:43 +03:00
2024-08-20 20:01:26 +03:00
// NewPathFromSvg creates a new Path and initialize it by a string consisting of SVG path data
NewPathFromSvg ( data string ) Path
2021-09-07 17:36:50 +03:00
// FillPath draws a path that is filled according to the current FillStyle.
FillPath ( path Path )
2024-10-28 13:11:43 +03:00
2021-09-07 17:36:50 +03:00
// StrokePath draws a path that is stroked (outlined) according to the current strokeStyle
// and other context settings
StrokePath ( path Path )
2024-10-28 13:11:43 +03:00
2021-09-07 17:36:50 +03:00
// FillAndStrokeRect draws a path that is filled according to the current FillStyle and
// is stroked (outlined) according to the current strokeStyle and other context settings
FillAndStrokePath ( path Path )
// DrawLine draws a line according to the current strokeStyle and other context settings
DrawLine ( x0 , y0 , x1 , y1 float64 )
// FillText draws a text string at the specified coordinates, filling the string's characters
// with the current FillStyle
FillText ( x , y float64 , text string )
2024-10-28 13:11:43 +03:00
2021-09-07 17:36:50 +03:00
// StrokeText strokes — that is, draws the outlines of — the characters of a text string
// at the specified coordinates
StrokeText ( x , y float64 , text string )
// DrawImage draws the image at the (x, y) position
DrawImage ( x , y float64 , image Image )
2024-10-28 13:11:43 +03:00
2021-09-07 17:36:50 +03:00
// DrawImageInRect draws the image in the rectangle (x, y, width, height), scaling in height and width if necessary
DrawImageInRect ( x , y , width , height float64 , image Image )
2024-10-28 13:11:43 +03:00
2022-11-23 15:10:29 +03:00
// DrawImageFragment draws the fragment (described by srcX, srcY, srcWidth, srcHeight) of image
2021-09-07 17:36:50 +03:00
// in the rectangle (dstX, dstY, dstWidth, dstHeight), scaling in height and width if necessary
DrawImageFragment ( srcX , srcY , srcWidth , srcHeight , dstX , dstY , dstWidth , dstHeight float64 , image Image )
2022-11-02 20:08:02 +03:00
finishDraw ( )
2021-09-07 17:36:50 +03:00
}
type canvasData struct {
2022-11-02 20:08:02 +03:00
view CanvasView
session Session
2021-09-07 17:36:50 +03:00
}
func newCanvas ( view CanvasView ) Canvas {
2024-07-05 16:41:07 +03:00
session := view . Session ( )
if ! session . canvasStart ( view . htmlID ( ) ) {
return nil
}
2021-09-07 17:36:50 +03:00
canvas := new ( canvasData )
canvas . view = view
2024-07-05 16:41:07 +03:00
canvas . session = session
2021-09-07 17:36:50 +03:00
return canvas
}
2022-11-02 20:08:02 +03:00
func ( canvas * canvasData ) finishDraw ( ) {
2022-11-23 15:10:29 +03:00
canvas . session . canvasFinish ( )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) View ( ) CanvasView {
return canvas . view
}
func ( canvas * canvasData ) Width ( ) float64 {
if canvas . view != nil {
return canvas . view . Frame ( ) . Width
}
return 0
}
func ( canvas * canvasData ) Height ( ) float64 {
if canvas . view != nil {
return canvas . view . Frame ( ) . Height
}
return 0
}
func ( canvas * canvasData ) Save ( ) {
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasFunc ( "save" )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) Restore ( ) {
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasFunc ( "restore" )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) ClipRect ( x , y , width , height float64 ) {
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasFunc ( "beginPath" )
canvas . session . callCanvasFunc ( "rect" , x , y , width , height )
canvas . session . callCanvasFunc ( "clip" )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) ClipPath ( path Path ) {
2024-08-20 20:01:26 +03:00
canvas . session . callCanvasFunc ( "clip" , path . obj ( ) )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) SetScale ( x , y float64 ) {
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasFunc ( "scale" , x , y )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) SetTranslation ( x , y float64 ) {
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasFunc ( "translate" , x , y )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) SetRotation ( angle float64 ) {
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasFunc ( "rotate" , angle )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) SetTransformation ( xScale , yScale , xSkew , ySkew , dx , dy float64 ) {
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasFunc ( "transform" , xScale , ySkew , xSkew , yScale , dx , dy )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) ResetTransformation ( ) {
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasFunc ( "resetTransform" )
canvas . session . callCanvasFunc ( "scale" , canvas . session . PixelRatio ( ) , canvas . session . PixelRatio ( ) )
//canvas.session.callCanvasFunc("scale", angle)
// TODO canvas.script.WriteString("\nctx.resetTransform();\nctx.scale(dpr, dpr);")
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) SetSolidColorFillStyle ( color Color ) {
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "fillStyle" , color . cssString ( ) )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) SetSolidColorStrokeStyle ( color Color ) {
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "strokeStyle" , color . cssString ( ) )
2021-09-07 17:36:50 +03:00
}
2022-11-02 20:08:02 +03:00
func ( canvas * canvasData ) createLinearGradient ( x0 , y0 float64 , color0 Color , x1 , y1 float64 , color1 Color , stopPoints [ ] GradientPoint ) any {
gradient := canvas . session . createCanvasVar ( "createLinearGradient" , x0 , y0 , x1 , y1 )
canvas . session . callCanvasVarFunc ( gradient , "addColorStop" , 0 , color0 . cssString ( ) )
2021-09-07 17:36:50 +03:00
for _ , point := range stopPoints {
if point . Offset >= 0 && point . Offset <= 1 {
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasVarFunc ( gradient , "addColorStop" , point . Offset , point . Color . cssString ( ) )
2021-09-07 17:36:50 +03:00
}
}
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasVarFunc ( gradient , "addColorStop" , 1 , color1 . cssString ( ) )
return gradient
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) SetLinearGradientFillStyle ( x0 , y0 float64 , color0 Color , x1 , y1 float64 , color1 Color , stopPoints [ ] GradientPoint ) {
2022-11-02 20:08:02 +03:00
gradient := canvas . createLinearGradient ( x0 , y0 , color0 , x1 , y1 , color1 , stopPoints )
canvas . session . updateCanvasProperty ( "fillStyle" , gradient )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) SetLinearGradientStrokeStyle ( x0 , y0 float64 , color0 Color , x1 , y1 float64 , color1 Color , stopPoints [ ] GradientPoint ) {
2022-11-02 20:08:02 +03:00
gradient := canvas . createLinearGradient ( x0 , y0 , color0 , x1 , y1 , color1 , stopPoints )
canvas . session . updateCanvasProperty ( "strokeStyle" , gradient )
2021-09-07 17:36:50 +03:00
}
2022-11-02 20:08:02 +03:00
func ( canvas * canvasData ) createRadialGradient ( x0 , y0 , r0 float64 , color0 Color , x1 , y1 , r1 float64 , color1 Color , stopPoints [ ] GradientPoint ) any {
gradient := canvas . session . createCanvasVar ( "createRadialGradient" , x0 , y0 , r0 , x1 , y1 , r1 )
canvas . session . callCanvasVarFunc ( gradient , "addColorStop" , 0 , color0 . cssString ( ) )
2021-09-07 17:36:50 +03:00
for _ , point := range stopPoints {
if point . Offset >= 0 && point . Offset <= 1 {
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasVarFunc ( gradient , "addColorStop" , point . Offset , point . Color . cssString ( ) )
2021-09-07 17:36:50 +03:00
}
}
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasVarFunc ( gradient , "addColorStop" , 1 , color1 . cssString ( ) )
return gradient
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) SetRadialGradientFillStyle ( x0 , y0 , r0 float64 , color0 Color , x1 , y1 , r1 float64 , color1 Color , stopPoints [ ] GradientPoint ) {
2022-11-02 20:08:02 +03:00
gradient := canvas . createRadialGradient ( x0 , y0 , r0 , color0 , x1 , y1 , r1 , color1 , stopPoints )
canvas . session . updateCanvasProperty ( "fillStyle" , gradient )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) SetRadialGradientStrokeStyle ( x0 , y0 , r0 float64 , color0 Color , x1 , y1 , r1 float64 , color1 Color , stopPoints [ ] GradientPoint ) {
2022-11-02 20:08:02 +03:00
gradient := canvas . createRadialGradient ( x0 , y0 , r0 , color0 , x1 , y1 , r1 , color1 , stopPoints )
canvas . session . updateCanvasProperty ( "strokeStyle" , gradient )
2021-09-07 17:36:50 +03:00
}
2024-12-04 19:27:33 +03:00
func ( canvas * canvasData ) createConicGradient ( x , y , startAngle float64 , startColor , endColor Color , stopPoints [ ] GradientPoint ) any {
gradient := canvas . session . createCanvasVar ( "createConicGradient" , startAngle , x , y )
canvas . session . callCanvasVarFunc ( gradient , "addColorStop" , 0 , startColor . cssString ( ) )
for _ , point := range stopPoints {
if point . Offset >= 0 && point . Offset <= 1 {
canvas . session . callCanvasVarFunc ( gradient , "addColorStop" , point . Offset , point . Color . cssString ( ) )
}
}
canvas . session . callCanvasVarFunc ( gradient , "addColorStop" , 1 , endColor . cssString ( ) )
return gradient
}
func ( canvas * canvasData ) SetConicGradientFillStyle ( x , y , startAngle float64 , startColor , endColor Color , stopPoints [ ] GradientPoint ) {
gradient := canvas . createConicGradient ( x , y , startAngle , startColor , endColor , stopPoints )
canvas . session . updateCanvasProperty ( "fillStyle" , gradient )
}
func ( canvas * canvasData ) SetConicGradientStrokeStyle ( x , y , startAngle float64 , startColor , endColor Color , stopPoints [ ] GradientPoint ) {
gradient := canvas . createConicGradient ( x , y , startAngle , startColor , endColor , stopPoints )
canvas . session . updateCanvasProperty ( "strokeStyle" , gradient )
}
2021-09-07 17:36:50 +03:00
func ( canvas * canvasData ) SetImageFillStyle ( image Image , repeat int ) {
if image == nil || image . LoadingStatus ( ) != ImageReady {
return
}
var repeatText string
switch repeat {
case NoRepeat :
repeatText = "no-repeat"
case RepeatXY :
repeatText = "repeat"
case RepeatX :
repeatText = "repeat-x"
case RepeatY :
repeatText = "repeat-y"
default :
return
}
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasImageFunc ( image . URL ( ) , "fillStyle" , "createPattern" , repeatText )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) SetLineWidth ( width float64 ) {
if width > 0 {
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "lineWidth" , width )
2021-09-07 17:36:50 +03:00
}
}
2024-10-28 13:11:43 +03:00
func ( canvas * canvasData ) SetLineJoin ( join LineJoin ) {
2021-09-07 17:36:50 +03:00
switch join {
case MiterJoin :
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "lineJoin" , "miter" )
2021-09-07 17:36:50 +03:00
case RoundJoin :
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "lineJoin" , "round" )
2021-09-07 17:36:50 +03:00
case BevelJoin :
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "lineJoin" , "bevel" )
2021-09-07 17:36:50 +03:00
}
}
2024-10-28 13:11:43 +03:00
func ( canvas * canvasData ) SetLineCap ( cap LineCap ) {
2021-09-07 17:36:50 +03:00
switch cap {
case ButtCap :
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "lineCap" , "butt" )
2021-09-07 17:36:50 +03:00
case RoundCap :
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "lineCap" , "round" )
2021-09-07 17:36:50 +03:00
case SquareCap :
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "lineCap" , "square" )
2021-09-07 17:36:50 +03:00
}
}
func ( canvas * canvasData ) SetLineDash ( dash [ ] float64 , offset float64 ) {
2022-11-02 21:05:55 +03:00
/ * buffer := allocStringBuilder ( )
defer freeStringBuilder ( buffer )
lead := '['
for _ , val := range dash {
buffer . WriteRune ( lead )
lead = ','
buffer . WriteString ( fmt . Sprintf ( "%g" , val ) )
}
buffer . WriteRune ( ']' )
canvas . session . callCanvasFunc ( "setLineDash" , buffer . String ( ) )
* /
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasFunc ( "setLineDash" , dash )
2021-09-07 17:36:50 +03:00
if offset >= 0 {
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "lineDashOffset" , offset )
2021-09-07 17:36:50 +03:00
}
}
2022-11-02 20:08:02 +03:00
/ *
func ( canvas * canvasData ) convertFont ( name string ) string {
buffer := allocStringBuilder ( )
defer freeStringBuilder ( buffer )
for i , font := range strings . Split ( name , "," ) {
font = strings . Trim ( font , " \n\"'" )
if i > 0 {
buffer . WriteRune ( ',' )
}
if strings . Contains ( font , " " ) {
buffer . WriteRune ( '"' )
buffer . WriteString ( font )
buffer . WriteRune ( '"' )
} else {
buffer . WriteString ( font )
}
2021-09-07 17:36:50 +03:00
}
2022-11-02 20:08:02 +03:00
return buffer . String ( )
2021-09-07 17:36:50 +03:00
}
2022-11-02 20:08:02 +03:00
* /
2022-10-30 12:35:22 +03:00
func ( canvas * canvasData ) fontWithParams ( name string , size SizeUnit , params FontParams ) string {
buffer := allocStringBuilder ( )
defer freeStringBuilder ( buffer )
if params . Italic {
buffer . WriteString ( "italic " )
}
if params . SmallCaps {
buffer . WriteString ( "small-caps " )
}
if params . Weight > 0 && params . Weight <= 9 {
switch params . Weight {
case 4 :
buffer . WriteString ( "normal " )
case 7 :
buffer . WriteString ( "bold " )
default :
buffer . WriteString ( strconv . Itoa ( params . Weight * 100 ) )
buffer . WriteRune ( ' ' )
}
}
buffer . WriteString ( size . cssString ( "1rem" , canvas . View ( ) . Session ( ) ) )
switch params . LineHeight . Type {
case Auto :
case SizeInPercent :
if params . LineHeight . Value != 100 {
buffer . WriteString ( "/" )
buffer . WriteString ( strconv . FormatFloat ( params . LineHeight . Value / 100 , 'g' , - 1 , 64 ) )
}
case SizeInFraction :
if params . LineHeight . Value != 1 {
buffer . WriteString ( "/" )
buffer . WriteString ( strconv . FormatFloat ( params . LineHeight . Value , 'g' , - 1 , 64 ) )
}
default :
buffer . WriteString ( "/" )
buffer . WriteString ( params . LineHeight . cssString ( "" , canvas . View ( ) . Session ( ) ) )
}
names := strings . Split ( name , "," )
lead := " "
for _ , font := range names {
font = strings . Trim ( font , " \n\"'" )
buffer . WriteString ( lead )
lead = ","
if strings . Contains ( font , " " ) {
buffer . WriteRune ( '"' )
buffer . WriteString ( font )
buffer . WriteRune ( '"' )
} else {
buffer . WriteString ( font )
}
}
return buffer . String ( )
}
2022-11-02 20:08:02 +03:00
func ( canvas * canvasData ) SetFont ( name string , size SizeUnit ) {
canvas . session . updateCanvasProperty ( "font" , canvas . fontWithParams ( name , size , FontParams { } ) )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) SetFontWithParams ( name string , size SizeUnit , params FontParams ) {
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "font" , canvas . fontWithParams ( name , size , params ) )
2021-09-07 17:36:50 +03:00
}
2022-10-30 12:35:22 +03:00
func ( canvas * canvasData ) TextMetrics ( text string , fontName string , fontSize SizeUnit , fontParams FontParams ) TextMetrics {
2022-11-02 20:08:02 +03:00
return canvas . session . canvasTextMetrics ( canvas . view . htmlID ( ) , canvas . fontWithParams ( fontName , fontSize , fontParams ) , text )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) SetTextBaseline ( baseline int ) {
switch baseline {
case AlphabeticBaseline :
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "textBaseline" , "alphabetic" )
2021-09-07 17:36:50 +03:00
case TopBaseline :
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "textBaseline" , "top" )
2021-09-07 17:36:50 +03:00
case MiddleBaseline :
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "textBaseline" , "middle" )
2021-09-07 17:36:50 +03:00
case BottomBaseline :
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "textBaseline" , "bottom" )
2021-09-07 17:36:50 +03:00
case HangingBaseline :
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "textBaseline" , "hanging" )
2021-09-07 17:36:50 +03:00
case IdeographicBaseline :
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "textBaseline" , "ideographic" )
2021-09-07 17:36:50 +03:00
}
}
func ( canvas * canvasData ) SetTextAlign ( align int ) {
switch align {
case LeftAlign :
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "textAlign" , "left" )
2021-09-07 17:36:50 +03:00
case RightAlign :
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "textAlign" , "right" )
2021-09-07 17:36:50 +03:00
case CenterAlign :
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "textAlign" , "center" )
2021-09-07 17:36:50 +03:00
case StartAlign :
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "textAlign" , "start" )
2021-09-07 17:36:50 +03:00
case EndAlign :
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "textAlign" , "end" )
2021-09-07 17:36:50 +03:00
}
}
func ( canvas * canvasData ) SetShadow ( offsetX , offsetY , blur float64 , color Color ) {
if color . Alpha ( ) > 0 && blur >= 0 {
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "shadowColor" , color . cssString ( ) )
canvas . session . updateCanvasProperty ( "shadowOffsetX" , offsetX )
canvas . session . updateCanvasProperty ( "shadowOffsetY" , offsetY )
canvas . session . updateCanvasProperty ( "shadowBlur" , blur )
2021-09-07 17:36:50 +03:00
}
}
func ( canvas * canvasData ) ResetShadow ( ) {
2022-11-02 20:08:02 +03:00
canvas . session . updateCanvasProperty ( "shadowColor" , "rgba(0,0,0,0)" )
canvas . session . updateCanvasProperty ( "shadowOffsetX" , 0 )
canvas . session . updateCanvasProperty ( "shadowOffsetY" , 0 )
canvas . session . updateCanvasProperty ( "shadowBlur" , 0 )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) ClearRect ( x , y , width , height float64 ) {
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasFunc ( "clearRect" , x , y , width , height )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) FillRect ( x , y , width , height float64 ) {
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasFunc ( "fillRect" , x , y , width , height )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) StrokeRect ( x , y , width , height float64 ) {
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasFunc ( "strokeRect" , x , y , width , height )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) FillAndStrokeRect ( x , y , width , height float64 ) {
canvas . FillRect ( x , y , width , height )
canvas . StrokeRect ( x , y , width , height )
}
2022-11-02 20:08:02 +03:00
func ( canvas * canvasData ) createRoundedRect ( x , y , width , height , r float64 ) {
2021-09-07 17:36:50 +03:00
left := strconv . FormatFloat ( x , 'g' , - 1 , 64 )
top := strconv . FormatFloat ( y , 'g' , - 1 , 64 )
right := strconv . FormatFloat ( x + width , 'g' , - 1 , 64 )
bottom := strconv . FormatFloat ( y + height , 'g' , - 1 , 64 )
leftR := strconv . FormatFloat ( x + r , 'g' , - 1 , 64 )
topR := strconv . FormatFloat ( y + r , 'g' , - 1 , 64 )
rightR := strconv . FormatFloat ( x + width - r , 'g' , - 1 , 64 )
bottomR := strconv . FormatFloat ( y + height - r , 'g' , - 1 , 64 )
radius := strconv . FormatFloat ( r , 'g' , - 1 , 64 )
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasFunc ( "beginPath" )
canvas . session . callCanvasFunc ( "moveTo" , left , topR )
canvas . session . callCanvasFunc ( "arc" , leftR , topR , radius , math . Pi , math . Pi * 3 / 2 )
canvas . session . callCanvasFunc ( "lineTo" , rightR , top )
canvas . session . callCanvasFunc ( "arc" , rightR , topR , radius , math . Pi * 3 / 2 , math . Pi * 2 )
canvas . session . callCanvasFunc ( "lineTo" , right , bottomR )
canvas . session . callCanvasFunc ( "arc" , rightR , bottomR , radius , 0 , math . Pi / 2 )
canvas . session . callCanvasFunc ( "lineTo" , leftR , bottom )
canvas . session . callCanvasFunc ( "arc" , leftR , bottomR , radius , math . Pi / 2 , math . Pi )
canvas . session . callCanvasFunc ( "closePath" )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) FillRoundedRect ( x , y , width , height , r float64 ) {
2022-11-02 20:08:02 +03:00
canvas . createRoundedRect ( x , y , width , height , r )
canvas . session . callCanvasFunc ( "fill" )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) StrokeRoundedRect ( x , y , width , height , r float64 ) {
2022-11-02 20:08:02 +03:00
canvas . createRoundedRect ( x , y , width , height , r )
canvas . session . callCanvasFunc ( "stroke" )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) FillAndStrokeRoundedRect ( x , y , width , height , r float64 ) {
2022-11-02 20:08:02 +03:00
canvas . createRoundedRect ( x , y , width , height , r )
canvas . session . callCanvasFunc ( "fill" )
canvas . session . callCanvasFunc ( "stroke" )
2021-09-07 17:36:50 +03:00
}
2022-11-02 20:08:02 +03:00
func ( canvas * canvasData ) createEllipse ( x , y , radiusX , radiusY , rotation float64 ) {
canvas . session . callCanvasFunc ( "beginPath" )
canvas . session . callCanvasFunc ( "moveTo" , x + radiusX , y )
canvas . session . callCanvasFunc ( "ellipse" , x , y , radiusX , radiusY , rotation , 0 , math . Pi * 2 )
//canvas.session.callCanvasFunc("closePath")
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) FillEllipse ( x , y , radiusX , radiusY , rotation float64 ) {
if radiusX >= 0 && radiusY >= 0 {
2022-11-02 20:08:02 +03:00
canvas . createEllipse ( x , y , radiusX , radiusY , rotation )
canvas . session . callCanvasFunc ( "fill" )
2021-09-07 17:36:50 +03:00
}
}
func ( canvas * canvasData ) StrokeEllipse ( x , y , radiusX , radiusY , rotation float64 ) {
if radiusX >= 0 && radiusY >= 0 {
2022-11-02 20:08:02 +03:00
canvas . createEllipse ( x , y , radiusX , radiusY , rotation )
canvas . session . callCanvasFunc ( "stroke" )
2021-09-07 17:36:50 +03:00
}
}
func ( canvas * canvasData ) FillAndStrokeEllipse ( x , y , radiusX , radiusY , rotation float64 ) {
if radiusX >= 0 && radiusY >= 0 {
2022-11-02 20:08:02 +03:00
canvas . createEllipse ( x , y , radiusX , radiusY , rotation )
canvas . session . callCanvasFunc ( "fill" )
canvas . session . callCanvasFunc ( "stroke" )
2021-09-07 17:36:50 +03:00
}
}
2022-11-02 20:08:02 +03:00
/ *
2021-09-07 17:36:50 +03:00
func ( canvas * canvasData ) writePointArgs ( x , y float64 ) {
canvas . script . WriteString ( strconv . FormatFloat ( x , 'g' , - 1 , 64 ) )
canvas . script . WriteRune ( ',' )
canvas . script . WriteString ( strconv . FormatFloat ( y , 'g' , - 1 , 64 ) )
}
func ( canvas * canvasData ) writeStringArgs ( text string , script * strings . Builder ) {
//rText := []rune(text)
for _ , ch := range text {
switch ch {
case '\t' :
script . WriteString ( ` \t ` )
case '\n' :
script . WriteString ( ` \n ` )
case '\r' :
script . WriteString ( ` \r ` )
case '\\' :
script . WriteString ( ` \\ ` )
case '"' :
script . WriteString ( ` \" ` )
case '\'' :
script . WriteString ( ` \' ` )
default :
if ch < ' ' {
script . WriteString ( fmt . Sprintf ( "\\x%02X" , int ( ch ) ) )
} else {
script . WriteRune ( ch )
}
}
}
}
2022-11-02 20:08:02 +03:00
* /
2021-09-07 17:36:50 +03:00
func ( canvas * canvasData ) FillText ( x , y float64 , text string ) {
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasFunc ( "fillText" , text , x , y )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) StrokeText ( x , y float64 , text string ) {
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasFunc ( "strokeText" , text , x , y )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) FillPath ( path Path ) {
2024-08-20 20:01:26 +03:00
canvas . session . callCanvasFunc ( "fill" , path . obj ( ) )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) StrokePath ( path Path ) {
2024-08-20 20:01:26 +03:00
canvas . session . callCanvasFunc ( "stroke" , path . obj ( ) )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) FillAndStrokePath ( path Path ) {
2024-08-20 20:01:26 +03:00
canvas . session . callCanvasFunc ( "fill" , path . obj ( ) )
canvas . session . callCanvasFunc ( "stroke" , path . obj ( ) )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) DrawLine ( x0 , y0 , x1 , y1 float64 ) {
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasFunc ( "beginPath" )
canvas . session . callCanvasFunc ( "moveTo" , x0 , y0 )
canvas . session . callCanvasFunc ( "lineTo" , x1 , y1 )
canvas . session . callCanvasFunc ( "stroke" )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) DrawImage ( x , y float64 , image Image ) {
if image == nil || image . LoadingStatus ( ) != ImageReady {
return
}
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasImageFunc ( image . URL ( ) , "" , "drawImage" , x , y )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) DrawImageInRect ( x , y , width , height float64 , image Image ) {
if image == nil || image . LoadingStatus ( ) != ImageReady {
return
}
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasImageFunc ( image . URL ( ) , "" , "drawImage" , x , y , width , height )
2021-09-07 17:36:50 +03:00
}
func ( canvas * canvasData ) DrawImageFragment ( srcX , srcY , srcWidth , srcHeight , dstX , dstY , dstWidth , dstHeight float64 , image Image ) {
if image == nil || image . LoadingStatus ( ) != ImageReady {
return
}
2022-11-02 20:08:02 +03:00
canvas . session . callCanvasImageFunc ( image . URL ( ) , "" , "drawImage" , srcX , srcY , srcWidth , srcHeight , dstX , dstY , dstWidth , dstHeight )
2021-09-07 17:36:50 +03:00
}