mirror of https://github.com/anoshenko/rui.git
				
				
				
			Optimised animation
This commit is contained in:
		
							parent
							
								
									09031b9fa0
								
							
						
					
					
						commit
						2f3de8fce3
					
				
							
								
								
									
										22
									
								
								animation.go
								
								
								
								
							
							
						
						
									
										22
									
								
								animation.go
								
								
								
								
							|  | @ -120,6 +120,7 @@ type AnimatedProperty struct { | |||
| type animationData struct { | ||||
| 	propertyList | ||||
| 	keyFramesName string | ||||
| 	usageCounter  int | ||||
| } | ||||
| 
 | ||||
| // Animation interface is used to set animation parameters. Used properties:
 | ||||
|  | @ -132,6 +133,8 @@ type Animation interface { | |||
| 	transitionCSS(buffer *strings.Builder, session Session) | ||||
| 	hasAnimatedProperty() bool | ||||
| 	animationName() string | ||||
| 	used() | ||||
| 	unused(session Session) | ||||
| } | ||||
| 
 | ||||
| func parseAnimation(obj DataObject) Animation { | ||||
|  | @ -179,6 +182,17 @@ func (animation *animationData) animationName() string { | |||
| 	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 { | ||||
| 	tag = strings.ToLower(tag) | ||||
| 	if tag == Direction { | ||||
|  | @ -387,7 +401,7 @@ func (animation *animationData) animationCSS(session Session) string { | |||
| 		} | ||||
| 
 | ||||
| 		animatedProps, ok := props.([]AnimatedProperty) | ||||
| 		if !ok { | ||||
| 		if !ok || len(animatedProps) == 0 { | ||||
| 			ErrorLog("Invalid animated properties.") | ||||
| 			return "" | ||||
| 		} | ||||
|  | @ -549,6 +563,7 @@ func (session *sessionData) registerAnimation(props []AnimatedProperty) string { | |||
| 
 | ||||
| 	var cssBuilder cssStyleBuilder | ||||
| 
 | ||||
| 	cssBuilder.init(0) | ||||
| 	cssBuilder.startAnimation(name) | ||||
| 
 | ||||
| 	fromParams := Params{} | ||||
|  | @ -606,10 +621,7 @@ func (session *sessionData) registerAnimation(props []AnimatedProperty) string { | |||
| 	cssBuilder.endAnimationFrame() | ||||
| 
 | ||||
| 	cssBuilder.endAnimation() | ||||
| 
 | ||||
| 	style := cssBuilder.finish() | ||||
| 	session.animationCSS += style | ||||
| 	session.addAnimationCSS(style) | ||||
| 	session.addAnimationCSS(cssBuilder.finish()) | ||||
| 
 | ||||
| 	return name | ||||
| } | ||||
|  |  | |||
|  | @ -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.Grow(16 * 1024) | ||||
| 	if kbSize > 0 { | ||||
| 		builder.buffer.Grow(kbSize * 1024) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (builder *cssStyleBuilder) finish() string { | ||||
|  | @ -168,7 +170,7 @@ func (builder *cssStyleBuilder) finish() string { | |||
| 
 | ||||
| func (builder *cssStyleBuilder) startMedia(rule string) { | ||||
| 	if builder.buffer == nil { | ||||
| 		builder.init() | ||||
| 		builder.init(0) | ||||
| 	} | ||||
| 	builder.buffer.WriteString(`@media screen`) | ||||
| 	builder.buffer.WriteString(rule) | ||||
|  | @ -178,7 +180,7 @@ func (builder *cssStyleBuilder) startMedia(rule string) { | |||
| 
 | ||||
| func (builder *cssStyleBuilder) endMedia() { | ||||
| 	if builder.buffer == nil { | ||||
| 		builder.init() | ||||
| 		builder.init(0) | ||||
| 	} | ||||
| 	builder.buffer.WriteString(`}\n`) | ||||
| 	builder.media = false | ||||
|  | @ -192,7 +194,7 @@ func (builder *cssStyleBuilder) startStyle(name string) { | |||
| 	} | ||||
| 
 | ||||
| 	if builder.buffer == nil { | ||||
| 		builder.init() | ||||
| 		builder.init(0) | ||||
| 	} | ||||
| 	if builder.media { | ||||
| 		builder.buffer.WriteString(`\t`) | ||||
|  | @ -210,7 +212,7 @@ func (builder *cssStyleBuilder) startStyle(name string) { | |||
| 
 | ||||
| func (builder *cssStyleBuilder) endStyle() { | ||||
| 	if builder.buffer == nil { | ||||
| 		builder.init() | ||||
| 		builder.init(0) | ||||
| 	} | ||||
| 	if builder.media { | ||||
| 		builder.buffer.WriteString(`\t`) | ||||
|  | @ -220,7 +222,7 @@ func (builder *cssStyleBuilder) endStyle() { | |||
| 
 | ||||
| func (builder *cssStyleBuilder) startAnimation(name string) { | ||||
| 	if builder.buffer == nil { | ||||
| 		builder.init() | ||||
| 		builder.init(0) | ||||
| 	} | ||||
| 
 | ||||
| 	builder.media = true | ||||
|  | @ -231,7 +233,7 @@ func (builder *cssStyleBuilder) startAnimation(name string) { | |||
| 
 | ||||
| func (builder *cssStyleBuilder) endAnimation() { | ||||
| 	if builder.buffer == nil { | ||||
| 		builder.init() | ||||
| 		builder.init(0) | ||||
| 	} | ||||
| 	builder.buffer.WriteString(`}\n`) | ||||
| 	builder.media = false | ||||
|  | @ -239,7 +241,7 @@ func (builder *cssStyleBuilder) endAnimation() { | |||
| 
 | ||||
| func (builder *cssStyleBuilder) startAnimationFrame(name string) { | ||||
| 	if builder.buffer == nil { | ||||
| 		builder.init() | ||||
| 		builder.init(0) | ||||
| 	} | ||||
| 
 | ||||
| 	builder.buffer.WriteString(`\t`) | ||||
|  | @ -249,7 +251,7 @@ func (builder *cssStyleBuilder) startAnimationFrame(name string) { | |||
| 
 | ||||
| func (builder *cssStyleBuilder) endAnimationFrame() { | ||||
| 	if builder.buffer == nil { | ||||
| 		builder.init() | ||||
| 		builder.init(0) | ||||
| 	} | ||||
| 	builder.buffer.WriteString(`\t}\n`) | ||||
| } | ||||
|  | @ -257,7 +259,7 @@ func (builder *cssStyleBuilder) endAnimationFrame() { | |||
| func (builder *cssStyleBuilder) add(key, value string) { | ||||
| 	if value != "" { | ||||
| 		if builder.buffer == nil { | ||||
| 			builder.init() | ||||
| 			builder.init(0) | ||||
| 		} | ||||
| 		if builder.media { | ||||
| 			builder.buffer.WriteString(`\t`) | ||||
|  | @ -276,7 +278,7 @@ func (builder *cssStyleBuilder) addValues(key, separator string, values ...strin | |||
| 	} | ||||
| 
 | ||||
| 	if builder.buffer == nil { | ||||
| 		builder.init() | ||||
| 		builder.init(0) | ||||
| 	} | ||||
| 	if builder.media { | ||||
| 		builder.buffer.WriteString(`\t`) | ||||
|  |  | |||
							
								
								
									
										40
									
								
								session.go
								
								
								
								
							
							
						
						
									
										40
									
								
								session.go
								
								
								
								
							|  | @ -143,7 +143,7 @@ type Session interface { | |||
| 	finishUpdateScript(htmlID string) | ||||
| 	sendResponse() | ||||
| 	addAnimationCSS(css string) | ||||
| 	clearAnimation() | ||||
| 	removeAnimation(keyframe string) | ||||
| 	canvasStart(htmlID string) | ||||
| 	callCanvasFunc(funcName string, args ...any) | ||||
| 	createCanvasVar(funcName string, args ...any) any | ||||
|  | @ -464,14 +464,46 @@ func (session *sessionData) sendResponse() { | |||
| } | ||||
| 
 | ||||
| func (session *sessionData) addAnimationCSS(css string) { | ||||
| 	session.animationCSS += css | ||||
| 	if session.bridge != nil { | ||||
| 		session.bridge.appendAnimationCSS(css) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (session *sessionData) clearAnimation() { | ||||
| 	if session.bridge != nil { | ||||
| 		session.bridge.setAnimationCSS("") | ||||
| 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 { | ||||
| 			session.bridge.setAnimationCSS(session.animationCSS) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										2
									
								
								theme.go
								
								
								
								
							
							
						
						
									
										2
									
								
								theme.go
								
								
								
								
							|  | @ -589,7 +589,7 @@ func (theme *theme) cssText(session Session) string { | |||
| 	} | ||||
| 
 | ||||
| 	var builder cssStyleBuilder | ||||
| 	builder.init() | ||||
| 	builder.init(16) | ||||
| 
 | ||||
| 	styleList := func(styles map[string]ViewStyle) []string { | ||||
| 		ruiStyles := []string{} | ||||
|  |  | |||
							
								
								
									
										19
									
								
								view.go
								
								
								
								
							
							
						
						
									
										19
									
								
								view.go
								
								
								
								
							|  | @ -341,6 +341,25 @@ func (view *viewData) set(tag string, value any) bool { | |||
| 		} | ||||
| 		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": | ||||
| 		if !view.setIntProperty(tag, value) { | ||||
| 			return false | ||||
|  |  | |||
|  | @ -143,18 +143,26 @@ func (style *viewStyle) setTransition(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) { | ||||
| 	case Animation: | ||||
| 		style.properties[tag] = []Animation{value} | ||||
| 		set([]Animation{value}) | ||||
| 		return true | ||||
| 
 | ||||
| 	case []Animation: | ||||
| 		style.properties[tag] = value | ||||
| 		set(value) | ||||
| 		return true | ||||
| 
 | ||||
| 	case DataObject: | ||||
| 		if animation := parseAnimation(value); animation.hasAnimatedProperty() { | ||||
| 			style.properties[tag] = []Animation{animation} | ||||
| 			set([]Animation{animation}) | ||||
| 			return true | ||||
| 		} | ||||
| 
 | ||||
|  | @ -174,7 +182,7 @@ func (style *viewStyle) setAnimation(tag string, value any) bool { | |||
| 			} | ||||
| 		} | ||||
| 		if result && len(animations) > 0 { | ||||
| 			style.properties[tag] = animations | ||||
| 			set(animations) | ||||
| 		} | ||||
| 		return result | ||||
| 	} | ||||
|  |  | |||
|  | @ -284,7 +284,6 @@ func (bridge *webBridge) removeProperty(htmlID, property string) { | |||
| } | ||||
| 
 | ||||
| func (bridge *webBridge) appendAnimationCSS(css string) { | ||||
| 	//bridge.callFunc("appendAnimationCSS", css)
 | ||||
| 	bridge.writeMessage(`{ | ||||
| 	let styles = document.getElementById('ruiAnimations'); | ||||
| 	if (styles) { | ||||
|  | @ -294,7 +293,6 @@ func (bridge *webBridge) appendAnimationCSS(css string) { | |||
| } | ||||
| 
 | ||||
| func (bridge *webBridge) setAnimationCSS(css string) { | ||||
| 	//bridge.callFunc("setAnimationCSS", css)
 | ||||
| 	bridge.writeMessage(`{ | ||||
| 	let styles = document.getElementById('ruiAnimations'); | ||||
| 	if (styles) { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue