2021-09-07 17:36:50 +03:00
|
|
|
package rui
|
|
|
|
|
|
|
|
const (
|
|
|
|
// Perspective is the name of the SizeUnit property that determines the distance between the z = 0 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).
|
|
|
|
Perspective = "perspective"
|
|
|
|
// PerspectiveOriginX is the name of the SizeUnit property that determines the 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%.
|
|
|
|
PerspectiveOriginX = "perspective-origin-x"
|
|
|
|
// PerspectiveOriginY is the name of the SizeUnit property that determines the 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%.
|
|
|
|
PerspectiveOriginY = "perspective-origin-y"
|
|
|
|
// BackfaceVisible is the name of the bool property that sets whether the back face of an element is
|
|
|
|
// visible when turned towards the user. Values:
|
2021-11-04 21:13:34 +03:00
|
|
|
// true - the back face is visible when turned towards the user (default value);
|
|
|
|
// false - the back face is hidden, effectively making the element invisible when turned away from the user.
|
2021-09-07 17:36:50 +03:00
|
|
|
BackfaceVisible = "backface-visibility"
|
|
|
|
// OriginX is the name of the SizeUnit property that determines the x-coordinate of the point around which
|
|
|
|
// a view transformation is applied.
|
|
|
|
// The default value is 50%.
|
|
|
|
OriginX = "origin-x"
|
|
|
|
// OriginY is the name of the SizeUnit property that determines the y-coordinate of the point around which
|
|
|
|
// a view transformation is applied.
|
|
|
|
// The default value is 50%.
|
|
|
|
OriginY = "origin-y"
|
|
|
|
// OriginZ is the name of the SizeUnit property that determines the z-coordinate of the point around which
|
|
|
|
// a view transformation is applied.
|
|
|
|
// The default value is 50%.
|
|
|
|
OriginZ = "origin-z"
|
|
|
|
// TranslateX is the name of the SizeUnit property that specify the x-axis translation value
|
|
|
|
// of a 2D/3D translation
|
|
|
|
TranslateX = "translate-x"
|
|
|
|
// TranslateY is the name of the SizeUnit property that specify the y-axis translation value
|
|
|
|
// of a 2D/3D translation
|
|
|
|
TranslateY = "translate-y"
|
|
|
|
// TranslateZ is the name of the SizeUnit property that specify the z-axis translation value
|
|
|
|
// of a 3D translation
|
|
|
|
TranslateZ = "translate-z"
|
|
|
|
// ScaleX is the name of the float property that specify the x-axis scaling value of a 2D/3D scale
|
|
|
|
// The default value is 1.
|
|
|
|
ScaleX = "scale-x"
|
|
|
|
// ScaleY is the name of the float property that specify the y-axis scaling value of a 2D/3D scale
|
|
|
|
// The default value is 1.
|
|
|
|
ScaleY = "scale-y"
|
|
|
|
// ScaleZ is the name of the float property that specify the z-axis scaling value of a 3D scale
|
|
|
|
// The default value is 1.
|
|
|
|
ScaleZ = "scale-z"
|
|
|
|
// Rotate is the name of the AngleUnit property that determines the angle of the view rotation.
|
|
|
|
// A positive angle denotes a clockwise rotation, a negative angle a counter-clockwise one.
|
|
|
|
Rotate = "rotate"
|
|
|
|
// RotateX is the name of the float property that determines the x-coordinate of the vector denoting
|
|
|
|
// the axis of rotation which could between 0 and 1.
|
|
|
|
RotateX = "rotate-x"
|
|
|
|
// RotateY is the name of the float property that determines the y-coordinate of the vector denoting
|
|
|
|
// the axis of rotation which could between 0 and 1.
|
|
|
|
RotateY = "rotate-y"
|
|
|
|
// RotateZ is the name of the float property that determines the z-coordinate of the vector denoting
|
|
|
|
// the axis of rotation which could between 0 and 1.
|
|
|
|
RotateZ = "rotate-z"
|
|
|
|
// SkewX is the name of the AngleUnit property that representing the angle to use to distort
|
|
|
|
// the element along the abscissa. The default value is 0.
|
|
|
|
SkewX = "skew-x"
|
|
|
|
// SkewY is the name of the AngleUnit property that representing the angle to use to distort
|
|
|
|
// the element along the ordinate. The default value is 0.
|
|
|
|
SkewY = "skew-y"
|
|
|
|
)
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-10-04 17:58:17 +03:00
|
|
|
func getSkew(style Properties, session Session) (AngleUnit, AngleUnit, bool) {
|
|
|
|
skewX, okX := angleProperty(style, SkewX, session)
|
|
|
|
skewY, okY := angleProperty(style, SkewY, session)
|
|
|
|
return skewX, skewY, okX || okY
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func getTranslate(style Properties, session Session) (SizeUnit, SizeUnit, SizeUnit) {
|
|
|
|
x, _ := sizeProperty(style, TranslateX, session)
|
|
|
|
y, _ := sizeProperty(style, TranslateY, session)
|
|
|
|
z, _ := sizeProperty(style, TranslateZ, session)
|
|
|
|
return x, y, z
|
|
|
|
}
|
|
|
|
|
|
|
|
func (style *viewStyle) transform(session Session) string {
|
|
|
|
|
|
|
|
buffer := allocStringBuilder()
|
|
|
|
defer freeStringBuilder(buffer)
|
|
|
|
|
2021-10-04 17:58:17 +03:00
|
|
|
skewX, skewY, skewOK := getSkew(style, session)
|
|
|
|
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(')')
|
|
|
|
}
|
|
|
|
|
|
|
|
x, y, z := getTranslate(style, session)
|
2022-08-18 18:18:36 +03:00
|
|
|
|
|
|
|
scaleX, okScaleX := floatTextProperty(style, ScaleX, session, 1)
|
|
|
|
scaleY, okScaleY := floatTextProperty(style, ScaleY, session, 1)
|
|
|
|
|
2021-09-07 17:36:50 +03:00
|
|
|
if getTransform3D(style, session) {
|
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(`)
|
|
|
|
buffer.WriteString(x.cssString("0"))
|
|
|
|
buffer.WriteRune(',')
|
|
|
|
buffer.WriteString(y.cssString("0"))
|
|
|
|
buffer.WriteRune(',')
|
|
|
|
buffer.WriteString(z.cssString("0"))
|
|
|
|
buffer.WriteRune(')')
|
|
|
|
}
|
|
|
|
|
2022-08-18 18:18:36 +03:00
|
|
|
scaleZ, okScaleZ := floatTextProperty(style, ScaleZ, session, 1)
|
|
|
|
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(')')
|
|
|
|
}
|
|
|
|
|
2021-10-04 17:58:17 +03:00
|
|
|
if angle, ok := angleProperty(style, Rotate, session); ok {
|
2022-08-18 18:18:36 +03:00
|
|
|
rotateX, _ := floatTextProperty(style, RotateX, session, 1)
|
|
|
|
rotateY, _ := floatTextProperty(style, RotateY, session, 1)
|
|
|
|
rotateZ, _ := floatTextProperty(style, RotateZ, session, 1)
|
|
|
|
|
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 {
|
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(`)
|
|
|
|
buffer.WriteString(x.cssString("0"))
|
|
|
|
buffer.WriteRune(',')
|
|
|
|
buffer.WriteString(y.cssString("0"))
|
|
|
|
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(')')
|
|
|
|
}
|
|
|
|
|
2021-10-04 17:58:17 +03:00
|
|
|
if angle, ok := angleProperty(style, 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) {
|
|
|
|
if getTransform3D(style, session) {
|
|
|
|
if perspective, ok := sizeProperty(style, Perspective, session); ok && perspective.Type != Auto && perspective.Value != 0 {
|
|
|
|
builder.add(`perspective`, perspective.cssString("0"))
|
|
|
|
}
|
|
|
|
|
|
|
|
x, y := getPerspectiveOrigin(style, session)
|
|
|
|
if x.Type != Auto || y.Type != Auto {
|
|
|
|
builder.addValues(`perspective-origin`, ` `, x.cssString("50%"), y.cssString("50%"))
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
|
|
|
builder.addValues(`transform-origin`, ` `, x.cssString("50%"), y.cssString("50%"), z.cssString("0"))
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
x, y, _ := getOrigin(style, session)
|
|
|
|
if x.Type != Auto || y.Type != Auto {
|
|
|
|
builder.addValues(`transform-origin`, ` `, x.cssString("50%"), y.cssString("50%"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
builder.add(`transform`, style.transform(session))
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
|
|
|
value = x.cssString("50%") + " " + y.cssString("50%")
|
|
|
|
}
|
|
|
|
updateCSSProperty(htmlID, "perspective-origin", value, session)
|
|
|
|
}
|
|
|
|
|
|
|
|
case BackfaceVisible:
|
|
|
|
if getTransform3D(view, session) {
|
2022-08-31 22:17:46 +03:00
|
|
|
if GetBackfaceVisible(view) {
|
2021-09-07 17:36:50 +03:00
|
|
|
updateCSSProperty(htmlID, BackfaceVisible, "visible", session)
|
|
|
|
} else {
|
|
|
|
updateCSSProperty(htmlID, BackfaceVisible, "hidden", session)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
|
|
|
value = x.cssString("50%") + " " + y.cssString("50%") + " " + z.cssString("50%")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if x.Type != Auto || y.Type != Auto {
|
|
|
|
value = x.cssString("50%") + " " + y.cssString("50%")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
updateCSSProperty(htmlID, "transform-origin", value, session)
|
|
|
|
|
|
|
|
case SkewX, SkewY, TranslateX, TranslateY, TranslateZ, ScaleX, ScaleY, ScaleZ, Rotate, RotateX, RotateY, RotateZ:
|
|
|
|
updateCSSProperty(htmlID, "transform", view.transform(session), session)
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|