Updated Path

* Added NewPath and NewPathFromSvg methods to Canvas interface
* Removed NewPath function
* Removed Reset methods from Path interface
This commit is contained in:
Alexei Anoshenko 2024-08-20 20:01:26 +03:00
parent 2708c7ceb6
commit 87148836c0
15 changed files with 109 additions and 50 deletions

View File

@ -5,6 +5,9 @@
* Added "transform" property and Transform interface * Added "transform" property and Transform interface
* Added OpenRawResource function * Added OpenRawResource function
* Added RemoveClientItem method to Session interface * Added RemoveClientItem method to Session interface
* Added NewPath and NewPathFromSvg methods to Canvas interface
* Removed NewPath function
* Removed Reset methods from Path interface
# v0.16.0 # v0.16.0
* Can use ListAdapter as "content" property value of ListLayout * Can use ListAdapter as "content" property value of ListLayout

View File

@ -4443,7 +4443,17 @@ rotation - угол поворота эллипса относительно ц
#### Path #### Path
Интерфейс Path позволяет описать сложную фигуру. Создается Path с помощью функции NewPath(). Интерфейс Path позволяет описать сложную фигуру. Для создания объекта Path используются два метода Canvas:
NewPath() Path
NewPathFromSvg(data string) Path
Метод NewPath() создает пустую фигуру. Далее вы должны описать фигуру используя методы интерфейса Path
Метод NewPathFromSvg(data string) Path создает фигуру описанную в параметре data.
Параметр data является описанием фигуры в формате елемента <path> svg изображения. Например
path := canvas.NewPathFromSvg("m 305,77.362183 c 0,0 -3,8.648649 -13,21.621616 -10,12.972981 -17,18.378381 -17,18.378381 0,0 6,4.32433 17,18.37838 11,14.05406 13,21.62162 13,21.62162 0,0 7.83867,-14.92584 13,-21.62162 10,-12.97297 17,-18.37838 17,-18.37838 0,0 -7,-5.4054 -17,-18.378381 C 308,86.010832 305,77.362183 305,77.362183 Z")
После создания вы должны описать фигуру. Для этого могут использоваться следующие функции интерфейса: После создания вы должны описать фигуру. Для этого могут использоваться следующие функции интерфейса:

View File

@ -4411,7 +4411,17 @@ rotation - the angle of rotation of the ellipse relative to the center in radian
#### Path #### Path
The Path interface allows you to describe a complex shape. Path is created using the NewPath () function. The Path interface allows you to describe a complex shape. Two Canvas methods are used to create a Path object:
NewPath() Path
NewPathFromSvg(data string) Path
The NewPath() method creates an empty shape. Next, you must describe the shape using the methods of the Path interface
The NewPathFromSvg(data string) Path method creates the shape described in the data parameter.
The data parameter is a description of the shape in the format of a <path> svg image element. For example
path := canvas.NewPathFromSvg("m 305,77.362183 c 0,0 -3,8.648649 -13,21.621616 -10,12.972981 -17,18.378381 -17,18.378381 0,0 6,4.32433 17,18.37838 11,14.05406 13,21.62162 13,21.62162 0,0 7.83867,-14.92584 13,-21.62162 10,-12.97297 17,-18.37838 17,-18.37838 0,0 -7,-5.4054 -17,-18.378381 C 308,86.010832 305,77.362183 305,77.362183 Z")
Once created, you must describe the shape. For this, the following interface functions can be used: Once created, you must describe the shape. For this, the following interface functions can be used:

View File

@ -2136,3 +2136,11 @@ function setCssVar(tag, value) {
root.style.setProperty(tag, value); root.style.setProperty(tag, value);
} }
} }
function createPath2D(svg) {
if (svg) {
return new Path2D(svg);
} else {
return new Path2D();
}
}

View File

@ -263,6 +263,11 @@ type Canvas interface {
// and is stroked (outlined) according to the current strokeStyle and other context settings // and is stroked (outlined) according to the current strokeStyle and other context settings
FillAndStrokeEllipse(x, y, radiusX, radiusY, rotation float64) FillAndStrokeEllipse(x, y, radiusX, radiusY, rotation float64)
// NewPath creates a new Path object
NewPath() Path
// NewPathFromSvg creates a new Path and initialize it by a string consisting of SVG path data
NewPathFromSvg(data string) Path
// FillPath draws a path that is filled according to the current FillStyle. // FillPath draws a path that is filled according to the current FillStyle.
FillPath(path Path) FillPath(path Path)
// StrokePath draws a path that is stroked (outlined) according to the current strokeStyle // StrokePath draws a path that is stroked (outlined) according to the current strokeStyle
@ -346,8 +351,7 @@ func (canvas *canvasData) ClipRect(x, y, width, height float64) {
} }
func (canvas *canvasData) ClipPath(path Path) { func (canvas *canvasData) ClipPath(path Path) {
path.create(canvas.session) canvas.session.callCanvasFunc("clip", path.obj())
canvas.session.callCanvasFunc("clip")
} }
func (canvas *canvasData) SetScale(x, y float64) { func (canvas *canvasData) SetScale(x, y float64) {
@ -779,19 +783,16 @@ func (canvas *canvasData) StrokeText(x, y float64, text string) {
} }
func (canvas *canvasData) FillPath(path Path) { func (canvas *canvasData) FillPath(path Path) {
path.create(canvas.session) canvas.session.callCanvasFunc("fill", path.obj())
canvas.session.callCanvasFunc("fill")
} }
func (canvas *canvasData) StrokePath(path Path) { func (canvas *canvasData) StrokePath(path Path) {
path.create(canvas.session) canvas.session.callCanvasFunc("stroke", path.obj())
canvas.session.callCanvasFunc("stroke")
} }
func (canvas *canvasData) FillAndStrokePath(path Path) { func (canvas *canvasData) FillAndStrokePath(path Path) {
path.create(canvas.session) canvas.session.callCanvasFunc("fill", path.obj())
canvas.session.callCanvasFunc("fill") canvas.session.callCanvasFunc("stroke", path.obj())
canvas.session.callCanvasFunc("stroke")
} }
func (canvas *canvasData) DrawLine(x0, y0, x1, y1 float64) { func (canvas *canvasData) DrawLine(x0, y0, x1, y1 float64) {

View File

@ -134,7 +134,7 @@ func (object *dataObject) PropertyObject(tag string) DataObject {
} }
func (object *dataObject) setNode(node DataNode) { func (object *dataObject) setNode(node DataNode) {
if object.property == nil || len(object.property) == 0 { if len(object.property) == 0 {
object.property = []DataNode{node} object.property = []DataNode{node}
} else { } else {
tag := node.Tag() tag := node.Tag()

View File

@ -1,3 +1,5 @@
//go:build !wasm
package rui package rui
import ( import (
@ -39,6 +41,7 @@ Example for echo:
} }
}) })
*/ */
func NewHandler(urlPrefix string, createContentFunc func(Session) SessionContent, params AppParams) *httpHandler { func NewHandler(urlPrefix string, createContentFunc func(Session) SessionContent, params AppParams) *httpHandler {
app := new(application) app := new(application)
app.params = params app.params = params

54
path.go
View File

@ -2,9 +2,6 @@ package rui
// Path is a path interface // Path is a path interface
type Path interface { type Path interface {
// Reset erases the Path
Reset()
// MoveTo begins a new sub-path at the point specified by the given (x, y) coordinates // MoveTo begins a new sub-path at the point specified by the given (x, y) coordinates
MoveTo(x, y float64) MoveTo(x, y float64)
@ -58,79 +55,76 @@ type Path interface {
// If the shape has already been closed or has only one point, this function does nothing. // If the shape has already been closed or has only one point, this function does nothing.
Close() Close()
create(session Session) //create(session Session)
} obj() any
type pathElement struct {
funcName string
args []any
} }
type pathData struct { type pathData struct {
elements []pathElement session Session
varName any
} }
// NewPath creates a new empty Path // NewPath creates a new empty Path
func NewPath() Path { func (canvas *canvasData) NewPath() Path {
path := new(pathData) path := new(pathData)
path.Reset() path.session = canvas.session
path.varName = canvas.session.createPath("")
return path return path
} }
func (path *pathData) Reset() { func (canvas *canvasData) NewPathFromSvg(data string) Path {
path.elements = []pathElement{ path := new(pathData)
{funcName: "beginPath", args: []any{}}, path.session = canvas.session
} path.varName = canvas.session.createPath(data)
return path
} }
func (path *pathData) MoveTo(x, y float64) { func (path *pathData) MoveTo(x, y float64) {
path.elements = append(path.elements, pathElement{funcName: "moveTo", args: []any{x, y}}) path.session.callCanvasVarFunc(path.varName, "moveTo", x, y)
} }
func (path *pathData) LineTo(x, y float64) { func (path *pathData) LineTo(x, y float64) {
path.elements = append(path.elements, pathElement{funcName: "lineTo", args: []any{x, y}}) path.session.callCanvasVarFunc(path.varName, "lineTo", x, y)
} }
func (path *pathData) ArcTo(x0, y0, x1, y1, radius float64) { func (path *pathData) ArcTo(x0, y0, x1, y1, radius float64) {
if radius > 0 { if radius > 0 {
path.elements = append(path.elements, pathElement{funcName: "arcTo", args: []any{x0, y0, x1, y1, radius}}) path.session.callCanvasVarFunc(path.varName, "arcTo", x0, y0, x1, y1, radius)
} }
} }
func (path *pathData) Arc(x, y, radius, startAngle, endAngle float64, clockwise bool) { func (path *pathData) Arc(x, y, radius, startAngle, endAngle float64, clockwise bool) {
if radius > 0 { if radius > 0 {
if !clockwise { if !clockwise {
path.elements = append(path.elements, pathElement{funcName: "arc", args: []any{x, y, radius, startAngle, endAngle, true}}) path.session.callCanvasVarFunc(path.varName, "arc", x, y, radius, startAngle, endAngle, true)
} else { } else {
path.elements = append(path.elements, pathElement{funcName: "arc", args: []any{x, y, radius, startAngle, endAngle}}) path.session.callCanvasVarFunc(path.varName, "arc", x, y, radius, startAngle, endAngle)
} }
} }
} }
func (path *pathData) BezierCurveTo(cp0x, cp0y, cp1x, cp1y, x, y float64) { func (path *pathData) BezierCurveTo(cp0x, cp0y, cp1x, cp1y, x, y float64) {
path.elements = append(path.elements, pathElement{funcName: "bezierCurveTo", args: []any{cp0x, cp0y, cp1x, cp1y, x, y}}) path.session.callCanvasVarFunc(path.varName, "bezierCurveTo", cp0x, cp0y, cp1x, cp1y, x, y)
} }
func (path *pathData) QuadraticCurveTo(cpx, cpy, x, y float64) { func (path *pathData) QuadraticCurveTo(cpx, cpy, x, y float64) {
path.elements = append(path.elements, pathElement{funcName: "quadraticCurveTo", args: []any{cpx, cpy, x, y}}) path.session.callCanvasVarFunc(path.varName, "quadraticCurveTo", cpx, cpy, x, y)
} }
func (path *pathData) Ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle float64, clockwise bool) { func (path *pathData) Ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle float64, clockwise bool) {
if radiusX > 0 && radiusY > 0 { if radiusX > 0 && radiusY > 0 {
if !clockwise { if !clockwise {
path.elements = append(path.elements, pathElement{funcName: "ellipse", args: []any{x, y, radiusX, radiusY, rotation, startAngle, endAngle, true}}) path.session.callCanvasVarFunc(path.varName, "ellipse", x, y, radiusX, radiusY, rotation, startAngle, endAngle, true)
} else { } else {
path.elements = append(path.elements, pathElement{funcName: "ellipse", args: []any{x, y, radiusX, radiusY, rotation, startAngle, endAngle}}) path.session.callCanvasVarFunc(path.varName, "ellipse", x, y, radiusX, radiusY, rotation, startAngle, endAngle)
} }
} }
} }
func (path *pathData) Close() { func (path *pathData) Close() {
path.elements = append(path.elements, pathElement{funcName: "close", args: []any{}}) path.session.callCanvasVarFunc(path.varName, "close")
} }
func (path *pathData) create(session Session) { func (path *pathData) obj() any {
for _, element := range path.elements { return path.varName
session.callCanvasFunc(element.funcName, element.args...)
}
} }

View File

@ -683,7 +683,7 @@ func (manager *popupManager) showPopup(popup Popup) {
} }
session := popup.Session() session := popup.Session()
if manager.popups == nil || len(manager.popups) == 0 { if len(manager.popups) == 0 {
manager.popups = []Popup{popup} manager.popups = []Popup{popup}
} else { } else {
manager.popups = append(manager.popups, popup) manager.popups = append(manager.popups, popup)

View File

@ -24,6 +24,7 @@ type bridge interface {
callCanvasVarFunc(v any, funcName string, args ...any) callCanvasVarFunc(v any, funcName string, args ...any)
callCanvasImageFunc(url string, property string, funcName string, args ...any) callCanvasImageFunc(url string, property string, funcName string, args ...any)
createCanvasVar(funcName string, args ...any) any createCanvasVar(funcName string, args ...any) any
createPath2D(arg string) any
updateCanvasProperty(property string, value any) updateCanvasProperty(property string, value any)
canvasFinish() canvasFinish()
canvasTextMetrics(htmlID, font, text string) TextMetrics canvasTextMetrics(htmlID, font, text string) TextMetrics
@ -151,6 +152,7 @@ type Session interface {
canvasStart(htmlID string) bool canvasStart(htmlID string) bool
callCanvasFunc(funcName string, args ...any) callCanvasFunc(funcName string, args ...any)
createCanvasVar(funcName string, args ...any) any createCanvasVar(funcName string, args ...any) any
createPath(arg string) any
callCanvasVarFunc(v any, funcName string, args ...any) callCanvasVarFunc(v any, funcName string, args ...any)
callCanvasImageFunc(url string, property string, funcName string, args ...any) callCanvasImageFunc(url string, property string, funcName string, args ...any)
updateCanvasProperty(property string, value any) updateCanvasProperty(property string, value any)
@ -561,6 +563,13 @@ func (session *sessionData) createCanvasVar(funcName string, args ...any) any {
return nil return nil
} }
func (session *sessionData) createPath(arg string) any {
if session.bridge != nil {
return session.bridge.createPath2D(arg)
}
return nil
}
func (session *sessionData) callCanvasVarFunc(v any, funcName string, args ...any) { func (session *sessionData) callCanvasVarFunc(v any, funcName string, args ...any) {
if session.bridge != nil && v != nil { if session.bridge != nil && v != nil {
session.bridge.callCanvasVarFunc(v, funcName, args...) session.bridge.callCanvasVarFunc(v, funcName, args...)

View File

@ -313,7 +313,7 @@ func (session *sessionData) Language() string {
return session.language return session.language
} }
if session.languages != nil && len(session.languages) > 0 { if len(session.languages) > 0 {
return session.languages[0] return session.languages[0]
} }

View File

@ -454,11 +454,7 @@ func (clip *polygonClip) cssStyle(session Session) string {
} }
func (clip *polygonClip) valid(session Session) bool { func (clip *polygonClip) valid(session Session) bool {
if clip.points == nil || len(clip.points) == 0 { return len(clip.points) > 0
return false
}
return true
} }
func parseClipShape(obj DataObject) ClipShape { func parseClipShape(obj DataObject) ClipShape {

View File

@ -66,7 +66,7 @@ func (container *viewsContainerData) Append(view View) {
if view != nil { if view != nil {
htmlID := container.htmlID() htmlID := container.htmlID()
view.setParentID(htmlID) view.setParentID(htmlID)
if container.views == nil || len(container.views) == 0 { if len(container.views) == 0 {
container.views = []View{view} container.views = []View{view}
} else { } else {
container.views = append(container.views, view) container.views = append(container.views, view)

View File

@ -193,6 +193,17 @@ func (bridge *wasmBridge) createCanvasVar(funcName string, args ...any) any {
return result return result
} }
func (bridge *wasmBridge) createPath2D(arg string) any {
if arg != "" {
result := bridge.canvas.Call("createPath2D", arg)
bridge.printFuncToLog("var "+result.String()+" = new Path2D", arg)
return result
}
result := bridge.canvas.Call("createPath2D")
bridge.printFuncToLog("var " + result.String() + " = new Path2D")
return result
}
func (bridge *wasmBridge) updateCanvasProperty(property string, value any) { func (bridge *wasmBridge) updateCanvasProperty(property string, value any) {
if !bridge.canvas.IsNull() { if !bridge.canvas.IsNull() {
if ProtocolInDebugLog { if ProtocolInDebugLog {

View File

@ -350,6 +350,20 @@ func (bridge *webBridge) createCanvasVar(funcName string, args ...any) any {
return result return result
} }
func (bridge *webBridge) createPath2D(arg string) any {
bridge.canvasVarNumber++
result := canvasVar{name: fmt.Sprintf("v%d", bridge.canvasVarNumber)}
bridge.canvasBuffer.WriteString("\nlet ")
bridge.canvasBuffer.WriteString(result.name)
bridge.canvasBuffer.WriteString(` = new Path2D(`)
if arg != "" {
argText, _ := bridge.argToString(arg)
bridge.canvasBuffer.WriteString(argText)
}
bridge.canvasBuffer.WriteString(`);`)
return result
}
func (bridge *webBridge) callCanvasVarFunc(v any, funcName string, args ...any) { func (bridge *webBridge) callCanvasVarFunc(v any, funcName string, args ...any) {
varName, ok := v.(canvasVar) varName, ok := v.(canvasVar)
if !ok { if !ok {