mirror of https://github.com/anoshenko/rui.git
				
				
				
			Canvas refactoring
This commit is contained in:
		
							parent
							
								
									b26525e892
								
							
						
					
					
						commit
						8200f98d0d
					
				
							
								
								
									
										48
									
								
								appWasm.go
								
								
								
								
							
							
						
						
									
										48
									
								
								appWasm.go
								
								
								
								
							|  | @ -4,6 +4,8 @@ package rui | |||
| 
 | ||||
| import ( | ||||
| 	_ "embed" | ||||
| 	"encoding/base64" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 	"syscall/js" | ||||
| ) | ||||
|  | @ -112,10 +114,46 @@ func (app *wasmApp) createSession() Session { | |||
| 	return session | ||||
| } | ||||
| 
 | ||||
| func (app *wasmApp) init() { | ||||
| func (app *wasmApp) init(params AppParams) { | ||||
| 
 | ||||
| 	app.params = params | ||||
| 
 | ||||
| 	document := js.Global().Get("document") | ||||
| 	body := document.Call("querySelector", "body") | ||||
| 	head := document.Call("querySelector", "head") | ||||
| 
 | ||||
| 	meta := document.Call("createElement", "meta") | ||||
| 	meta.Set("name", "viewport") | ||||
| 	meta.Set("content", "width=device-width") | ||||
| 	head.Call("appendChild", meta) | ||||
| 
 | ||||
| 	meta = document.Call("createElement", "base") | ||||
| 	meta.Set("target", "_blank") | ||||
| 	meta.Set("rel", "noopener") | ||||
| 	head.Call("appendChild", meta) | ||||
| 
 | ||||
| 	if params.Icon != "" { | ||||
| 		if image, ok := resources.images[params.Icon]; ok && image.fs != nil { | ||||
| 			dataType := map[string]string{ | ||||
| 				".svg":  "data:image/svg+xml", | ||||
| 				".png":  "data:image/png", | ||||
| 				".jpg":  "data:image/jpg", | ||||
| 				".jpeg": "data:image/jpg", | ||||
| 				".gif":  "data:image/gif", | ||||
| 			} | ||||
| 			ext := strings.ToLower(filepath.Ext(params.Icon)) | ||||
| 			if prefix, ok := dataType[ext]; ok { | ||||
| 				if data, err := image.fs.ReadFile(image.path); err == nil { | ||||
| 					meta = document.Call("createElement", "link") | ||||
| 					meta.Set("rel", "icon") | ||||
| 					meta.Set("href", prefix+";base64,"+base64.StdEncoding.EncodeToString(data)) | ||||
| 					head.Call("appendChild", meta) | ||||
| 				} else { | ||||
| 					DebugLog(err.Error()) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	script := document.Call("createElement", "script") | ||||
| 	script.Set("type", "text/javascript") | ||||
|  | @ -156,6 +194,11 @@ func (app *wasmApp) init() { | |||
| 	div.Set("download", "") | ||||
| 	div.Set("style", "display: none;") | ||||
| 	body.Call("appendChild", div) | ||||
| 
 | ||||
| 	if params.TitleColor != 0 { | ||||
| 		app.brige.runFunc("setTitleColor", params.TitleColor.cssString()) | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // StartApp - create the new wasmApp and start it
 | ||||
|  | @ -168,11 +211,10 @@ func StartApp(addr string, createContentFunc func(Session) SessionContent, param | |||
| 	} | ||||
| 
 | ||||
| 	app := new(wasmApp) | ||||
| 	app.params = params | ||||
| 	app.createContentFunc = createContentFunc | ||||
| 	app.brige = createWasmBrige() | ||||
| 
 | ||||
| 	app.init() | ||||
| 	app.init(params) | ||||
| 	<-app.close | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1795,4 +1795,17 @@ function getPropertyValue(answerID, elementId, name) { | |||
| 
 | ||||
| function appendStyles(styles) { | ||||
| 	document.querySelector('style').textContent += styles | ||||
| } | ||||
| } | ||||
| 
 | ||||
| function getCanvasContext(elementId) { | ||||
| 	const canvas = document.getElementById(elementId) | ||||
| 	const ctx = canvas.getContext('2d'); | ||||
| 	const dpr = window.devicePixelRatio || 1; | ||||
| 	//var gradient;
 | ||||
| 	//var path;
 | ||||
| 	//var img;
 | ||||
| 	ctx.canvas.width = dpr * canvas.clientWidth; | ||||
| 	ctx.canvas.height = dpr * canvas.clientHeight; | ||||
| 	ctx.scale(dpr, dpr); | ||||
| 	return ctx; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										543
									
								
								canvas.go
								
								
								
								
							
							
						
						
									
										543
									
								
								canvas.go
								
								
								
								
							|  | @ -1,7 +1,7 @@ | |||
| package rui | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
|  | @ -290,42 +290,24 @@ type Canvas interface { | |||
| 	// 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) | ||||
| 
 | ||||
| 	finishDraw() string | ||||
| 	finishDraw() | ||||
| } | ||||
| 
 | ||||
| type canvasData struct { | ||||
| 	view   CanvasView | ||||
| 	script strings.Builder | ||||
| 	view    CanvasView | ||||
| 	session Session | ||||
| } | ||||
| 
 | ||||
| func newCanvas(view CanvasView) Canvas { | ||||
| 	canvas := new(canvasData) | ||||
| 	canvas.view = view | ||||
| 	canvas.script.Grow(4096) | ||||
| 	canvas.script.WriteString(`const canvas = document.getElementById('`) | ||||
| 	canvas.script.WriteString(view.htmlID()) | ||||
| 	canvas.script.WriteString(`'); | ||||
| const ctx = canvas.getContext('2d'); | ||||
| const dpr = window.devicePixelRatio || 1; | ||||
| var gradient; | ||||
| var path; | ||||
| var img; | ||||
| ctx.canvas.width = dpr * canvas.clientWidth; | ||||
| ctx.canvas.height = dpr * canvas.clientHeight; | ||||
| ctx.scale(dpr, dpr);`) | ||||
| 	/* | ||||
| 	   	canvas.script.WriteString(strconv.FormatFloat(view.canvasWidth(), 'g', -1, 64)) | ||||
| 	   	canvas.script.WriteString(`; | ||||
| 	   ctx.canvas.height = dpr * `) | ||||
| 	   	canvas.script.WriteString(strconv.FormatFloat(view.canvasHeight(), 'g', -1, 64)) | ||||
| 	   	canvas.script.WriteString(";\nctx.scale(dpr, dpr);") | ||||
| 	*/ | ||||
| 	canvas.session = view.Session() | ||||
| 	canvas.session.cavnasStart(view.htmlID()) | ||||
| 	return canvas | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) finishDraw() string { | ||||
| 	canvas.script.WriteString("\n") | ||||
| 	return canvas.script.String() | ||||
| func (canvas *canvasData) finishDraw() { | ||||
| 	canvas.session.cavnasFinish() | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) View() CanvasView { | ||||
|  | @ -347,162 +329,102 @@ func (canvas *canvasData) Height() float64 { | |||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) Save() { | ||||
| 	canvas.script.WriteString("\nctx.save();") | ||||
| 	canvas.session.callCanvasFunc("save") | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) Restore() { | ||||
| 	canvas.script.WriteString("\nctx.restore();") | ||||
| 	canvas.session.callCanvasFunc("restore") | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) ClipRect(x, y, width, height float64) { | ||||
| 	canvas.script.WriteString("\nctx.beginPath();\nctx.rect(") | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(x, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(y, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(width, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(height, 'g', -1, 64)) | ||||
| 	canvas.script.WriteString(");\nctx.clip();") | ||||
| 	canvas.session.callCanvasFunc("beginPath") | ||||
| 	canvas.session.callCanvasFunc("rect", x, y, width, height) | ||||
| 	canvas.session.callCanvasFunc("clip") | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) ClipPath(path Path) { | ||||
| 	canvas.script.WriteString(path.scriptText()) | ||||
| 	canvas.script.WriteString("\nctx.clip();") | ||||
| 	path.create(canvas.session) | ||||
| 	canvas.session.callCanvasFunc("clip") | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetScale(x, y float64) { | ||||
| 	canvas.script.WriteString("\nctx.scale(") | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(x, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(y, 'g', -1, 64)) | ||||
| 	canvas.script.WriteString(");") | ||||
| 	canvas.session.callCanvasFunc("scale", x, y) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetTranslation(x, y float64) { | ||||
| 	canvas.script.WriteString("\nctx.translate(") | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(x, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(y, 'g', -1, 64)) | ||||
| 	canvas.script.WriteString(");") | ||||
| 	canvas.session.callCanvasFunc("translate", x, y) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetRotation(angle float64) { | ||||
| 	canvas.script.WriteString("\nctx.rotate(") | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(angle, 'g', -1, 64)) | ||||
| 	canvas.script.WriteString(");") | ||||
| 	canvas.session.callCanvasFunc("rotate", angle) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetTransformation(xScale, yScale, xSkew, ySkew, dx, dy float64) { | ||||
| 	canvas.script.WriteString("\nctx.transform(") | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(xScale, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(ySkew, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(xSkew, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(yScale, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(dx, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(dy, 'g', -1, 64)) | ||||
| 	canvas.script.WriteString(");") | ||||
| 	canvas.session.callCanvasFunc("transform", xScale, ySkew, xSkew, yScale, dx, dy) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) ResetTransformation() { | ||||
| 	canvas.script.WriteString("\nctx.resetTransform();\nctx.scale(dpr, dpr);") | ||||
| 	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);")
 | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetSolidColorFillStyle(color Color) { | ||||
| 	canvas.script.WriteString("\nctx.fillStyle = \"") | ||||
| 	canvas.script.WriteString(color.cssString()) | ||||
| 	canvas.script.WriteString(`";`) | ||||
| 	canvas.session.updateCanvasProperty("fillStyle", color.cssString()) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetSolidColorStrokeStyle(color Color) { | ||||
| 	canvas.script.WriteString("\nctx.strokeStyle = \"") | ||||
| 	canvas.script.WriteString(color.cssString()) | ||||
| 	canvas.script.WriteString(`";`) | ||||
| 	canvas.session.updateCanvasProperty("strokeStyle", color.cssString()) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) setLinearGradient(x0, y0 float64, color0 Color, x1, y1 float64, color1 Color, stopPoints []GradientPoint) { | ||||
| 	canvas.script.WriteString("\ngradient = ctx.createLinearGradient(") | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(x0, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(y0, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(x1, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(y1, 'g', -1, 64)) | ||||
| 	canvas.script.WriteString(");\ngradient.addColorStop(0, '") | ||||
| 	canvas.script.WriteString(color0.cssString()) | ||||
| 	canvas.script.WriteString("');") | ||||
| 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()) | ||||
| 
 | ||||
| 	for _, point := range stopPoints { | ||||
| 		if point.Offset >= 0 && point.Offset <= 1 { | ||||
| 			canvas.script.WriteString("\ngradient.addColorStop(") | ||||
| 			canvas.script.WriteString(strconv.FormatFloat(point.Offset, 'g', -1, 64)) | ||||
| 			canvas.script.WriteString(", '") | ||||
| 			canvas.script.WriteString(point.Color.cssString()) | ||||
| 			canvas.script.WriteString("');") | ||||
| 			canvas.session.callCanvasVarFunc(gradient, "addColorStop", point.Offset, point.Color.cssString()) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	canvas.script.WriteString("\ngradient.addColorStop(1, '") | ||||
| 	canvas.script.WriteString(color1.cssString()) | ||||
| 	canvas.script.WriteString("');") | ||||
| 	canvas.session.callCanvasVarFunc(gradient, "addColorStop", 1, color1.cssString()) | ||||
| 	return gradient | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetLinearGradientFillStyle(x0, y0 float64, color0 Color, x1, y1 float64, color1 Color, stopPoints []GradientPoint) { | ||||
| 	canvas.setLinearGradient(x0, y0, color0, x1, y1, color1, stopPoints) | ||||
| 	canvas.script.WriteString("\nctx.fillStyle = gradient;") | ||||
| 	gradient := canvas.createLinearGradient(x0, y0, color0, x1, y1, color1, stopPoints) | ||||
| 	canvas.session.updateCanvasProperty("fillStyle", gradient) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetLinearGradientStrokeStyle(x0, y0 float64, color0 Color, x1, y1 float64, color1 Color, stopPoints []GradientPoint) { | ||||
| 	canvas.setLinearGradient(x0, y0, color0, x1, y1, color1, stopPoints) | ||||
| 	canvas.script.WriteString("\nctx.strokeStyle = gradient;") | ||||
| 	gradient := canvas.createLinearGradient(x0, y0, color0, x1, y1, color1, stopPoints) | ||||
| 	canvas.session.updateCanvasProperty("strokeStyle", gradient) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) setRadialGradient(x0, y0, r0 float64, color0 Color, x1, y1, r1 float64, color1 Color, stopPoints []GradientPoint) { | ||||
| 	canvas.script.WriteString("\ngradient = ctx.createRadialGradient(") | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(x0, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(y0, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(r0, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(x1, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(y1, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(r1, 'g', -1, 64)) | ||||
| 	canvas.script.WriteString(");\ngradient.addColorStop(0, '") | ||||
| 	canvas.script.WriteString(color0.cssString()) | ||||
| 	canvas.script.WriteString("');") | ||||
| 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()) | ||||
| 
 | ||||
| 	for _, point := range stopPoints { | ||||
| 		if point.Offset >= 0 && point.Offset <= 1 { | ||||
| 			canvas.script.WriteString("\ngradient.addColorStop(") | ||||
| 			canvas.script.WriteString(strconv.FormatFloat(point.Offset, 'g', -1, 64)) | ||||
| 			canvas.script.WriteString(", '") | ||||
| 			canvas.script.WriteString(point.Color.cssString()) | ||||
| 			canvas.script.WriteString("');") | ||||
| 			canvas.session.callCanvasVarFunc(gradient, "addColorStop", point.Offset, point.Color.cssString()) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	canvas.script.WriteString("\ngradient.addColorStop(1, '") | ||||
| 	canvas.script.WriteString(color1.cssString()) | ||||
| 	canvas.script.WriteString("');") | ||||
| 	canvas.session.callCanvasVarFunc(gradient, "addColorStop", 1, color1.cssString()) | ||||
| 	return gradient | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetRadialGradientFillStyle(x0, y0, r0 float64, color0 Color, x1, y1, r1 float64, color1 Color, stopPoints []GradientPoint) { | ||||
| 	canvas.setRadialGradient(x0, y0, r0, color0, x1, y1, r1, color1, stopPoints) | ||||
| 	canvas.script.WriteString("\nctx.fillStyle = gradient;") | ||||
| 	gradient := canvas.createRadialGradient(x0, y0, r0, color0, x1, y1, r1, color1, stopPoints) | ||||
| 	canvas.session.updateCanvasProperty("fillStyle", gradient) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetRadialGradientStrokeStyle(x0, y0, r0 float64, color0 Color, x1, y1, r1 float64, color1 Color, stopPoints []GradientPoint) { | ||||
| 	canvas.setRadialGradient(x0, y0, r0, color0, x1, y1, r1, color1, stopPoints) | ||||
| 	canvas.script.WriteString("\nctx.strokeStyle = gradient;") | ||||
| 	gradient := canvas.createRadialGradient(x0, y0, r0, color0, x1, y1, r1, color1, stopPoints) | ||||
| 	canvas.session.updateCanvasProperty("strokeStyle", gradient) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetImageFillStyle(image Image, repeat int) { | ||||
|  | @ -528,89 +450,70 @@ func (canvas *canvasData) SetImageFillStyle(image Image, repeat int) { | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	canvas.script.WriteString("\nimg = images.get('") | ||||
| 	canvas.script.WriteString(image.URL()) | ||||
| 	canvas.script.WriteString("');\nif (img) {\nctx.fillStyle = ctx.createPattern(img,'") | ||||
| 	canvas.script.WriteString(repeatText) | ||||
| 	canvas.script.WriteString("');\n}") | ||||
| 	canvas.session.callCanvasImageFunc(image.URL(), "fillStyle", "createPattern", repeatText) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetLineWidth(width float64) { | ||||
| 	if width > 0 { | ||||
| 		canvas.script.WriteString("\nctx.lineWidth = '") | ||||
| 		canvas.script.WriteString(strconv.FormatFloat(width, 'g', -1, 64)) | ||||
| 		canvas.script.WriteString("';") | ||||
| 		canvas.session.updateCanvasProperty("lineWidth", width) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetLineJoin(join int) { | ||||
| 	switch join { | ||||
| 	case MiterJoin: | ||||
| 		canvas.script.WriteString("\nctx.lineJoin = 'miter';") | ||||
| 		canvas.session.updateCanvasProperty("lineJoin", "miter") | ||||
| 
 | ||||
| 	case RoundJoin: | ||||
| 		canvas.script.WriteString("\nctx.lineJoin = 'round';") | ||||
| 		canvas.session.updateCanvasProperty("lineJoin", "round") | ||||
| 
 | ||||
| 	case BevelJoin: | ||||
| 		canvas.script.WriteString("\nctx.lineJoin = 'bevel';") | ||||
| 		canvas.session.updateCanvasProperty("lineJoin", "bevel") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetLineCap(cap int) { | ||||
| 	switch cap { | ||||
| 	case ButtCap: | ||||
| 		canvas.script.WriteString("\nctx.lineCap = 'butt';") | ||||
| 		canvas.session.updateCanvasProperty("lineCap", "butt") | ||||
| 
 | ||||
| 	case RoundCap: | ||||
| 		canvas.script.WriteString("\nctx.lineCap = 'round';") | ||||
| 		canvas.session.updateCanvasProperty("lineCap", "round") | ||||
| 
 | ||||
| 	case SquareCap: | ||||
| 		canvas.script.WriteString("\nctx.lineCap = 'square';") | ||||
| 		canvas.session.updateCanvasProperty("lineCap", "square") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetLineDash(dash []float64, offset float64) { | ||||
| 	canvas.script.WriteString("\nctx.setLineDash([") | ||||
| 	for i, d := range dash { | ||||
| 		if i > 0 { | ||||
| 			canvas.script.WriteString(",") | ||||
| 		} | ||||
| 		canvas.script.WriteString(strconv.FormatFloat(d, 'g', -1, 64)) | ||||
| 	} | ||||
| 
 | ||||
| 	canvas.script.WriteString("]);") | ||||
| 	canvas.session.callCanvasFunc("setLineDash", dash) | ||||
| 	if offset >= 0 { | ||||
| 		canvas.script.WriteString("\nctx.lineDashOffset = '") | ||||
| 		canvas.script.WriteString(strconv.FormatFloat(offset, 'g', -1, 64)) | ||||
| 		canvas.script.WriteString("';") | ||||
| 		canvas.session.updateCanvasProperty("lineDashOffset", offset) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) writeFont(name string, script *strings.Builder) { | ||||
| 	names := strings.Split(name, ",") | ||||
| 	lead := " " | ||||
| 	for _, font := range names { | ||||
| 		font = strings.Trim(font, " \n\"'") | ||||
| 		script.WriteString(lead) | ||||
| 		lead = "," | ||||
| 		if strings.Contains(font, " ") { | ||||
| 			script.WriteRune('"') | ||||
| 			script.WriteString(font) | ||||
| 			script.WriteRune('"') | ||||
| 		} else { | ||||
| 			script.WriteString(font) | ||||
| /* | ||||
| 	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) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return buffer.String() | ||||
| 	} | ||||
| 	script.WriteString("';") | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetFont(name string, size SizeUnit) { | ||||
| 	canvas.script.WriteString("\nctx.font = '") | ||||
| 	canvas.script.WriteString(size.cssString("1rem", canvas.View().Session())) | ||||
| 	canvas.writeFont(name, &canvas.script) | ||||
| } | ||||
| 
 | ||||
| */ | ||||
| func (canvas *canvasData) fontWithParams(name string, size SizeUnit, params FontParams) string { | ||||
| 	buffer := allocStringBuilder() | ||||
| 	defer freeStringBuilder(buffer) | ||||
|  | @ -672,135 +575,76 @@ func (canvas *canvasData) fontWithParams(name string, size SizeUnit, params Font | |||
| 	return buffer.String() | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) setFontWithParams(name string, size SizeUnit, params FontParams, script *strings.Builder) { | ||||
| 	script.WriteString("\nctx.font = '") | ||||
| 	if params.Italic { | ||||
| 		script.WriteString("italic ") | ||||
| 	} | ||||
| 	if params.SmallCaps { | ||||
| 		script.WriteString("small-caps ") | ||||
| 	} | ||||
| 	if params.Weight > 0 && params.Weight <= 9 { | ||||
| 		switch params.Weight { | ||||
| 		case 4: | ||||
| 			script.WriteString("normal ") | ||||
| 		case 7: | ||||
| 			script.WriteString("bold ") | ||||
| 		default: | ||||
| 			script.WriteString(strconv.Itoa(params.Weight * 100)) | ||||
| 			script.WriteRune(' ') | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	script.WriteString(size.cssString("1rem", canvas.View().Session())) | ||||
| 	switch params.LineHeight.Type { | ||||
| 	case Auto: | ||||
| 
 | ||||
| 	case SizeInPercent: | ||||
| 		if params.LineHeight.Value != 100 { | ||||
| 			script.WriteString("/") | ||||
| 			script.WriteString(strconv.FormatFloat(params.LineHeight.Value/100, 'g', -1, 64)) | ||||
| 		} | ||||
| 
 | ||||
| 	case SizeInFraction: | ||||
| 		if params.LineHeight.Value != 1 { | ||||
| 			script.WriteString("/") | ||||
| 			script.WriteString(strconv.FormatFloat(params.LineHeight.Value, 'g', -1, 64)) | ||||
| 		} | ||||
| 
 | ||||
| 	default: | ||||
| 		script.WriteString("/") | ||||
| 		script.WriteString(params.LineHeight.cssString("", canvas.View().Session())) | ||||
| 	} | ||||
| 
 | ||||
| 	canvas.writeFont(name, script) | ||||
| func (canvas *canvasData) SetFont(name string, size SizeUnit) { | ||||
| 	canvas.session.updateCanvasProperty("font", canvas.fontWithParams(name, size, FontParams{})) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetFontWithParams(name string, size SizeUnit, params FontParams) { | ||||
| 	canvas.setFontWithParams(name, size, params, &canvas.script) | ||||
| 	canvas.session.updateCanvasProperty("font", canvas.fontWithParams(name, size, params)) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) TextMetrics(text string, fontName string, fontSize SizeUnit, fontParams FontParams) TextMetrics { | ||||
| 	view := canvas.View() | ||||
| 	return view.Session().canvasTextMetrics(view.htmlID(), canvas.fontWithParams(fontName, fontSize, fontParams), text) | ||||
| 	return canvas.session.canvasTextMetrics(canvas.view.htmlID(), canvas.fontWithParams(fontName, fontSize, fontParams), text) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetTextBaseline(baseline int) { | ||||
| 	switch baseline { | ||||
| 	case AlphabeticBaseline: | ||||
| 		canvas.script.WriteString("\nctx.textBaseline = 'alphabetic';") | ||||
| 		canvas.session.updateCanvasProperty("textBaseline", "alphabetic") | ||||
| 	case TopBaseline: | ||||
| 		canvas.script.WriteString("\nctx.textBaseline = 'top';") | ||||
| 		canvas.session.updateCanvasProperty("textBaseline", "top") | ||||
| 	case MiddleBaseline: | ||||
| 		canvas.script.WriteString("\nctx.textBaseline = 'middle';") | ||||
| 		canvas.session.updateCanvasProperty("textBaseline", "middle") | ||||
| 	case BottomBaseline: | ||||
| 		canvas.script.WriteString("\nctx.textBaseline = 'bottom';") | ||||
| 		canvas.session.updateCanvasProperty("textBaseline", "bottom") | ||||
| 	case HangingBaseline: | ||||
| 		canvas.script.WriteString("\nctx.textBaseline = 'hanging';") | ||||
| 		canvas.session.updateCanvasProperty("textBaseline", "hanging") | ||||
| 	case IdeographicBaseline: | ||||
| 		canvas.script.WriteString("\nctx.textBaseline = 'ideographic';") | ||||
| 		canvas.session.updateCanvasProperty("textBaseline", "ideographic") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetTextAlign(align int) { | ||||
| 	switch align { | ||||
| 	case LeftAlign: | ||||
| 		canvas.script.WriteString("\nctx.textAlign = 'left';") | ||||
| 		canvas.session.updateCanvasProperty("textAlign", "left") | ||||
| 	case RightAlign: | ||||
| 		canvas.script.WriteString("\nctx.textAlign = 'right';") | ||||
| 		canvas.session.updateCanvasProperty("textAlign", "right") | ||||
| 	case CenterAlign: | ||||
| 		canvas.script.WriteString("\nctx.textAlign = 'center';") | ||||
| 		canvas.session.updateCanvasProperty("textAlign", "center") | ||||
| 	case StartAlign: | ||||
| 		canvas.script.WriteString("\nctx.textAlign = 'start';") | ||||
| 		canvas.session.updateCanvasProperty("textAlign", "start") | ||||
| 	case EndAlign: | ||||
| 		canvas.script.WriteString("\nctx.textAlign = 'end';") | ||||
| 		canvas.session.updateCanvasProperty("textAlign", "end") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) SetShadow(offsetX, offsetY, blur float64, color Color) { | ||||
| 	if color.Alpha() > 0 && blur >= 0 { | ||||
| 		canvas.script.WriteString("\nctx.shadowColor = '") | ||||
| 		canvas.script.WriteString(color.cssString()) | ||||
| 		canvas.script.WriteString("';\nctx.shadowOffsetX = ") | ||||
| 		canvas.script.WriteString(strconv.FormatFloat(offsetX, 'g', -1, 64)) | ||||
| 		canvas.script.WriteString(";\nctx.shadowOffsetY = ") | ||||
| 		canvas.script.WriteString(strconv.FormatFloat(offsetY, 'g', -1, 64)) | ||||
| 		canvas.script.WriteString(";\nctx.shadowBlur = ") | ||||
| 		canvas.script.WriteString(strconv.FormatFloat(blur, 'g', -1, 64)) | ||||
| 		canvas.script.WriteString(";") | ||||
| 		canvas.session.updateCanvasProperty("shadowColor", color.cssString()) | ||||
| 		canvas.session.updateCanvasProperty("shadowOffsetX", offsetX) | ||||
| 		canvas.session.updateCanvasProperty("shadowOffsetY", offsetY) | ||||
| 		canvas.session.updateCanvasProperty("shadowBlur", blur) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) ResetShadow() { | ||||
| 	canvas.script.WriteString("\nctx.shadowColor = 'rgba(0,0,0,0)';\nctx.shadowOffsetX = 0;\nctx.shadowOffsetY = 0;\nctx.shadowBlur = 0;") | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) writeRectArgs(x, y, width, height float64) { | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(x, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(y, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(width, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(height, 'g', -1, 64)) | ||||
| 	canvas.session.updateCanvasProperty("shadowColor", "rgba(0,0,0,0)") | ||||
| 	canvas.session.updateCanvasProperty("shadowOffsetX", 0) | ||||
| 	canvas.session.updateCanvasProperty("shadowOffsetY", 0) | ||||
| 	canvas.session.updateCanvasProperty("shadowBlur", 0) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) ClearRect(x, y, width, height float64) { | ||||
| 	canvas.script.WriteString("\nctx.clearRect(") | ||||
| 	canvas.writeRectArgs(x, y, width, height) | ||||
| 	canvas.script.WriteString(");") | ||||
| 	canvas.session.callCanvasFunc("clearRect", x, y, width, height) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) FillRect(x, y, width, height float64) { | ||||
| 	canvas.script.WriteString("\nctx.fillRect(") | ||||
| 	canvas.writeRectArgs(x, y, width, height) | ||||
| 	canvas.script.WriteString(");") | ||||
| 	canvas.session.callCanvasFunc("fillRect", x, y, width, height) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) StrokeRect(x, y, width, height float64) { | ||||
| 	canvas.script.WriteString("\nctx.strokeRect(") | ||||
| 	canvas.writeRectArgs(x, y, width, height) | ||||
| 	canvas.script.WriteString(");") | ||||
| 	canvas.session.callCanvasFunc("strokeRect", x, y, width, height) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) FillAndStrokeRect(x, y, width, height float64) { | ||||
|  | @ -808,7 +652,7 @@ func (canvas *canvasData) FillAndStrokeRect(x, y, width, height float64) { | |||
| 	canvas.StrokeRect(x, y, width, height) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) writeRoundedRect(x, y, width, height, r float64) { | ||||
| func (canvas *canvasData) createRoundedRect(x, y, width, height, r float64) { | ||||
| 	left := strconv.FormatFloat(x, 'g', -1, 64) | ||||
| 	top := strconv.FormatFloat(y, 'g', -1, 64) | ||||
| 	right := strconv.FormatFloat(x+width, 'g', -1, 64) | ||||
|  | @ -818,104 +662,65 @@ func (canvas *canvasData) writeRoundedRect(x, y, width, height, r float64) { | |||
| 	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) | ||||
| 	canvas.script.WriteString("\nctx.beginPath();\nctx.moveTo(") | ||||
| 	canvas.script.WriteString(left) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(topR) | ||||
| 	canvas.script.WriteString(");\nctx.arc(") | ||||
| 	canvas.script.WriteString(leftR) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(topR) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(radius) | ||||
| 	canvas.script.WriteString(",Math.PI,Math.PI*3/2);\nctx.lineTo(") | ||||
| 	canvas.script.WriteString(rightR) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(top) | ||||
| 	canvas.script.WriteString(");\nctx.arc(") | ||||
| 	canvas.script.WriteString(rightR) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(topR) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(radius) | ||||
| 	canvas.script.WriteString(",Math.PI*3/2,Math.PI*2);\nctx.lineTo(") | ||||
| 	canvas.script.WriteString(right) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(bottomR) | ||||
| 	canvas.script.WriteString(");\nctx.arc(") | ||||
| 	canvas.script.WriteString(rightR) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(bottomR) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(radius) | ||||
| 	canvas.script.WriteString(",0,Math.PI/2);\nctx.lineTo(") | ||||
| 	canvas.script.WriteString(leftR) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(bottom) | ||||
| 	canvas.script.WriteString(");\nctx.arc(") | ||||
| 	canvas.script.WriteString(leftR) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(bottomR) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(radius) | ||||
| 	canvas.script.WriteString(",Math.PI/2,Math.PI);\nctx.closePath();") | ||||
| 
 | ||||
| 	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") | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) FillRoundedRect(x, y, width, height, r float64) { | ||||
| 	canvas.writeRoundedRect(x, y, width, height, r) | ||||
| 	canvas.script.WriteString("\nctx.fill();") | ||||
| 	canvas.createRoundedRect(x, y, width, height, r) | ||||
| 	canvas.session.callCanvasFunc("fill") | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) StrokeRoundedRect(x, y, width, height, r float64) { | ||||
| 	canvas.writeRoundedRect(x, y, width, height, r) | ||||
| 	canvas.script.WriteString("\nctx.stroke();") | ||||
| 	canvas.createRoundedRect(x, y, width, height, r) | ||||
| 	canvas.session.callCanvasFunc("stroke") | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) FillAndStrokeRoundedRect(x, y, width, height, r float64) { | ||||
| 	canvas.writeRoundedRect(x, y, width, height, r) | ||||
| 	canvas.script.WriteString("\nctx.fill();\nctx.stroke();") | ||||
| 	canvas.createRoundedRect(x, y, width, height, r) | ||||
| 	canvas.session.callCanvasFunc("fill") | ||||
| 	canvas.session.callCanvasFunc("stroke") | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) writeEllipse(x, y, radiusX, radiusY, rotation float64) { | ||||
| 	yText := strconv.FormatFloat(y, 'g', -1, 64) | ||||
| 	canvas.script.WriteString("\nctx.beginPath();\nctx.moveTo(") | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(x+radiusX, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(yText) | ||||
| 	canvas.script.WriteString(");\nctx.ellipse(") | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(x, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(yText) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(radiusX, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(radiusY, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(rotation, 'g', -1, 64)) | ||||
| 	canvas.script.WriteString(",0,Math.PI*2);") | ||||
| 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")
 | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) FillEllipse(x, y, radiusX, radiusY, rotation float64) { | ||||
| 	if radiusX >= 0 && radiusY >= 0 { | ||||
| 		canvas.writeEllipse(x, y, radiusX, radiusY, rotation) | ||||
| 		canvas.script.WriteString("\nctx.fill();") | ||||
| 		canvas.createEllipse(x, y, radiusX, radiusY, rotation) | ||||
| 		canvas.session.callCanvasFunc("fill") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) StrokeEllipse(x, y, radiusX, radiusY, rotation float64) { | ||||
| 	if radiusX >= 0 && radiusY >= 0 { | ||||
| 		canvas.writeEllipse(x, y, radiusX, radiusY, rotation) | ||||
| 		canvas.script.WriteString("\nctx.stroke();") | ||||
| 		canvas.createEllipse(x, y, radiusX, radiusY, rotation) | ||||
| 		canvas.session.callCanvasFunc("stroke") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) FillAndStrokeEllipse(x, y, radiusX, radiusY, rotation float64) { | ||||
| 	if radiusX >= 0 && radiusY >= 0 { | ||||
| 		canvas.writeEllipse(x, y, radiusX, radiusY, rotation) | ||||
| 		canvas.script.WriteString("\nctx.fill();\nctx.stroke();") | ||||
| 		canvas.createEllipse(x, y, radiusX, radiusY, rotation) | ||||
| 		canvas.session.callCanvasFunc("fill") | ||||
| 		canvas.session.callCanvasFunc("stroke") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| func (canvas *canvasData) writePointArgs(x, y float64) { | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(x, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
|  | @ -947,101 +752,59 @@ func (canvas *canvasData) writeStringArgs(text string, script *strings.Builder) | |||
| 		} | ||||
| 	} | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| func (canvas *canvasData) FillText(x, y float64, text string) { | ||||
| 	canvas.script.WriteString("\nctx.fillText('") | ||||
| 	canvas.writeStringArgs(text, &canvas.script) | ||||
| 	canvas.script.WriteString(`',`) | ||||
| 	canvas.writePointArgs(x, y) | ||||
| 	canvas.script.WriteString(");") | ||||
| 	canvas.session.callCanvasFunc("fillText", text, x, y) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) StrokeText(x, y float64, text string) { | ||||
| 	canvas.script.WriteString("\nctx.strokeText('") | ||||
| 	canvas.writeStringArgs(text, &canvas.script) | ||||
| 	canvas.script.WriteString(`',`) | ||||
| 	canvas.writePointArgs(x, y) | ||||
| 	canvas.script.WriteString(");") | ||||
| 	canvas.session.callCanvasFunc("strokeText", text, x, y) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) FillPath(path Path) { | ||||
| 	canvas.script.WriteString(path.scriptText()) | ||||
| 	canvas.script.WriteString("\nctx.fill();") | ||||
| 	path.create(canvas.session) | ||||
| 	canvas.session.callCanvasFunc("fill") | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) StrokePath(path Path) { | ||||
| 	canvas.script.WriteString(path.scriptText()) | ||||
| 	canvas.script.WriteString("\nctx.stroke();") | ||||
| 	path.create(canvas.session) | ||||
| 	canvas.session.callCanvasFunc("stroke") | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) FillAndStrokePath(path Path) { | ||||
| 	canvas.script.WriteString(path.scriptText()) | ||||
| 	canvas.script.WriteString("\nctx.fill();\nctx.stroke();") | ||||
| 	path.create(canvas.session) | ||||
| 	canvas.session.callCanvasFunc("fill") | ||||
| 	canvas.session.callCanvasFunc("stroke") | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) DrawLine(x0, y0, x1, y1 float64) { | ||||
| 	canvas.script.WriteString("\nctx.beginPath();\nctx.moveTo(") | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(x0, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(y0, 'g', -1, 64)) | ||||
| 	canvas.script.WriteString(");\nctx.lineTo(") | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(x1, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(y1, 'g', -1, 64)) | ||||
| 	canvas.script.WriteString(");\nctx.stroke();") | ||||
| 	canvas.session.callCanvasFunc("beginPath") | ||||
| 	canvas.session.callCanvasFunc("moveTo", x0, y0) | ||||
| 	canvas.session.callCanvasFunc("lineTo", x1, y1) | ||||
| 	canvas.session.callCanvasFunc("stroke") | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) DrawImage(x, y float64, image Image) { | ||||
| 	if image == nil || image.LoadingStatus() != ImageReady { | ||||
| 		return | ||||
| 	} | ||||
| 	canvas.script.WriteString("\nimg = images.get('") | ||||
| 	canvas.script.WriteString(image.URL()) | ||||
| 	canvas.script.WriteString("');\nif (img) {\nctx.drawImage(img,") | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(x, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(y, 'g', -1, 64)) | ||||
| 	canvas.script.WriteString(");\n}") | ||||
| 
 | ||||
| 	canvas.session.callCanvasImageFunc(image.URL(), "", "drawImage", x, y) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) DrawImageInRect(x, y, width, height float64, image Image) { | ||||
| 	if image == nil || image.LoadingStatus() != ImageReady { | ||||
| 		return | ||||
| 	} | ||||
| 	canvas.script.WriteString("\nimg = images.get('") | ||||
| 	canvas.script.WriteString(image.URL()) | ||||
| 	canvas.script.WriteString("');\nif (img) {\nctx.drawImage(img,") | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(x, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(y, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(width, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(height, 'g', -1, 64)) | ||||
| 	canvas.script.WriteString(");\n}") | ||||
| 
 | ||||
| 	canvas.session.callCanvasImageFunc(image.URL(), "", "drawImage", x, y, width, height) | ||||
| } | ||||
| 
 | ||||
| func (canvas *canvasData) DrawImageFragment(srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight float64, image Image) { | ||||
| 	if image == nil || image.LoadingStatus() != ImageReady { | ||||
| 		return | ||||
| 	} | ||||
| 	canvas.script.WriteString("\nimg = images.get('") | ||||
| 	canvas.script.WriteString(image.URL()) | ||||
| 	canvas.script.WriteString("');\nif (img) {\nctx.drawImage(img,") | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(srcX, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(srcY, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(srcWidth, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(srcHeight, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(dstX, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(dstY, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(dstWidth, 'g', -1, 64)) | ||||
| 	canvas.script.WriteRune(',') | ||||
| 	canvas.script.WriteString(strconv.FormatFloat(dstHeight, 'g', -1, 64)) | ||||
| 	canvas.script.WriteString(");\n}") | ||||
| 
 | ||||
| 	canvas.session.callCanvasImageFunc(image.URL(), "", "drawImage", srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight) | ||||
| } | ||||
|  |  | |||
|  | @ -107,7 +107,7 @@ func (canvasView *canvasViewData) Redraw() { | |||
| 		if canvasView.drawer != nil { | ||||
| 			canvasView.drawer(canvas) | ||||
| 		} | ||||
| 		canvasView.session.runScript(canvas.finishDraw()) | ||||
| 		canvas.finishDraw() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										63
									
								
								imageView.go
								
								
								
								
							
							
						
						
									
										63
									
								
								imageView.go
								
								
								
								
							|  | @ -1,7 +1,10 @@ | |||
| package rui | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/base64" | ||||
| 	"fmt" | ||||
| 	"path/filepath" | ||||
| 	"runtime" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
|  | @ -129,12 +132,10 @@ func (imageView *imageViewData) set(tag string, value any) bool { | |||
| 		if text, ok := value.(string); ok { | ||||
| 			imageView.properties[Source] = text | ||||
| 			if imageView.created { | ||||
| 				src := text | ||||
| 				if src != "" && src[0] == '@' { | ||||
| 					src, _ = imageProperty(imageView, Source, imageView.session) | ||||
| 				} | ||||
| 				src, srcset := imageView.src(text) | ||||
| 				imageView.session.updateProperty(imageView.htmlID(), "src", src) | ||||
| 				if srcset := imageView.srcSet(src); srcset != "" { | ||||
| 
 | ||||
| 				if srcset != "" { | ||||
| 					imageView.session.updateProperty(imageView.htmlID(), "srcset", srcset) | ||||
| 				} else { | ||||
| 					imageView.session.removeProperty(imageView.htmlID(), "srcset") | ||||
|  | @ -214,29 +215,51 @@ func (imageView *imageViewData) htmlTag() string { | |||
| 	return "img" | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| func (imageView *imageViewData) closeHTMLTag() bool { | ||||
| 	return false | ||||
| func (imageView *imageViewData) src(src string) (string, string) { | ||||
| 	if src != "" && src[0] == '@' { | ||||
| 		if image, ok := imageView.Session().ImageConstant(src[1:]); ok { | ||||
| 			src = image | ||||
| 		} else { | ||||
| 			src = "" | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if src != "" { | ||||
| 		srcset := imageView.srcSet(src) | ||||
| 		if runtime.GOOS == "js" { | ||||
| 			if image, ok := resources.images[src]; ok && image.fs != nil { | ||||
| 				dataType := map[string]string{ | ||||
| 					".svg":  "data:image/svg+xml", | ||||
| 					".png":  "data:image/png", | ||||
| 					".jpg":  "data:image/jpg", | ||||
| 					".jpeg": "data:image/jpg", | ||||
| 					".gif":  "data:image/gif", | ||||
| 				} | ||||
| 				ext := strings.ToLower(filepath.Ext(src)) | ||||
| 				if prefix, ok := dataType[ext]; ok { | ||||
| 					if data, err := image.fs.ReadFile(image.path); err == nil { | ||||
| 						return prefix + ";base64," + base64.StdEncoding.EncodeToString(data), "" | ||||
| 					} else { | ||||
| 						DebugLog(err.Error()) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return src, srcset | ||||
| 	} | ||||
| 	return "", "" | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| func (imageView *imageViewData) htmlProperties(self View, buffer *strings.Builder) { | ||||
| 
 | ||||
| 	imageView.viewData.htmlProperties(self, buffer) | ||||
| 
 | ||||
| 	if imageResource, ok := imageProperty(imageView, Source, imageView.Session()); ok && imageResource != "" { | ||||
| 		if imageResource[0] == '@' { | ||||
| 			if image, ok := imageView.Session().ImageConstant(imageResource[1:]); ok { | ||||
| 				imageResource = image | ||||
| 			} else { | ||||
| 				imageResource = "" | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if imageResource != "" { | ||||
| 		if src, srcset := imageView.src(imageResource); src != "" { | ||||
| 			buffer.WriteString(` src="`) | ||||
| 			buffer.WriteString(imageResource) | ||||
| 			buffer.WriteString(src) | ||||
| 			buffer.WriteString(`"`) | ||||
| 			if srcset := imageView.srcSet(imageResource); srcset != "" { | ||||
| 			if srcset != "" { | ||||
| 				buffer.WriteString(` srcset="`) | ||||
| 				buffer.WriteString(srcset) | ||||
| 				buffer.WriteString(`"`) | ||||
|  |  | |||
							
								
								
									
										110
									
								
								path.go
								
								
								
								
							
							
						
						
									
										110
									
								
								path.go
								
								
								
								
							|  | @ -1,10 +1,5 @@ | |||
| package rui | ||||
| 
 | ||||
| import ( | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| // Path is a path interface
 | ||||
| type Path interface { | ||||
| 	// Reset erases the Path
 | ||||
|  | @ -63,134 +58,79 @@ type Path interface { | |||
| 	// If the shape has already been closed or has only one point, this function does nothing.
 | ||||
| 	Close() | ||||
| 
 | ||||
| 	scriptText() string | ||||
| 	create(session Session) | ||||
| } | ||||
| 
 | ||||
| type pathElement struct { | ||||
| 	funcName string | ||||
| 	args     []any | ||||
| } | ||||
| 
 | ||||
| type pathData struct { | ||||
| 	script strings.Builder | ||||
| 	elements []pathElement | ||||
| } | ||||
| 
 | ||||
| // NewPath creates a new empty Path
 | ||||
| func NewPath() Path { | ||||
| 	path := new(pathData) | ||||
| 	path.script.Grow(4096) | ||||
| 	path.script.WriteString("\nctx.beginPath();") | ||||
| 	path.Reset() | ||||
| 	return path | ||||
| } | ||||
| 
 | ||||
| func (path *pathData) Reset() { | ||||
| 	path.script.Reset() | ||||
| 	path.script.WriteString("\nctx.beginPath();") | ||||
| 	path.elements = []pathElement{ | ||||
| 		pathElement{funcName: "beginPath", args: []any{}}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (path *pathData) MoveTo(x, y float64) { | ||||
| 	path.script.WriteString("\nctx.moveTo(") | ||||
| 	path.script.WriteString(strconv.FormatFloat(x, 'g', -1, 64)) | ||||
| 	path.script.WriteRune(',') | ||||
| 	path.script.WriteString(strconv.FormatFloat(y, 'g', -1, 64)) | ||||
| 	path.script.WriteString(");") | ||||
| 	path.elements = append(path.elements, pathElement{funcName: "moveTo", args: []any{x, y}}) | ||||
| } | ||||
| 
 | ||||
| func (path *pathData) LineTo(x, y float64) { | ||||
| 	path.script.WriteString("\nctx.lineTo(") | ||||
| 	path.script.WriteString(strconv.FormatFloat(x, 'g', -1, 64)) | ||||
| 	path.script.WriteRune(',') | ||||
| 	path.script.WriteString(strconv.FormatFloat(y, 'g', -1, 64)) | ||||
| 	path.script.WriteString(");") | ||||
| 	path.elements = append(path.elements, pathElement{funcName: "lineTo", args: []any{x, y}}) | ||||
| } | ||||
| 
 | ||||
| func (path *pathData) ArcTo(x0, y0, x1, y1, radius float64) { | ||||
| 	if radius > 0 { | ||||
| 		path.script.WriteString("\nctx.arcTo(") | ||||
| 		path.script.WriteString(strconv.FormatFloat(x0, 'g', -1, 64)) | ||||
| 		path.script.WriteRune(',') | ||||
| 		path.script.WriteString(strconv.FormatFloat(y0, 'g', -1, 64)) | ||||
| 		path.script.WriteRune(',') | ||||
| 		path.script.WriteString(strconv.FormatFloat(x1, 'g', -1, 64)) | ||||
| 		path.script.WriteRune(',') | ||||
| 		path.script.WriteString(strconv.FormatFloat(y1, 'g', -1, 64)) | ||||
| 		path.script.WriteRune(',') | ||||
| 		path.script.WriteString(strconv.FormatFloat(radius, 'g', -1, 64)) | ||||
| 		path.script.WriteString(");") | ||||
| 		path.elements = append(path.elements, pathElement{funcName: "arcTo", args: []any{x0, y0, x1, y1, radius}}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (path *pathData) Arc(x, y, radius, startAngle, endAngle float64, clockwise bool) { | ||||
| 	if radius > 0 { | ||||
| 		path.script.WriteString("\nctx.arc(") | ||||
| 		path.script.WriteString(strconv.FormatFloat(x, 'g', -1, 64)) | ||||
| 		path.script.WriteRune(',') | ||||
| 		path.script.WriteString(strconv.FormatFloat(y, 'g', -1, 64)) | ||||
| 		path.script.WriteRune(',') | ||||
| 		path.script.WriteString(strconv.FormatFloat(radius, 'g', -1, 64)) | ||||
| 		path.script.WriteRune(',') | ||||
| 		path.script.WriteString(strconv.FormatFloat(startAngle, 'g', -1, 64)) | ||||
| 		path.script.WriteRune(',') | ||||
| 		path.script.WriteString(strconv.FormatFloat(endAngle, 'g', -1, 64)) | ||||
| 		if !clockwise { | ||||
| 			path.script.WriteString(",true);") | ||||
| 			path.elements = append(path.elements, pathElement{funcName: "arc", args: []any{x, y, radius, startAngle, endAngle, true}}) | ||||
| 		} else { | ||||
| 			path.script.WriteString(");") | ||||
| 			path.elements = append(path.elements, pathElement{funcName: "arc", args: []any{x, y, radius, startAngle, endAngle}}) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (path *pathData) BezierCurveTo(cp0x, cp0y, cp1x, cp1y, x, y float64) { | ||||
| 	path.script.WriteString("\nctx.bezierCurveTo(") | ||||
| 	path.script.WriteString(strconv.FormatFloat(cp0x, 'g', -1, 64)) | ||||
| 	path.script.WriteRune(',') | ||||
| 	path.script.WriteString(strconv.FormatFloat(cp0y, 'g', -1, 64)) | ||||
| 	path.script.WriteRune(',') | ||||
| 	path.script.WriteString(strconv.FormatFloat(cp1x, 'g', -1, 64)) | ||||
| 	path.script.WriteRune(',') | ||||
| 	path.script.WriteString(strconv.FormatFloat(cp1y, 'g', -1, 64)) | ||||
| 	path.script.WriteRune(',') | ||||
| 	path.script.WriteString(strconv.FormatFloat(x, 'g', -1, 64)) | ||||
| 	path.script.WriteRune(',') | ||||
| 	path.script.WriteString(strconv.FormatFloat(y, 'g', -1, 64)) | ||||
| 	path.script.WriteString(");") | ||||
| 	path.elements = append(path.elements, pathElement{funcName: "bezierCurveTo", args: []any{cp0x, cp0y, cp1x, cp1y, x, y}}) | ||||
| } | ||||
| 
 | ||||
| func (path *pathData) QuadraticCurveTo(cpx, cpy, x, y float64) { | ||||
| 	path.script.WriteString("\nctx.quadraticCurveTo(") | ||||
| 	path.script.WriteString(strconv.FormatFloat(cpx, 'g', -1, 64)) | ||||
| 	path.script.WriteRune(',') | ||||
| 	path.script.WriteString(strconv.FormatFloat(cpy, 'g', -1, 64)) | ||||
| 	path.script.WriteRune(',') | ||||
| 	path.script.WriteString(strconv.FormatFloat(x, 'g', -1, 64)) | ||||
| 	path.script.WriteRune(',') | ||||
| 	path.script.WriteString(strconv.FormatFloat(y, 'g', -1, 64)) | ||||
| 	path.script.WriteString(");") | ||||
| 	path.elements = append(path.elements, pathElement{funcName: "quadraticCurveTo", args: []any{cpx, cpy, x, y}}) | ||||
| } | ||||
| 
 | ||||
| func (path *pathData) Ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle float64, clockwise bool) { | ||||
| 	if radiusX > 0 && radiusY > 0 { | ||||
| 		path.script.WriteString("\nctx.ellipse(") | ||||
| 		path.script.WriteString(strconv.FormatFloat(x, 'g', -1, 64)) | ||||
| 		path.script.WriteRune(',') | ||||
| 		path.script.WriteString(strconv.FormatFloat(y, 'g', -1, 64)) | ||||
| 		path.script.WriteRune(',') | ||||
| 		path.script.WriteString(strconv.FormatFloat(radiusX, 'g', -1, 64)) | ||||
| 		path.script.WriteRune(',') | ||||
| 		path.script.WriteString(strconv.FormatFloat(radiusY, 'g', -1, 64)) | ||||
| 		path.script.WriteRune(',') | ||||
| 		path.script.WriteString(strconv.FormatFloat(rotation, 'g', -1, 64)) | ||||
| 		path.script.WriteRune(',') | ||||
| 		path.script.WriteString(strconv.FormatFloat(startAngle, 'g', -1, 64)) | ||||
| 		path.script.WriteRune(',') | ||||
| 		path.script.WriteString(strconv.FormatFloat(endAngle, 'g', -1, 64)) | ||||
| 		if !clockwise { | ||||
| 			path.script.WriteString(",true);") | ||||
| 			path.elements = append(path.elements, pathElement{funcName: "ellipse", args: []any{x, y, radiusX, radiusY, rotation, startAngle, endAngle, true}}) | ||||
| 		} else { | ||||
| 			path.script.WriteString(");") | ||||
| 			path.elements = append(path.elements, pathElement{funcName: "ellipse", args: []any{x, y, radiusX, radiusY, rotation, startAngle, endAngle}}) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (path *pathData) Close() { | ||||
| 	path.script.WriteString("\nctx.close();") | ||||
| 	path.elements = append(path.elements, pathElement{funcName: "close", args: []any{}}) | ||||
| } | ||||
| 
 | ||||
| func (path *pathData) scriptText() string { | ||||
| 	return path.script.String() | ||||
| func (path *pathData) create(session Session) { | ||||
| 	for _, element := range path.elements { | ||||
| 		session.callCanvasFunc(element.funcName, element.args...) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -123,7 +123,7 @@ func scanEmbedImagesDir(fs *embed.FS, dir, prefix string) { | |||
| 			} else { | ||||
| 				ext := strings.ToLower(filepath.Ext(name)) | ||||
| 				switch ext { | ||||
| 				case ".png", ".jpg", ".jpeg", ".svg": | ||||
| 				case ".png", ".jpg", ".jpeg", ".svg", ".gif", ".bmp": | ||||
| 					registerImage(fs, path, prefix+name) | ||||
| 				} | ||||
| 			} | ||||
|  |  | |||
							
								
								
									
										57
									
								
								session.go
								
								
								
								
							
							
						
						
									
										57
									
								
								session.go
								
								
								
								
							|  | @ -18,6 +18,13 @@ type webBrige interface { | |||
| 	removeProperty(htmlID, property string) | ||||
| 	readMessage() (string, bool) | ||||
| 	writeMessage(text string) bool | ||||
| 	cavnasStart(htmlID string) | ||||
| 	callCanvasFunc(funcName string, args ...any) | ||||
| 	callCanvasVarFunc(v any, funcName string, args ...any) | ||||
| 	callCanvasImageFunc(url string, property string, funcName string, args ...any) | ||||
| 	createCanvasVar(funcName string, args ...any) any | ||||
| 	updateCanvasProperty(property string, value any) | ||||
| 	cavnasFinish() | ||||
| 	canvasTextMetrics(htmlID, font, text string) TextMetrics | ||||
| 	htmlPropertyValue(htmlID, name string) string | ||||
| 	answerReceived(answer DataObject) | ||||
|  | @ -115,6 +122,13 @@ type Session interface { | |||
| 	runScript(script string) | ||||
| 	startUpdateScript(htmlID string) bool | ||||
| 	finishUpdateScript(htmlID string) | ||||
| 	cavnasStart(htmlID string) | ||||
| 	callCanvasFunc(funcName string, args ...any) | ||||
| 	createCanvasVar(funcName string, args ...any) any | ||||
| 	callCanvasVarFunc(v any, funcName string, args ...any) | ||||
| 	callCanvasImageFunc(url string, property string, funcName string, args ...any) | ||||
| 	updateCanvasProperty(property string, value any) | ||||
| 	cavnasFinish() | ||||
| 	canvasTextMetrics(htmlID, font, text string) TextMetrics | ||||
| 	htmlPropertyValue(htmlID, name string) string | ||||
| 	handleAnswer(data DataObject) | ||||
|  | @ -395,6 +409,49 @@ func (session *sessionData) finishUpdateScript(htmlID string) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (session *sessionData) cavnasStart(htmlID string) { | ||||
| 	if session.brige != nil { | ||||
| 		session.brige.cavnasStart(htmlID) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (session *sessionData) callCanvasFunc(funcName string, args ...any) { | ||||
| 	if session.brige != nil { | ||||
| 		session.brige.callCanvasFunc(funcName, args...) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (session *sessionData) updateCanvasProperty(property string, value any) { | ||||
| 	if session.brige != nil { | ||||
| 		session.brige.updateCanvasProperty(property, value) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (session *sessionData) createCanvasVar(funcName string, args ...any) any { | ||||
| 	if session.brige != nil { | ||||
| 		return session.brige.createCanvasVar(funcName, args...) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (session *sessionData) callCanvasVarFunc(v any, funcName string, args ...any) { | ||||
| 	if session.brige != nil && v != nil { | ||||
| 		session.brige.callCanvasVarFunc(v, funcName, args...) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (session *sessionData) callCanvasImageFunc(url string, property string, funcName string, args ...any) { | ||||
| 	if session.brige != nil { | ||||
| 		session.brige.callCanvasImageFunc(url, property, funcName, args...) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (session *sessionData) cavnasFinish() { | ||||
| 	if session.brige != nil { | ||||
| 		session.brige.cavnasFinish() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (session *sessionData) runScript(script string) { | ||||
| 	if session.brige != nil { | ||||
| 		session.brige.writeMessage(script) | ||||
|  |  | |||
							
								
								
									
										139
									
								
								webBrige.go
								
								
								
								
							
							
						
						
									
										139
									
								
								webBrige.go
								
								
								
								
							|  | @ -13,13 +13,19 @@ import ( | |||
| ) | ||||
| 
 | ||||
| type wsBrige struct { | ||||
| 	conn          *websocket.Conn | ||||
| 	answer        map[int]chan DataObject | ||||
| 	answerID      int | ||||
| 	answerMutex   sync.Mutex | ||||
| 	closed        bool | ||||
| 	buffer        strings.Builder | ||||
| 	updateScripts map[string]*strings.Builder | ||||
| 	conn            *websocket.Conn | ||||
| 	answer          map[int]chan DataObject | ||||
| 	answerID        int | ||||
| 	answerMutex     sync.Mutex | ||||
| 	closed          bool | ||||
| 	buffer          strings.Builder | ||||
| 	canvasBuffer    strings.Builder | ||||
| 	canvasVarNumber int | ||||
| 	updateScripts   map[string]*strings.Builder | ||||
| } | ||||
| 
 | ||||
| type canvasVar struct { | ||||
| 	name string | ||||
| } | ||||
| 
 | ||||
| var upgrader = websocket.Upgrader{ | ||||
|  | @ -119,6 +125,21 @@ func (brige *wsBrige) argToString(arg any) (string, bool) { | |||
| 	case float64: | ||||
| 		return fmt.Sprintf("%g", arg), true | ||||
| 
 | ||||
| 	case []float64: | ||||
| 		buffer := allocStringBuilder() | ||||
| 		defer freeStringBuilder(buffer) | ||||
| 		lead := '[' | ||||
| 		for _, val := range arg { | ||||
| 			buffer.WriteRune(lead) | ||||
| 			lead = ',' | ||||
| 			buffer.WriteString(fmt.Sprintf("%g", val)) | ||||
| 		} | ||||
| 		buffer.WriteRune(']') | ||||
| 		return buffer.String(), true | ||||
| 
 | ||||
| 	case canvasVar: | ||||
| 		return arg.name, true | ||||
| 
 | ||||
| 	default: | ||||
| 		if n, ok := isInt(arg); ok { | ||||
| 			return fmt.Sprintf("%d", n), true | ||||
|  | @ -203,6 +224,110 @@ func (brige *wsBrige) removeProperty(htmlID, property string) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (brige *wsBrige) cavnasStart(htmlID string) { | ||||
| 	brige.canvasBuffer.Reset() | ||||
| 	brige.canvasBuffer.WriteString(`const ctx = getCanvasContext('`) | ||||
| 	brige.canvasBuffer.WriteString(htmlID) | ||||
| 	brige.canvasBuffer.WriteString(`');`) | ||||
| } | ||||
| 
 | ||||
| func (brige *wsBrige) callCanvasFunc(funcName string, args ...any) { | ||||
| 	brige.canvasBuffer.WriteString("\nctx.") | ||||
| 	brige.canvasBuffer.WriteString(funcName) | ||||
| 	brige.canvasBuffer.WriteRune('(') | ||||
| 	for i, arg := range args { | ||||
| 		if i > 0 { | ||||
| 			brige.canvasBuffer.WriteString(", ") | ||||
| 		} | ||||
| 		argText, _ := brige.argToString(arg) | ||||
| 		brige.canvasBuffer.WriteString(argText) | ||||
| 	} | ||||
| 	brige.canvasBuffer.WriteString(");") | ||||
| } | ||||
| 
 | ||||
| func (brige *wsBrige) updateCanvasProperty(property string, value any) { | ||||
| 	brige.canvasBuffer.WriteString("\nctx.") | ||||
| 	brige.canvasBuffer.WriteString(property) | ||||
| 	brige.canvasBuffer.WriteString(" = ") | ||||
| 	argText, _ := brige.argToString(value) | ||||
| 	brige.canvasBuffer.WriteString(argText) | ||||
| 	brige.canvasBuffer.WriteString(";") | ||||
| } | ||||
| 
 | ||||
| func (brige *wsBrige) createCanvasVar(funcName string, args ...any) any { | ||||
| 	brige.canvasVarNumber++ | ||||
| 	result := canvasVar{name: fmt.Sprintf("v%d", brige.canvasVarNumber)} | ||||
| 	brige.canvasBuffer.WriteString("\nvar ") | ||||
| 	brige.canvasBuffer.WriteString(result.name) | ||||
| 	brige.canvasBuffer.WriteString(" = ctx.") | ||||
| 	brige.canvasBuffer.WriteString(funcName) | ||||
| 	brige.canvasBuffer.WriteRune('(') | ||||
| 	for i, arg := range args { | ||||
| 		if i > 0 { | ||||
| 			brige.canvasBuffer.WriteString(", ") | ||||
| 		} | ||||
| 		argText, _ := brige.argToString(arg) | ||||
| 		brige.canvasBuffer.WriteString(argText) | ||||
| 	} | ||||
| 	brige.canvasBuffer.WriteString(");") | ||||
| 	return result | ||||
| } | ||||
| 
 | ||||
| func (brige *wsBrige) callCanvasVarFunc(v any, funcName string, args ...any) { | ||||
| 	varName, ok := v.(canvasVar) | ||||
| 	if !ok { | ||||
| 		return | ||||
| 	} | ||||
| 	brige.canvasBuffer.WriteString("\n") | ||||
| 	brige.canvasBuffer.WriteString(varName.name) | ||||
| 	brige.canvasBuffer.WriteRune('.') | ||||
| 	brige.canvasBuffer.WriteString(funcName) | ||||
| 	brige.canvasBuffer.WriteRune('(') | ||||
| 	for i, arg := range args { | ||||
| 		if i > 0 { | ||||
| 			brige.canvasBuffer.WriteString(", ") | ||||
| 		} | ||||
| 		argText, _ := brige.argToString(arg) | ||||
| 		brige.canvasBuffer.WriteString(argText) | ||||
| 	} | ||||
| 	brige.canvasBuffer.WriteString(");") | ||||
| } | ||||
| 
 | ||||
| func (brige *wsBrige) callCanvasImageFunc(url string, property string, funcName string, args ...any) { | ||||
| 
 | ||||
| 	brige.canvasBuffer.WriteString("\nimg = images.get('") | ||||
| 	brige.canvasBuffer.WriteString(url) | ||||
| 	brige.canvasBuffer.WriteString("');\nif (img) {\n") | ||||
| 	if property != "" { | ||||
| 		brige.canvasBuffer.WriteString("ctx.") | ||||
| 		brige.canvasBuffer.WriteString(property) | ||||
| 		brige.canvasBuffer.WriteString(" = ") | ||||
| 	} | ||||
| 	brige.canvasBuffer.WriteString("ctx.") | ||||
| 	brige.canvasBuffer.WriteString(funcName) | ||||
| 	brige.canvasBuffer.WriteString("(img") | ||||
| 	for _, arg := range args { | ||||
| 		brige.canvasBuffer.WriteString(", ") | ||||
| 		argText, _ := brige.argToString(arg) | ||||
| 		brige.canvasBuffer.WriteString(argText) | ||||
| 	} | ||||
| 	brige.canvasBuffer.WriteString(");\n}") | ||||
| } | ||||
| 
 | ||||
| func (brige *wsBrige) cavnasFinish() { | ||||
| 	brige.canvasBuffer.WriteString("\n") | ||||
| 	script := brige.canvasBuffer.String() | ||||
| 	if ProtocolInDebugLog { | ||||
| 		DebugLog("Run script:") | ||||
| 		DebugLog(script) | ||||
| 	} | ||||
| 	if brige.conn == nil { | ||||
| 		ErrorLog("No connection") | ||||
| 	} else if err := brige.conn.WriteMessage(websocket.TextMessage, []byte(script)); err != nil { | ||||
| 		ErrorLog(err.Error()) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (brige *wsBrige) readMessage() (string, bool) { | ||||
| 	_, p, err := brige.conn.ReadMessage() | ||||
| 	if err != nil { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue