2021-09-07 17:36:50 +03:00
package rui
2024-08-13 13:52:47 +03:00
import (
"fmt"
"math"
"strings"
)
2024-09-12 14:05:11 +03:00
// Constants for [Transform] specific properties
2021-09-07 17:36:50 +03:00
const (
2024-09-18 13:50:06 +03:00
// Perspective is the constant for "perspective" property tag.
//
// Used by `View`.
// Distance between the z-plane and the user in order to give a 3D-positioned element some perspective. Each 3D element
// with z > 0 becomes larger, each 3D-element with z < 0 becomes smaller. The default value is 0 (no 3D effects).
//
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
//
// Internal type is `SizeUnit`, other types converted to it during assignment.
// See `SizeUnit` description for more details.
2021-09-07 17:36:50 +03:00
Perspective = "perspective"
2024-08-13 13:52:47 +03:00
2024-09-18 13:50:06 +03:00
// PerspectiveOriginX is the constant for "perspective-origin-x" property tag.
//
// Used by `View`.
// x-coordinate of the position at which the viewer is looking. It is used as the vanishing point by the "perspective"
// property. The default value is 50%.
//
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
//
// Internal type is `SizeUnit`, other types converted to it during assignment.
// See `SizeUnit` description for more details.
2021-09-07 17:36:50 +03:00
PerspectiveOriginX = "perspective-origin-x"
2024-08-13 13:52:47 +03:00
2024-09-18 13:50:06 +03:00
// PerspectiveOriginY is the constant for "perspective-origin-y" property tag.
//
// Used by `View`.
// y-coordinate of the position at which the viewer is looking. It is used as the vanishing point by the "perspective"
// property. The default value is 50%.
//
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
//
// Internal type is `SizeUnit`, other types converted to it during assignment.
// See `SizeUnit` description for more details.
2021-09-07 17:36:50 +03:00
PerspectiveOriginY = "perspective-origin-y"
2024-08-13 13:52:47 +03:00
2024-09-18 13:50:06 +03:00
// BackfaceVisible is the constant for "backface-visibility" property tag.
//
// Used by `View`.
// Controls whether the back face of a view is visible when turned towards the user. Default value is `true`.
//
// Supported types: `bool`, `int`, `string`.
//
// Values:
// `true` or `1` or "true", "yes", "on", "1" - Back face is visible when turned towards the user.
// `false` or `0` or "false", "no", "off", "0" - Back face is hidden, effectively making the view invisible when turned away from the user.
2021-09-07 17:36:50 +03:00
BackfaceVisible = "backface-visibility"
2024-08-13 13:52:47 +03:00
2024-09-18 13:50:06 +03:00
// OriginX is the constant for "origin-x" property tag.
//
// Used by `View`.
// x-coordinate of the point around which a view transformation is applied. The default value is 50%.
//
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
//
// Internal type is `SizeUnit`, other types converted to it during assignment.
// See `SizeUnit` description for more details.
2021-09-07 17:36:50 +03:00
OriginX = "origin-x"
2024-08-13 13:52:47 +03:00
2024-09-18 13:50:06 +03:00
// OriginY is the constant for "origin-y" property tag.
//
// Used by `View`.
// y-coordinate of the point around which a view transformation is applied. The default value is 50%.
//
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
//
// Internal type is `SizeUnit`, other types converted to it during assignment.
// See `SizeUnit` description for more details.
2021-09-07 17:36:50 +03:00
OriginY = "origin-y"
2024-08-13 13:52:47 +03:00
2024-09-18 13:50:06 +03:00
// OriginZ is the constant for "origin-z" property tag.
//
// Used by `View`.
// z-coordinate of the point around which a view transformation is applied. The default value is 50%.
//
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
//
// Internal type is `SizeUnit`, other types converted to it during assignment.
// See `SizeUnit` description for more details.
2021-09-07 17:36:50 +03:00
OriginZ = "origin-z"
2024-08-13 13:52:47 +03:00
2024-09-18 13:50:06 +03:00
// TransformTag is the constant for "transform" property tag.
//
// Used by `View`.
// Specify translation, scale and rotation over x, y and z axes as well as a distorsion of a view along x and y axes.
//
// Supported types: `Transform`, `string`.
//
// See `Transform` description for more details.
//
// Conversion rules:
// `Transform` - stored as is, no conversion performed.
// `string` - string representation of `Transform` interface. Example: "_{translate-x = 10px, scale-y = 1.1}".
2024-08-13 13:52:47 +03:00
TransformTag = "transform"
2024-09-18 13:50:06 +03:00
// TranslateX is the constant for "translate-x" property tag.
//
// Used by `View`, `Transform`.
//
// Usage in `View`:
// x-axis translation value of a 2D/3D translation.
//
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
//
// Internal type is `SizeUnit`, other types converted to it during assignment.
// See `SizeUnit` description for more details.
//
// Usage in `Transform`:
// x-axis translation value of a 2D/3D translation.
//
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
//
// Internal type is `SizeUnit`, other types converted to it during assignment.
// See `SizeUnit` description for more details.
2021-09-07 17:36:50 +03:00
TranslateX = "translate-x"
2024-08-13 13:52:47 +03:00
2024-09-18 13:50:06 +03:00
// TranslateY is the constant for "translate-y" property tag.
//
// Used by `View`, `Transform`.
//
// Usage in `View`:
// y-axis translation value of a 2D/3D translation.
//
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
//
// Internal type is `SizeUnit`, other types converted to it during assignment.
// See `SizeUnit` description for more details.
//
// Usage in `Transform`:
// x-axis translation value of a 2D/3D translation.
//
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
//
// Internal type is `SizeUnit`, other types converted to it during assignment.
// See `SizeUnit` description for more details.
2021-09-07 17:36:50 +03:00
TranslateY = "translate-y"
2024-08-13 13:52:47 +03:00
2024-09-18 13:50:06 +03:00
// TranslateZ is the constant for "translate-z" property tag.
//
// Used by `View`, `Transform`.
//
// Usage in `View`:
// z-axis translation value of a 3D translation.
//
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
//
// Internal type is `SizeUnit`, other types converted to it during assignment.
// See `SizeUnit` description for more details.
//
// Usage in `Transform`:
// z-axis translation value of a 3D translation.
//
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
//
// Internal type is `SizeUnit`, other types converted to it during assignment.
// See `SizeUnit` description for more details.
2021-09-07 17:36:50 +03:00
TranslateZ = "translate-z"
2024-08-13 13:52:47 +03:00
2024-09-18 13:50:06 +03:00
// ScaleX is the constant for "scale-x" property tag.
//
// Used by `View`, `Transform`.
//
// Usage in `View`:
// x-axis scaling value of a 2D/3D scale. The original scale is 1. Values between 0 and 1 are used to decrease original
// scale, more than 1 - to increase. The default value is 1.
//
// Supported types: `float`, `int`, `string`.
//
// Internal type is `float`, other types converted to it during assignment.
//
// Usage in `Transform`:
// x-axis scaling value of a 2D/3D scale. The original scale is 1. Values between 0 and 1 are used to decrease original
// scale, more than 1 - to increase. The default value is 1.
//
// Supported types: `float`, `int`, `string`.
//
// Internal type is `float`, other types converted to it during assignment.
2021-09-07 17:36:50 +03:00
ScaleX = "scale-x"
2024-08-13 13:52:47 +03:00
2024-09-18 13:50:06 +03:00
// ScaleY is the constant for "scale-y" property tag.
//
// Used by `View`, `Transform`.
//
// Usage in `View`:
// y-axis scaling value of a 2D/3D scale. The original scale is 1. Values between 0 and 1 are used to decrease original
// scale, more than 1 - to increase. The default value is 1.
//
// Supported types: `float`, `int`, `string`.
//
// Internal type is `float`, other types converted to it during assignment.
//
// Usage in `Transform`:
// y-axis scaling value of a 2D/3D scale. The original scale is 1. Values between 0 and 1 are used to decrease original
// scale, more than 1 - to increase. The default value is 1.
//
// Supported types: `float`, `int`, `string`.
//
// Internal type is `float`, other types converted to it during assignment.
2021-09-07 17:36:50 +03:00
ScaleY = "scale-y"
2024-08-13 13:52:47 +03:00
2024-09-18 13:50:06 +03:00
// ScaleZ is the constant for "scale-z" property tag.
//
// Used by `View`, `Transform`.
//
// Usage in `View`:
// z-axis scaling value of a 3D scale. The original scale is 1. Values between 0 and 1 are used to decrease original
// scale, more than 1 - to increase. The default value is 1.
//
// Supported types: `float`, `int`, `string`.
//
// Internal type is `float`, other types converted to it during assignment.
//
// Usage in `Transform`:
// z-axis scaling value of a 3D scale. The original scale is 1. Values between 0 and 1 are used to decrease original
// scale, more than 1 - to increase. The default value is 1.
//
// Supported types: `float`, `int`, `string`.
//
// Internal type is `float`, other types converted to it during assignment.
2021-09-07 17:36:50 +03:00
ScaleZ = "scale-z"
2024-08-13 13:52:47 +03:00
2024-09-18 13:50:06 +03:00
// Rotate is the constant for "rotate" property tag.
//
// Used by `View`, `Transform`.
//
// Usage in `View`:
// Angle of the view rotation. A positive angle denotes a clockwise rotation, a negative angle a counter-clockwise.
//
// Supported types: `AngleUnit`, `string`, `float`, `int`.
//
// Internal type is `AngleUnit`, other types will be converted to it during assignment.
// See `AngleUnit` description for more details.
//
// Conversion rules:
// `AngleUnit` - stored as is, no conversion performed.
// `string` - must contain string representation of `AngleUnit`. If numeric value will be provided without any suffix then `AngleUnit` with value and `Radian` value type will be created.
// `float` - a new `AngleUnit` value will be created with `Radian` as a type.
// `int` - a new `AngleUnit` value will be created with `Radian` as a type.
//
// Usage in `Transform`:
// Angle of the view rotation. A positive angle denotes a clockwise rotation, a negative angle a counter-clockwise.
//
// Supported types: `AngleUnit`, `string`, `float`, `int`.
//
// Internal type is `AngleUnit`, other types will be converted to it during assignment.
// See `AngleUnit` description for more details.
//
// Conversion rules:
// `AngleUnit` - stored as is, no conversion performed.
// `string` - must contain string representation of `AngleUnit`. If numeric value will be provided without any suffix then `AngleUnit` with value and `Radian` value type will be created.
// `float` - a new `AngleUnit` value will be created with `Radian` as a type.
// `int` - a new `AngleUnit` value will be created with `Radian` as a type.
2021-09-07 17:36:50 +03:00
Rotate = "rotate"
2024-08-13 13:52:47 +03:00
2024-09-18 13:50:06 +03:00
// RotateX is the constant for "rotate-x" property tag.
//
// Used by `View`, `Transform`.
//
// Usage in `View`:
// x-coordinate of the vector denoting the axis of rotation in range 0 to 1.
//
// Supported types: `float`, `int`, `string`.
//
// Internal type is `float`, other types converted to it during assignment.
//
// Usage in `Transform`:
// x-coordinate of the vector denoting the axis of rotation in range 0 to 1.
//
// Supported types: `float`, `int`, `string`.
//
// Internal type is `float`, other types converted to it during assignment.
2021-09-07 17:36:50 +03:00
RotateX = "rotate-x"
2024-08-13 13:52:47 +03:00
2024-09-18 13:50:06 +03:00
// RotateY is the constant for "rotate-y" property tag.
//
// Used by `View`, `Transform`.
//
// Usage in `View`:
// y-coordinate of the vector denoting the axis of rotation in range 0 to 1.
//
// Supported types: `float`, `int`, `string`.
//
// Internal type is `float`, other types converted to it during assignment.
//
// Usage in `Transform`:
// y-coordinate of the vector denoting the axis of rotation in range 0 to 1.
//
// Supported types: `float`, `int`, `string`.
//
// Internal type is `float`, other types converted to it during assignment.
2021-09-07 17:36:50 +03:00
RotateY = "rotate-y"
2024-08-13 13:52:47 +03:00
2024-09-18 13:50:06 +03:00
// RotateZ is the constant for "rotate-z" property tag.
//
// Used by `View`, `Transform`.
//
// Usage in `View`:
// z-coordinate of the vector denoting the axis of rotation in range 0 to 1.
//
// Supported types: `float`, `int`, `string`.
//
// Internal type is `float`, other types converted to it during assignment.
//
// Usage in `Transform`:
// z-coordinate of the vector denoting the axis of rotation in range 0 to 1.
//
// Supported types: `float`, `int`, `string`.
//
// Internal type is `float`, other types converted to it during assignment.
2021-09-07 17:36:50 +03:00
RotateZ = "rotate-z"
2024-08-13 13:52:47 +03:00
2024-09-18 13:50:06 +03:00
// SkewX is the constant for "skew-x" property tag.
//
// Used by `View`, `Transform`.
//
// Usage in `View`:
// Angle to use to distort the element along the abscissa. The default value is 0.
//
// Supported types: `AngleUnit`, `string`, `float`, `int`.
//
// Internal type is `AngleUnit`, other types will be converted to it during assignment.
// See `AngleUnit` description for more details.
//
// Conversion rules:
// `AngleUnit` - stored as is, no conversion performed.
// `string` - must contain string representation of `AngleUnit`. If numeric value will be provided without any suffix then `AngleUnit` with value and `Radian` value type will be created.
// `float` - a new `AngleUnit` value will be created with `Radian` as a type.
// `int` - a new `AngleUnit` value will be created with `Radian` as a type.
//
// Usage in `Transform`:
// Angle to use to distort the element along the abscissa. The default value is 0.
//
// Supported types: `AngleUnit`, `string`, `float`, `int`.
//
// Internal type is `AngleUnit`, other types will be converted to it during assignment.
// See `AngleUnit` description for more details.
//
// Conversion rules:
// `AngleUnit` - stored as is, no conversion performed.
// `string` - must contain string representation of `AngleUnit`. If numeric value will be provided without any suffix then `AngleUnit` with value and `Radian` value type will be created.
// `float` - a new `AngleUnit` value will be created with `Radian` as a type.
// `int` - a new `AngleUnit` value will be created with `Radian` as a type.
2021-09-07 17:36:50 +03:00
SkewX = "skew-x"
2024-08-13 13:52:47 +03:00
2024-09-18 13:50:06 +03:00
// SkewY is the constant for "skew-y" property tag.
//
// Used by `View`, `Transform`.
//
// Usage in `View`:
// Angle to use to distort the element along the ordinate. The default value is 0.
//
// Supported types: `AngleUnit`, `string`, `float`, `int`.
//
// Internal type is `AngleUnit`, other types will be converted to it during assignment.
// See `AngleUnit` description for more details.
//
// Conversion rules:
// `AngleUnit` - stored as is, no conversion performed.
// `string` - must contain string representation of `AngleUnit`. If numeric value will be provided without any suffix then `AngleUnit` with value and `Radian` value type will be created.
// `float` - a new `AngleUnit` value will be created with `Radian` as a type.
// `int` - a new `AngleUnit` value will be created with `Radian` as a type.
//
// Usage in `Transform`:
// Angle to use to distort the element along the ordinate. The default value is 0.
//
// Supported types: `AngleUnit`, `string`, `float`, `int`.
//
// Internal type is `AngleUnit`, other types will be converted to it during assignment.
// See `AngleUnit` description for more details.
//
// Conversion rules:
// `AngleUnit` - stored as is, no conversion performed.
// `string` - must contain string representation of `AngleUnit`. If numeric value will be provided without any suffix then `AngleUnit` with value and `Radian` value type will be created.
// `float` - a new `AngleUnit` value will be created with `Radian` as a type.
// `int` - a new `AngleUnit` value will be created with `Radian` as a type.
2021-09-07 17:36:50 +03:00
SkewY = "skew-y"
)
2024-08-13 13:52:47 +03:00
// Transform interface specifies view transformation parameters: the x-, y-, and z-axis translation values,
// the x-, y-, and z-axis scaling values, the angle to use to distort the element along the abscissa and ordinate,
// the angle of the view rotation.
// Valid property tags: TranslateX ("translate-x"), TranslateY ("translate-y"), TranslateZ ("translate-z"),
// ScaleX ("scale-x"), ScaleY ("scale-y"), ScaleZ ("scale-z"), Rotate ("rotate"), RotateX ("rotate-x"),
// RotateY ("rotate-y"), RotateZ ("rotate-z"), SkewX ("skew-x"), and SkewY ("skew-y")
type Transform interface {
Properties
fmt . Stringer
stringWriter
transformCSS ( session Session , transform3D bool ) string
}
type transformData struct {
propertyList
}
2024-09-12 14:05:11 +03:00
// NewTransform creates a new transform property data and return its interface
2024-08-13 13:52:47 +03:00
func NewTransform ( params Params ) Transform {
transform := new ( transformData )
transform . properties = map [ string ] any { }
for tag , value := range params {
transform . Set ( tag , value )
}
return transform
}
func ( style * viewStyle ) setTransform ( value any ) bool {
setObject := func ( obj DataObject ) bool {
transform := NewTransform ( nil )
ok := true
for i := 0 ; i < obj . PropertyCount ( ) ; i ++ {
if prop := obj . Property ( i ) ; prop . Type ( ) == TextNode {
if ! transform . Set ( prop . Tag ( ) , prop . Text ( ) ) {
ok = false
}
} else {
ok = false
}
}
if ! ok && len ( transform . AllTags ( ) ) == 0 {
return false
}
style . properties [ TransformTag ] = transform
return true
}
switch value := value . ( type ) {
case Transform :
style . properties [ TransformTag ] = value
2024-08-13 16:27:54 +03:00
return true
2024-08-13 13:52:47 +03:00
case DataObject :
return setObject ( value )
case DataNode :
if obj := value . Object ( ) ; obj != nil {
return setObject ( obj )
}
notCompatibleType ( TransformTag , value )
return false
case string :
if obj := ParseDataText ( value ) ; obj != nil {
return setObject ( obj )
}
notCompatibleType ( TransformTag , value )
return false
}
return false
}
func ( style * viewStyle ) transformProperty ( ) Transform {
if val , ok := style . properties [ TransformTag ] ; ok {
if transform , ok := val . ( Transform ) ; ok {
return transform
}
}
return nil
}
func ( style * viewStyle ) setTransformProperty ( tag string , value any ) bool {
switch tag {
case RotateX , RotateY , RotateZ , Rotate , SkewX , SkewY , ScaleX , ScaleY , ScaleZ , TranslateX , TranslateY , TranslateZ :
if transform := style . transformProperty ( ) ; transform != nil {
return transform . Set ( tag , value )
}
transform := NewTransform ( nil )
if ! transform . Set ( tag , value ) {
return false
}
style . properties [ TransformTag ] = transform
return true
}
ErrorLogF ( ` "Transform" interface does not support the "%s" property ` , tag )
return false
}
func ( transform * transformData ) String ( ) string {
buffer := allocStringBuilder ( )
defer freeStringBuilder ( buffer )
transform . writeString ( buffer , "" )
return buffer . String ( )
}
func ( transform * transformData ) writeString ( buffer * strings . Builder , indent string ) {
buffer . WriteString ( "_{ " )
comma := false
for _ , tag := range [ ] string { SkewX , SkewY , TranslateX , TranslateY , TranslateZ ,
ScaleX , ScaleY , ScaleZ , Rotate , RotateX , RotateY , RotateZ } {
if value , ok := transform . properties [ tag ] ; ok {
if comma {
buffer . WriteString ( ", " )
}
buffer . WriteString ( tag )
buffer . WriteString ( " = " )
writePropertyValue ( buffer , tag , value , indent )
comma = true
}
}
buffer . WriteString ( " }" )
}
func ( transform * transformData ) Set ( tag string , value any ) bool {
return transform . set ( strings . ToLower ( tag ) , value )
}
func ( transform * transformData ) set ( tag string , value any ) bool {
if value == nil {
_ , exist := transform . properties [ tag ]
if exist {
delete ( transform . properties , tag )
}
return exist
}
switch tag {
case RotateX , RotateY , RotateZ :
return transform . setFloatProperty ( tag , value , 0 , 1 )
case Rotate , SkewX , SkewY :
return transform . setAngleProperty ( tag , value )
case ScaleX , ScaleY , ScaleZ :
return transform . setFloatProperty ( tag , value , - math . MaxFloat64 , math . MaxFloat64 )
case TranslateX , TranslateY , TranslateZ :
return transform . setSizeProperty ( tag , value )
}
return false
}
2021-09-07 17:36:50 +03:00
func getTransform3D ( style Properties , session Session ) bool {
perspective , ok := sizeProperty ( style , Perspective , session )
return ok && perspective . Type != Auto && perspective . Value != 0
}
func getPerspectiveOrigin ( style Properties , session Session ) ( SizeUnit , SizeUnit ) {
x , _ := sizeProperty ( style , PerspectiveOriginX , session )
y , _ := sizeProperty ( style , PerspectiveOriginY , session )
return x , y
}
func getOrigin ( style Properties , session Session ) ( SizeUnit , SizeUnit , SizeUnit ) {
x , _ := sizeProperty ( style , OriginX , session )
y , _ := sizeProperty ( style , OriginY , session )
z , _ := sizeProperty ( style , OriginZ , session )
return x , y , z
}
2024-08-13 13:52:47 +03:00
func ( transform * transformData ) getSkew ( session Session ) ( AngleUnit , AngleUnit , bool ) {
skewX , okX := angleProperty ( transform , SkewX , session )
skewY , okY := angleProperty ( transform , SkewY , session )
2021-10-04 17:58:17 +03:00
return skewX , skewY , okX || okY
2021-09-07 17:36:50 +03:00
}
2024-08-13 13:52:47 +03:00
func ( transform * transformData ) getTranslate ( session Session ) ( SizeUnit , SizeUnit , SizeUnit ) {
x , _ := sizeProperty ( transform , TranslateX , session )
y , _ := sizeProperty ( transform , TranslateY , session )
z , _ := sizeProperty ( transform , TranslateZ , session )
2021-09-07 17:36:50 +03:00
return x , y , z
}
2024-08-13 13:52:47 +03:00
func ( transform * transformData ) transformCSS ( session Session , transform3D bool ) string {
2021-09-07 17:36:50 +03:00
buffer := allocStringBuilder ( )
defer freeStringBuilder ( buffer )
2024-08-13 13:52:47 +03:00
skewX , skewY , skewOK := transform . getSkew ( session )
2021-10-04 17:58:17 +03:00
if skewOK {
2021-09-07 17:36:50 +03:00
buffer . WriteString ( ` skew( ` )
buffer . WriteString ( skewX . cssString ( ) )
buffer . WriteRune ( ',' )
buffer . WriteString ( skewY . cssString ( ) )
buffer . WriteRune ( ')' )
}
2024-08-13 13:52:47 +03:00
x , y , z := transform . getTranslate ( session )
2022-08-18 18:18:36 +03:00
2024-08-13 13:52:47 +03:00
scaleX , okScaleX := floatTextProperty ( transform , ScaleX , session , 1 )
scaleY , okScaleY := floatTextProperty ( transform , ScaleY , session , 1 )
2022-08-18 18:18:36 +03:00
2024-08-13 13:52:47 +03:00
if transform3D {
2021-10-04 17:58:17 +03:00
if x . Type != Auto || y . Type != Auto || z . Type != Auto {
2021-09-07 17:36:50 +03:00
if buffer . Len ( ) > 0 {
buffer . WriteRune ( ' ' )
}
buffer . WriteString ( ` translate3d( ` )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( x . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
buffer . WriteRune ( ',' )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( y . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
buffer . WriteRune ( ',' )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( z . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
buffer . WriteRune ( ')' )
}
2024-08-13 13:52:47 +03:00
scaleZ , okScaleZ := floatTextProperty ( transform , ScaleZ , session , 1 )
2022-08-18 18:18:36 +03:00
if okScaleX || okScaleY || okScaleZ {
2021-09-07 17:36:50 +03:00
if buffer . Len ( ) > 0 {
buffer . WriteRune ( ' ' )
}
buffer . WriteString ( ` scale3d( ` )
2022-08-18 18:18:36 +03:00
buffer . WriteString ( scaleX )
2021-09-07 17:36:50 +03:00
buffer . WriteRune ( ',' )
2022-08-18 18:18:36 +03:00
buffer . WriteString ( scaleY )
2021-09-07 17:36:50 +03:00
buffer . WriteRune ( ',' )
2022-08-18 18:18:36 +03:00
buffer . WriteString ( scaleZ )
2021-09-07 17:36:50 +03:00
buffer . WriteRune ( ')' )
}
2024-08-13 13:52:47 +03:00
if angle , ok := angleProperty ( transform , Rotate , session ) ; ok {
rotateX , _ := floatTextProperty ( transform , RotateX , session , 1 )
rotateY , _ := floatTextProperty ( transform , RotateY , session , 1 )
rotateZ , _ := floatTextProperty ( transform , RotateZ , session , 1 )
2022-08-18 18:18:36 +03:00
2021-09-07 17:36:50 +03:00
if buffer . Len ( ) > 0 {
buffer . WriteRune ( ' ' )
}
buffer . WriteString ( ` rotate3d( ` )
2022-08-18 18:18:36 +03:00
buffer . WriteString ( rotateX )
2021-09-07 17:36:50 +03:00
buffer . WriteRune ( ',' )
2022-08-18 18:18:36 +03:00
buffer . WriteString ( rotateY )
2021-09-07 17:36:50 +03:00
buffer . WriteRune ( ',' )
2022-08-18 18:18:36 +03:00
buffer . WriteString ( rotateZ )
2021-09-07 17:36:50 +03:00
buffer . WriteRune ( ',' )
buffer . WriteString ( angle . cssString ( ) )
buffer . WriteRune ( ')' )
}
2021-10-04 17:58:17 +03:00
2021-09-07 17:36:50 +03:00
} else {
2024-08-13 13:52:47 +03:00
2021-10-04 17:58:17 +03:00
if x . Type != Auto || y . Type != Auto {
2021-09-07 17:36:50 +03:00
if buffer . Len ( ) > 0 {
buffer . WriteRune ( ' ' )
}
buffer . WriteString ( ` translate( ` )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( x . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
buffer . WriteRune ( ',' )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( y . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
buffer . WriteRune ( ')' )
}
2022-08-18 18:18:36 +03:00
if okScaleX || okScaleY {
2021-09-07 17:36:50 +03:00
if buffer . Len ( ) > 0 {
buffer . WriteRune ( ' ' )
}
buffer . WriteString ( ` scale( ` )
2022-08-18 18:18:36 +03:00
buffer . WriteString ( scaleX )
2021-09-07 17:36:50 +03:00
buffer . WriteRune ( ',' )
2022-08-18 18:18:36 +03:00
buffer . WriteString ( scaleY )
2021-09-07 17:36:50 +03:00
buffer . WriteRune ( ')' )
}
2024-08-13 13:52:47 +03:00
if angle , ok := angleProperty ( transform , Rotate , session ) ; ok {
2021-09-07 17:36:50 +03:00
if buffer . Len ( ) > 0 {
buffer . WriteRune ( ' ' )
}
buffer . WriteString ( ` rotate( ` )
buffer . WriteString ( angle . cssString ( ) )
buffer . WriteRune ( ')' )
}
}
return buffer . String ( )
}
func ( style * viewStyle ) writeViewTransformCSS ( builder cssBuilder , session Session ) {
2024-08-13 13:52:47 +03:00
transform3D := getTransform3D ( style , session )
if transform3D {
2021-09-07 17:36:50 +03:00
if perspective , ok := sizeProperty ( style , Perspective , session ) ; ok && perspective . Type != Auto && perspective . Value != 0 {
2022-09-05 14:00:07 +03:00
builder . add ( ` perspective ` , perspective . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
}
x , y := getPerspectiveOrigin ( style , session )
if x . Type != Auto || y . Type != Auto {
2022-09-05 14:00:07 +03:00
builder . addValues ( ` perspective-origin ` , ` ` , x . cssString ( "50%" , session ) , y . cssString ( "50%" , session ) )
2021-09-07 17:36:50 +03:00
}
if backfaceVisible , ok := boolProperty ( style , BackfaceVisible , session ) ; ok {
if backfaceVisible {
builder . add ( ` backface-visibility ` , ` visible ` )
} else {
builder . add ( ` backface-visibility ` , ` hidden ` )
}
}
x , y , z := getOrigin ( style , session )
if x . Type != Auto || y . Type != Auto || z . Type != Auto {
2022-09-05 14:00:07 +03:00
builder . addValues ( ` transform-origin ` , ` ` , x . cssString ( "50%" , session ) , y . cssString ( "50%" , session ) , z . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
}
} else {
x , y , _ := getOrigin ( style , session )
if x . Type != Auto || y . Type != Auto {
2022-09-05 14:00:07 +03:00
builder . addValues ( ` transform-origin ` , ` ` , x . cssString ( "50%" , session ) , y . cssString ( "50%" , session ) )
2021-09-07 17:36:50 +03:00
}
}
2024-08-13 13:52:47 +03:00
if transform := style . transformProperty ( ) ; transform != nil {
builder . add ( ` transform ` , transform . transformCSS ( session , transform3D ) )
}
2021-09-07 17:36:50 +03:00
}
func ( view * viewData ) updateTransformProperty ( tag string ) bool {
htmlID := view . htmlID ( )
session := view . session
switch tag {
case Perspective :
updateCSSStyle ( htmlID , session )
case PerspectiveOriginX , PerspectiveOriginY :
if getTransform3D ( view , session ) {
2022-08-31 22:17:46 +03:00
x , y := GetPerspectiveOrigin ( view )
2021-09-07 17:36:50 +03:00
value := ""
if x . Type != Auto || y . Type != Auto {
2022-09-05 14:00:07 +03:00
value = x . cssString ( "50%" , session ) + " " + y . cssString ( "50%" , session )
2021-09-07 17:36:50 +03:00
}
2022-10-30 17:22:33 +03:00
session . updateCSSProperty ( htmlID , "perspective-origin" , value )
2021-09-07 17:36:50 +03:00
}
case BackfaceVisible :
if getTransform3D ( view , session ) {
2022-08-31 22:17:46 +03:00
if GetBackfaceVisible ( view ) {
2022-10-30 17:22:33 +03:00
session . updateCSSProperty ( htmlID , BackfaceVisible , "visible" )
2021-09-07 17:36:50 +03:00
} else {
2022-10-30 17:22:33 +03:00
session . updateCSSProperty ( htmlID , BackfaceVisible , "hidden" )
2021-09-07 17:36:50 +03:00
}
}
case OriginX , OriginY , OriginZ :
x , y , z := getOrigin ( view , session )
value := ""
if getTransform3D ( view , session ) {
if x . Type != Auto || y . Type != Auto || z . Type != Auto {
2022-09-05 14:00:07 +03:00
value = x . cssString ( "50%" , session ) + " " + y . cssString ( "50%" , session ) + " " + z . cssString ( "50%" , session )
2021-09-07 17:36:50 +03:00
}
} else {
if x . Type != Auto || y . Type != Auto {
2022-09-05 14:00:07 +03:00
value = x . cssString ( "50%" , session ) + " " + y . cssString ( "50%" , session )
2021-09-07 17:36:50 +03:00
}
}
2022-10-30 17:22:33 +03:00
session . updateCSSProperty ( htmlID , "transform-origin" , value )
2021-09-07 17:36:50 +03:00
2024-08-13 13:52:47 +03:00
case TransformTag , SkewX , SkewY , TranslateX , TranslateY , TranslateZ ,
ScaleX , ScaleY , ScaleZ , Rotate , RotateX , RotateY , RotateZ :
if transform := view . transformProperty ( ) ; transform != nil {
transform3D := getTransform3D ( view , session )
session . updateCSSProperty ( htmlID , "transform" , transform . transformCSS ( session , transform3D ) )
} else {
session . updateCSSProperty ( htmlID , "transform" , "" )
}
2021-09-07 17:36:50 +03:00
default :
return false
}
return true
}