Optimised animation

This commit is contained in:
anoshenko 2024-07-01 19:17:03 +03:00
parent 09031b9fa0
commit 2f3de8fce3
7 changed files with 99 additions and 28 deletions

View File

@ -120,6 +120,7 @@ type AnimatedProperty struct {
type animationData struct { type animationData struct {
propertyList propertyList
keyFramesName string keyFramesName string
usageCounter int
} }
// Animation interface is used to set animation parameters. Used properties: // Animation interface is used to set animation parameters. Used properties:
@ -132,6 +133,8 @@ type Animation interface {
transitionCSS(buffer *strings.Builder, session Session) transitionCSS(buffer *strings.Builder, session Session)
hasAnimatedProperty() bool hasAnimatedProperty() bool
animationName() string animationName() string
used()
unused(session Session)
} }
func parseAnimation(obj DataObject) Animation { func parseAnimation(obj DataObject) Animation {
@ -179,6 +182,17 @@ func (animation *animationData) animationName() string {
return animation.keyFramesName return animation.keyFramesName
} }
func (animation *animationData) used() {
animation.usageCounter++
}
func (animation *animationData) unused(session Session) {
animation.usageCounter--
if animation.usageCounter <= 0 && animation.keyFramesName != "" {
session.removeAnimation(animation.keyFramesName)
}
}
func (animation *animationData) normalizeTag(tag string) string { func (animation *animationData) normalizeTag(tag string) string {
tag = strings.ToLower(tag) tag = strings.ToLower(tag)
if tag == Direction { if tag == Direction {
@ -387,7 +401,7 @@ func (animation *animationData) animationCSS(session Session) string {
} }
animatedProps, ok := props.([]AnimatedProperty) animatedProps, ok := props.([]AnimatedProperty)
if !ok { if !ok || len(animatedProps) == 0 {
ErrorLog("Invalid animated properties.") ErrorLog("Invalid animated properties.")
return "" return ""
} }
@ -549,6 +563,7 @@ func (session *sessionData) registerAnimation(props []AnimatedProperty) string {
var cssBuilder cssStyleBuilder var cssBuilder cssStyleBuilder
cssBuilder.init(0)
cssBuilder.startAnimation(name) cssBuilder.startAnimation(name)
fromParams := Params{} fromParams := Params{}
@ -606,10 +621,7 @@ func (session *sessionData) registerAnimation(props []AnimatedProperty) string {
cssBuilder.endAnimationFrame() cssBuilder.endAnimationFrame()
cssBuilder.endAnimation() cssBuilder.endAnimation()
session.addAnimationCSS(cssBuilder.finish())
style := cssBuilder.finish()
session.animationCSS += style
session.addAnimationCSS(style)
return name return name
} }

View File

@ -150,9 +150,11 @@ func (builder *cssValueBuilder) addValues(key, separator string, values ...strin
} }
} }
func (builder *cssStyleBuilder) init() { func (builder *cssStyleBuilder) init(kbSize int) {
builder.buffer = allocStringBuilder() builder.buffer = allocStringBuilder()
builder.buffer.Grow(16 * 1024) if kbSize > 0 {
builder.buffer.Grow(kbSize * 1024)
}
} }
func (builder *cssStyleBuilder) finish() string { func (builder *cssStyleBuilder) finish() string {
@ -168,7 +170,7 @@ func (builder *cssStyleBuilder) finish() string {
func (builder *cssStyleBuilder) startMedia(rule string) { func (builder *cssStyleBuilder) startMedia(rule string) {
if builder.buffer == nil { if builder.buffer == nil {
builder.init() builder.init(0)
} }
builder.buffer.WriteString(`@media screen`) builder.buffer.WriteString(`@media screen`)
builder.buffer.WriteString(rule) builder.buffer.WriteString(rule)
@ -178,7 +180,7 @@ func (builder *cssStyleBuilder) startMedia(rule string) {
func (builder *cssStyleBuilder) endMedia() { func (builder *cssStyleBuilder) endMedia() {
if builder.buffer == nil { if builder.buffer == nil {
builder.init() builder.init(0)
} }
builder.buffer.WriteString(`}\n`) builder.buffer.WriteString(`}\n`)
builder.media = false builder.media = false
@ -192,7 +194,7 @@ func (builder *cssStyleBuilder) startStyle(name string) {
} }
if builder.buffer == nil { if builder.buffer == nil {
builder.init() builder.init(0)
} }
if builder.media { if builder.media {
builder.buffer.WriteString(`\t`) builder.buffer.WriteString(`\t`)
@ -210,7 +212,7 @@ func (builder *cssStyleBuilder) startStyle(name string) {
func (builder *cssStyleBuilder) endStyle() { func (builder *cssStyleBuilder) endStyle() {
if builder.buffer == nil { if builder.buffer == nil {
builder.init() builder.init(0)
} }
if builder.media { if builder.media {
builder.buffer.WriteString(`\t`) builder.buffer.WriteString(`\t`)
@ -220,7 +222,7 @@ func (builder *cssStyleBuilder) endStyle() {
func (builder *cssStyleBuilder) startAnimation(name string) { func (builder *cssStyleBuilder) startAnimation(name string) {
if builder.buffer == nil { if builder.buffer == nil {
builder.init() builder.init(0)
} }
builder.media = true builder.media = true
@ -231,7 +233,7 @@ func (builder *cssStyleBuilder) startAnimation(name string) {
func (builder *cssStyleBuilder) endAnimation() { func (builder *cssStyleBuilder) endAnimation() {
if builder.buffer == nil { if builder.buffer == nil {
builder.init() builder.init(0)
} }
builder.buffer.WriteString(`}\n`) builder.buffer.WriteString(`}\n`)
builder.media = false builder.media = false
@ -239,7 +241,7 @@ func (builder *cssStyleBuilder) endAnimation() {
func (builder *cssStyleBuilder) startAnimationFrame(name string) { func (builder *cssStyleBuilder) startAnimationFrame(name string) {
if builder.buffer == nil { if builder.buffer == nil {
builder.init() builder.init(0)
} }
builder.buffer.WriteString(`\t`) builder.buffer.WriteString(`\t`)
@ -249,7 +251,7 @@ func (builder *cssStyleBuilder) startAnimationFrame(name string) {
func (builder *cssStyleBuilder) endAnimationFrame() { func (builder *cssStyleBuilder) endAnimationFrame() {
if builder.buffer == nil { if builder.buffer == nil {
builder.init() builder.init(0)
} }
builder.buffer.WriteString(`\t}\n`) builder.buffer.WriteString(`\t}\n`)
} }
@ -257,7 +259,7 @@ func (builder *cssStyleBuilder) endAnimationFrame() {
func (builder *cssStyleBuilder) add(key, value string) { func (builder *cssStyleBuilder) add(key, value string) {
if value != "" { if value != "" {
if builder.buffer == nil { if builder.buffer == nil {
builder.init() builder.init(0)
} }
if builder.media { if builder.media {
builder.buffer.WriteString(`\t`) builder.buffer.WriteString(`\t`)
@ -276,7 +278,7 @@ func (builder *cssStyleBuilder) addValues(key, separator string, values ...strin
} }
if builder.buffer == nil { if builder.buffer == nil {
builder.init() builder.init(0)
} }
if builder.media { if builder.media {
builder.buffer.WriteString(`\t`) builder.buffer.WriteString(`\t`)

View File

@ -143,7 +143,7 @@ type Session interface {
finishUpdateScript(htmlID string) finishUpdateScript(htmlID string)
sendResponse() sendResponse()
addAnimationCSS(css string) addAnimationCSS(css string)
clearAnimation() removeAnimation(keyframe string)
canvasStart(htmlID string) canvasStart(htmlID string)
callCanvasFunc(funcName string, args ...any) callCanvasFunc(funcName string, args ...any)
createCanvasVar(funcName string, args ...any) any createCanvasVar(funcName string, args ...any) any
@ -464,14 +464,46 @@ func (session *sessionData) sendResponse() {
} }
func (session *sessionData) addAnimationCSS(css string) { func (session *sessionData) addAnimationCSS(css string) {
session.animationCSS += css
if session.bridge != nil { if session.bridge != nil {
session.bridge.appendAnimationCSS(css) session.bridge.appendAnimationCSS(css)
} }
} }
func (session *sessionData) clearAnimation() { func (session *sessionData) removeAnimation(keyframe string) {
css := session.animationCSS
index := strings.Index(css, "@keyframes "+keyframe)
if index < 0 {
return
}
start := strings.IndexRune(css[index:], '{')
if start < 0 {
return
}
n := 1
end := -1
for i := start + index + 1; i < len(css); i++ {
if css[i] == '}' {
n--
if n == 0 {
end = i + 1
if end < len(css) && css[end] == '\n' {
end++
}
break
}
} else if css[i] == '{' {
n++
}
}
if end > index {
session.animationCSS = css[:index] + css[end:]
if session.bridge != nil { if session.bridge != nil {
session.bridge.setAnimationCSS("") session.bridge.setAnimationCSS(session.animationCSS)
}
} }
} }

View File

@ -589,7 +589,7 @@ func (theme *theme) cssText(session Session) string {
} }
var builder cssStyleBuilder var builder cssStyleBuilder
builder.init() builder.init(16)
styleList := func(styles map[string]ViewStyle) []string { styleList := func(styles map[string]ViewStyle) []string {
ruiStyles := []string{} ruiStyles := []string{}

19
view.go
View File

@ -341,6 +341,25 @@ func (view *viewData) set(tag string, value any) bool {
} }
view.viewID = text view.viewID = text
case AnimationTag:
oldAnimations := []Animation{}
if val, ok := view.properties[AnimationTag]; ok && val != nil {
if animation, ok := val.([]Animation); ok {
oldAnimations = animation
}
}
if !view.setAnimation(tag, value) {
return false
}
for _, animation := range oldAnimations {
animation.unused(view.session)
}
if view.created {
viewPropertyChanged(view, tag)
}
case TabIndex, "tab-index": case TabIndex, "tab-index":
if !view.setIntProperty(tag, value) { if !view.setIntProperty(tag, value) {
return false return false

View File

@ -143,18 +143,26 @@ func (style *viewStyle) setTransition(tag string, value any) bool {
} }
func (style *viewStyle) setAnimation(tag string, value any) bool { func (style *viewStyle) setAnimation(tag string, value any) bool {
set := func(animations []Animation) {
style.properties[tag] = animations
for _, animation := range animations {
animation.used()
}
}
switch value := value.(type) { switch value := value.(type) {
case Animation: case Animation:
style.properties[tag] = []Animation{value} set([]Animation{value})
return true return true
case []Animation: case []Animation:
style.properties[tag] = value set(value)
return true return true
case DataObject: case DataObject:
if animation := parseAnimation(value); animation.hasAnimatedProperty() { if animation := parseAnimation(value); animation.hasAnimatedProperty() {
style.properties[tag] = []Animation{animation} set([]Animation{animation})
return true return true
} }
@ -174,7 +182,7 @@ func (style *viewStyle) setAnimation(tag string, value any) bool {
} }
} }
if result && len(animations) > 0 { if result && len(animations) > 0 {
style.properties[tag] = animations set(animations)
} }
return result return result
} }

View File

@ -284,7 +284,6 @@ func (bridge *webBridge) removeProperty(htmlID, property string) {
} }
func (bridge *webBridge) appendAnimationCSS(css string) { func (bridge *webBridge) appendAnimationCSS(css string) {
//bridge.callFunc("appendAnimationCSS", css)
bridge.writeMessage(`{ bridge.writeMessage(`{
let styles = document.getElementById('ruiAnimations'); let styles = document.getElementById('ruiAnimations');
if (styles) { if (styles) {
@ -294,7 +293,6 @@ func (bridge *webBridge) appendAnimationCSS(css string) {
} }
func (bridge *webBridge) setAnimationCSS(css string) { func (bridge *webBridge) setAnimationCSS(css string) {
//bridge.callFunc("setAnimationCSS", css)
bridge.writeMessage(`{ bridge.writeMessage(`{
let styles = document.getElementById('ruiAnimations'); let styles = document.getElementById('ruiAnimations');
if (styles) { if (styles) {