@ -2,7 +2,6 @@ import { CODES, KEYS } from "../keys";
import {
isWritableElement ,
getFontString ,
viewportCoordsToSceneCoords ,
getFontFamilyString ,
} from "../utils" ;
import Scene from "../scene/Scene" ;
@ -37,16 +36,20 @@ const getTransform = (
angle : number ,
appState : AppState ,
maxWidth : number ,
maxHeight : number ,
) = > {
const { zoom , offsetTop , offsetLeft } = appState ;
const degree = ( 180 * angle ) / Math . PI ;
// offsets must be multiplied by 2 to account for the division by 2 of
// the whole expression afterwards
let translateX = ( ( width - offsetLeft * 2 ) * ( zoom . value - 1 ) ) / 2 ;
cons t translateY = ( ( height - offsetTop * 2 ) * ( zoom . value - 1 ) ) / 2 ;
le t translateY = ( ( height - offsetTop * 2 ) * ( zoom . value - 1 ) ) / 2 ;
if ( width > maxWidth && zoom . value !== 1 ) {
translateX = ( maxWidth / 2 ) * ( zoom . value - 1 ) ;
}
if ( height > maxHeight && zoom . value !== 1 ) {
translateY = ( ( maxHeight - offsetTop * 2 ) * ( zoom . value - 1 ) ) / 2 ;
}
return ` translate( ${ translateX } px, ${ translateY } px) scale( ${ zoom . value } ) rotate( ${ degree } deg) ` ;
} ;
@ -106,12 +109,13 @@ export const textWysiwyg = ({
let maxHeight = updatedElement . height ;
let width = updatedElement . width ;
let height = updatedElement . height ;
const height = Math . max ( editable . scrollHeight , updatedElement . height ) ;
if ( container && updatedElement . containerId ) {
const propertiesUpdated = textPropertiesUpdated (
updatedElement ,
editable ,
) ;
if ( propertiesUpdated ) {
const currentContainer = Scene . getScene ( updatedElement ) ? . getElement (
updatedElement . containerId ,
@ -133,15 +137,14 @@ export const textWysiwyg = ({
maxWidth = container . width - PADDING * 2 ;
maxHeight = container . height - PADDING * 2 ;
width = maxWidth ;
height = Math . min ( height , maxHeight ) ;
// The coordinates of text box set a distance of
// 30px to preserve padding
coordX = container . x + PADDING ;
// autogrow container height if text exceeds
if ( editable . client Height > maxHeight ) {
if ( editable . scroll Height > maxHeight ) {
const diff = Math . min (
editable . client Height - maxHeight ,
editable . scroll Height - maxHeight ,
approxLineHeight ,
) ;
mutateElement ( container , { height : container.height + diff } ) ;
@ -150,10 +153,10 @@ export const textWysiwyg = ({
// autoshrink container height until original container height
// is reached when text is removed
container . height > originalContainerHeight &&
editable . client Height < maxHeight
editable . scroll Height < maxHeight
) {
const diff = Math . min (
maxHeight - editable . client Height,
maxHeight - editable . scroll Height,
approxLineHeight ,
) ;
mutateElement ( container , { height : container.height - diff } ) ;
@ -161,18 +164,17 @@ export const textWysiwyg = ({
// Start pushing text upward until a diff of 30px (padding)
// is reached
else {
const lines = editable . client Height / approxLineHeight ;
const lines = editable . scroll Height / approxLineHeight ;
// For some reason the scrollHeight gets set to twice the lineHeight
// when you start typing for first time and thus line count is 2
// hence this check
if ( lines > 2 || propertiesUpdated ) {
// vertically center align the text
coordY =
container . y + container . height / 2 - editable . client Height / 2 ;
container . y + container . height / 2 - editable . scroll Height / 2 ;
}
}
}
const [ viewportX , viewportY ] = getViewportCoords ( coordX , coordY ) ;
const { textAlign , angle } = updatedElement ;
@ -192,19 +194,35 @@ export const textWysiwyg = ({
) . marginRight . slice ( 0 , - 2 ) ,
) ;
}
// Make sure text editor height doesn't go beyond viewport
const editorMaxHeight =
( appState . offsetTop + appState . height - viewportY ) /
( appState . height -
viewportY -
// There is a ~14px difference which keeps on increasing
// with every zoom step when offset present hence I am subtracting it here
// However this is not the best fix and breaks in
// few scenarios
( appState . offsetTop
? ( ( appState . zoom . value * 100 - 100 ) / 10 ) * 14
: 0 ) ) /
appState . zoom . value ;
Object . assign ( editable . style , {
font : getFontString ( updatedElement ) ,
// must be defined *after* font ¯\_(ツ)_/¯
lineHeight : ` ${ lineHeight } px ` ,
width : ` ${ width } px ` ,
height : ` ${ Math . max ( editable . clientHeight , updatedElement . height ) } px ` ,
height : ` ${ height } px ` ,
left : ` ${ viewportX } px ` ,
top : ` ${ viewportY } px ` ,
transform : getTransform ( width , height , angle , appState , maxWidth ) ,
transform : getTransform (
width ,
height ,
angle ,
appState ,
maxWidth ,
editorMaxHeight ,
) ,
textAlign ,
color : updatedElement.strokeColor ,
opacity : updatedElement.opacity / 100 ,
@ -416,20 +434,16 @@ export const textWysiwyg = ({
getFontString ( updateElement ) ,
container . width ,
) ;
const { x , y } = viewportCoordsToSceneCoords (
{
clientX : Number ( editable . style . left . slice ( 0 , - 2 ) ) ,
clientY : Number ( editable . style . top . slice ( 0 , - 2 ) ) ,
} ,
appState ,
) ;
if ( isTextElement ( updateElement ) && updateElement . containerId ) {
const editorHeight = Number ( editable . style . height . slice ( 0 , - 2 ) ) ;
if ( editable . value ) {
mutateElement ( updateElement , {
y : y + appState . offsetTop ,
height : Number ( editable . style . height . slice ( 0 , - 2 ) ) ,
// vertically center align
y : container.y + container . height / 2 - editorHeight / 2 ,
height : editorHeight ,
width : Number ( editable . style . width . slice ( 0 , - 2 ) ) ,
x : x + appState . offsetLeft ,
// preserve padding
x : container.x + PADDING ,
} ) ;
const boundTextElementId = getBoundTextElementId ( container ) ;
if ( ! boundTextElementId || boundTextElementId !== element . id ) {