Skip to content

Commit 287c2f0

Browse files
author
Alexander
committed
ShapeManager. Делаем чтобы для стиллизации текста не нужно было переходить в режим редактирования текста.
1 parent fa32806 commit 287c2f0

File tree

3 files changed

+211
-44
lines changed

3 files changed

+211
-44
lines changed

src/demo/js/listeners/init-canvas-state-listeners.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export default ({
3535
} = serializationControls
3636
const {
3737
getActiveText,
38+
getActiveTextTarget,
3839
syncTextControls,
3940
isTextboxObject
4041
} = textApi
@@ -79,7 +80,7 @@ export default ({
7980
const handleSelectionChange = (event) => {
8081
const eventTarget = event?.target
8182
const explicitTextbox = eventTarget && isTextboxObject(eventTarget) ? eventTarget : null
82-
const textObject = explicitTextbox ?? getActiveText()
83+
const textObject = explicitTextbox ?? getActiveTextTarget()
8384
const shapeGroup = getActiveShape()
8485

8586
if (textObject) {
@@ -141,11 +142,12 @@ export default ({
141142
}
142143
})
143144

144-
editorInstance.canvas.on('object:modified', (event) => {
145+
editorInstance.canvas.on('object:modified', () => {
145146
syncCurrentObjectData()
146147

147-
if (event?.target && event.target === getActiveText()) {
148-
syncTextControls(event.target)
148+
const activeTextTarget = getActiveTextTarget()
149+
if (activeTextTarget) {
150+
syncTextControls(activeTextTarget)
149151
}
150152

151153
const activeShape = getActiveShape()

src/demo/js/listeners/init-text-listeners.js

Lines changed: 107 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,16 @@ export default ({ editorInstance, controls }) => {
148148
return object
149149
}
150150

151+
/**
152+
* Возвращает текстовый target для UI: обычный textbox или текст внутри активного shape.
153+
*/
154+
const getActiveTextTarget = () => {
155+
const activeText = getActiveText()
156+
if (activeText) return activeText
157+
158+
return editorInstance.shapeManager.getTextNode()
159+
}
160+
151161
/**
152162
* Проверяет, считается ли значение жирным начертанием.
153163
*/
@@ -432,17 +442,69 @@ export default ({ editorInstance, controls }) => {
432442
const applyTextStyle = ({ style, options = {} }) => {
433443
if (isSyncingControls) return
434444

435-
const target = getActiveText()
436-
if (!target) return
445+
const activeText = getActiveText()
446+
if (activeText) {
447+
const updated = editorInstance.textManager.updateText({
448+
target: activeText,
449+
style,
450+
...options
451+
})
452+
if (!updated) return
453+
454+
syncTextControls(updated)
455+
return
456+
}
437457

438-
const updated = editorInstance.textManager.updateText({
439-
target,
458+
const updatedShape = editorInstance.shapeManager.updateTextStyle({
440459
style,
441460
...options
442461
})
443-
if (!updated) return
462+
if (!updatedShape) return
444463

445-
syncTextControls(updated)
464+
const updatedText = editorInstance.shapeManager.getTextNode({
465+
target: updatedShape
466+
})
467+
if (!updatedText) return
468+
469+
syncTextControls(updatedText)
470+
}
471+
472+
/**
473+
* Применяет горизонтальное выравнивание к активному тексту или тексту внутри активного shape.
474+
*/
475+
const applyTextAlign = ({ align }) => {
476+
const activeText = getActiveText()
477+
if (activeText) {
478+
applyTextStyle({ style: { align } })
479+
return
480+
}
481+
482+
const updatedShape = editorInstance.shapeManager.setTextAlign({
483+
horizontal: align
484+
})
485+
if (!updatedShape) return
486+
487+
const updatedText = editorInstance.shapeManager.getTextNode({
488+
target: updatedShape
489+
})
490+
if (!updatedText) return
491+
492+
syncTextControls(updatedText)
493+
}
494+
495+
/**
496+
* Возвращает последовательность align-значений для текущего активного target.
497+
*/
498+
const getAlignSequenceForActiveTarget = () => {
499+
const activeText = getActiveText()
500+
if (activeText) return ALIGN_SEQUENCE
501+
502+
const activeShapeText = editorInstance.shapeManager.getTextNode()
503+
if (activeShapeText) {
504+
return ['left', 'center', 'right']
505+
}
506+
507+
return ALIGN_SEQUENCE
446508
}
447509

448510
/**
@@ -621,7 +683,7 @@ export default ({ editorInstance, controls }) => {
621683
})
622684
textColorInput.value = color
623685
setPaletteSelection({ buttons: fillButtons, color })
624-
if (!getActiveText()) return
686+
if (!getActiveTextTarget()) return
625687

626688
applyTextStyle({ style: { color } })
627689
})
@@ -638,9 +700,14 @@ export default ({ editorInstance, controls }) => {
638700
setPaletteSelection({ buttons: strokeButtons, color })
639701

640702
const width = getStrokeWidthFromInput()
641-
if (!getActiveText() || width <= 0) return
703+
if (!getActiveTextTarget() || width <= 0) return
642704

643-
applyTextStyle({ style: { strokeColor: color } })
705+
applyTextStyle({
706+
style: {
707+
strokeColor: color,
708+
strokeWidth: width
709+
}
710+
})
644711
})
645712
}
646713
}
@@ -658,7 +725,7 @@ export default ({ editorInstance, controls }) => {
658725

659726
textContentInput.addEventListener('input', (event) => {
660727
if (isSyncingControls) return
661-
if (!getActiveText()) return
728+
if (!getActiveTextTarget()) return
662729

663730
applyTextStyle({
664731
style: { text: event.target.value },
@@ -667,14 +734,14 @@ export default ({ editorInstance, controls }) => {
667734
})
668735

669736
textContentInput.addEventListener('change', (event) => {
670-
if (!getActiveText()) return
737+
if (!getActiveTextTarget()) return
671738
applyTextStyle({ style: { text: event.target.value } })
672739
})
673740

674741
textFontFamilySelect.addEventListener('change', (event) => {
675742
const { value: family } = event.target
676743
ensureFontOption({ family })
677-
if (!getActiveText()) return
744+
if (!getActiveTextTarget()) return
678745

679746
applyTextStyle({ style: { fontFamily: family } })
680747
})
@@ -683,7 +750,7 @@ export default ({ editorInstance, controls }) => {
683750
const rawValue = Number(event.target.value)
684751
const value = Math.max(1, Number.isNaN(rawValue) ? 1 : Math.round(rawValue))
685752
event.target.value = value
686-
if (!getActiveText()) return
753+
if (!getActiveTextTarget()) return
687754

688755
applyTextStyle({ style: { fontSize: value } })
689756
})
@@ -705,20 +772,21 @@ export default ({ editorInstance, controls }) => {
705772
button.addEventListener('click', () => {
706773
const nextState = !isButtonActive(button)
707774
setToggleActive({ button, isActive: nextState })
708-
if (!getActiveText()) return
775+
if (!getActiveTextTarget()) return
709776

710777
applyTextStyle({ style: { [key]: nextState } })
711778
})
712779
}
713780

714781
textAlignToggle.addEventListener('click', () => {
782+
const alignSequence = getAlignSequenceForActiveTarget()
715783
const currentAlign = textAlignToggle.dataset.align ?? 'left'
716-
const currentIndex = ALIGN_SEQUENCE.indexOf(currentAlign)
717-
const nextAlign = ALIGN_SEQUENCE[(currentIndex + 1) % ALIGN_SEQUENCE.length]
784+
const currentIndex = alignSequence.indexOf(currentAlign)
785+
const nextAlign = alignSequence[(currentIndex + 1) % alignSequence.length]
718786
updateAlignButtonDisplay({ align: nextAlign })
719-
if (!getActiveText()) return
787+
if (!getActiveTextTarget()) return
720788

721-
applyTextStyle({ style: { align: nextAlign } })
789+
applyTextAlign({ align: nextAlign })
722790
})
723791
}
724792

@@ -733,7 +801,7 @@ export default ({ editorInstance, controls }) => {
733801
})
734802
event.target.value = color
735803
setPaletteSelection({ buttons: textColorButtons, color })
736-
if (!getActiveText()) return
804+
if (!getActiveTextTarget()) return
737805

738806
applyTextStyle({ style: { color } })
739807
})
@@ -747,16 +815,21 @@ export default ({ editorInstance, controls }) => {
747815
setPaletteSelection({ buttons: textStrokeButtons, color })
748816

749817
const width = getStrokeWidthFromInput()
750-
if (!getActiveText() || width <= 0) return
818+
if (!getActiveTextTarget() || width <= 0) return
751819

752-
applyTextStyle({ style: { strokeColor: color } })
820+
applyTextStyle({
821+
style: {
822+
strokeColor: color,
823+
strokeWidth: width
824+
}
825+
})
753826
})
754827

755828
textStrokeWidthInput.addEventListener('input', (event) => {
756829
const rawWidth = Number(event.target.value)
757830
const width = Math.max(0, Number.isNaN(rawWidth) ? 0 : Math.round(rawWidth))
758831
setStrokeWidthUI({ width })
759-
if (!getActiveText()) return
832+
if (!getActiveTextTarget()) return
760833

761834
if (width === 0) {
762835
applyTextStyle({
@@ -779,7 +852,7 @@ export default ({ editorInstance, controls }) => {
779852
const rawWidth = Number(event.target.value)
780853
const width = Math.max(0, Number.isNaN(rawWidth) ? 0 : Math.round(rawWidth))
781854
setStrokeWidthUI({ width })
782-
if (!getActiveText()) return
855+
if (!getActiveTextTarget()) return
783856

784857
if (width === 0) {
785858
applyTextStyle({ style: { strokeWidth: 0 } })
@@ -799,7 +872,7 @@ export default ({ editorInstance, controls }) => {
799872
const opacityPercent = Math.max(0, Math.min(100, Number.isNaN(rawOpacity) ? 0 : rawOpacity))
800873
event.target.value = opacityPercent
801874
textOpacityValue.textContent = `${opacityPercent}%`
802-
if (!getActiveText()) return
875+
if (!getActiveTextTarget()) return
803876

804877
applyTextStyle({
805878
style: { opacity: opacityPercent / 100 },
@@ -812,7 +885,7 @@ export default ({ editorInstance, controls }) => {
812885
const opacityPercent = Math.max(0, Math.min(100, Number.isNaN(rawOpacity) ? 0 : rawOpacity))
813886
event.target.value = opacityPercent
814887
textOpacityValue.textContent = `${opacityPercent}%`
815-
if (!getActiveText()) return
888+
if (!getActiveTextTarget()) return
816889

817890
applyTextStyle({ style: { opacity: opacityPercent / 100 } })
818891
})
@@ -825,7 +898,7 @@ export default ({ editorInstance, controls }) => {
825898
textBackgroundEnabledCheckbox.addEventListener('change', () => {
826899
const enabled = Boolean(textBackgroundEnabledCheckbox.checked)
827900
setBackgroundControlsEnabled({ enabled })
828-
if (!getActiveText()) return
901+
if (!getActiveTextTarget()) return
829902

830903
if (!enabled) {
831904
applyTextStyle({ style: { backgroundColor: '' } })
@@ -841,7 +914,7 @@ export default ({ editorInstance, controls }) => {
841914
fallback: textBackgroundColorInput.value
842915
})
843916
event.target.value = color
844-
if (!getActiveText()) return
917+
if (!getActiveTextTarget()) return
845918
if (!textBackgroundEnabledCheckbox.checked) return
846919

847920
applyTextStyle({ style: { backgroundColor: color } })
@@ -855,7 +928,7 @@ export default ({ editorInstance, controls }) => {
855928
fallback: 100
856929
})
857930
textBackgroundOpacityValue.textContent = `${opacityPercent}%`
858-
if (!getActiveText()) return
931+
if (!getActiveTextTarget()) return
859932
if (!textBackgroundEnabledCheckbox.checked) return
860933

861934
applyTextStyle({
@@ -872,7 +945,7 @@ export default ({ editorInstance, controls }) => {
872945
fallback: 100
873946
})
874947
textBackgroundOpacityValue.textContent = `${opacityPercent}%`
875-
if (!getActiveText()) return
948+
if (!getActiveTextTarget()) return
876949
if (!textBackgroundEnabledCheckbox.checked) return
877950

878951
applyTextStyle({ style: { backgroundOpacity: opacityPercent / 100 } })
@@ -893,7 +966,7 @@ export default ({ editorInstance, controls }) => {
893966
for (const { input, key } of paddingInputs) {
894967
input.addEventListener('input', () => {
895968
const value = parseNumberInput({ input, min: 0, fallback: 0 })
896-
if (!getActiveText()) return
969+
if (!getActiveTextTarget()) return
897970
if (!textBackgroundEnabledCheckbox.checked) return
898971

899972
applyTextStyle({
@@ -904,7 +977,7 @@ export default ({ editorInstance, controls }) => {
904977

905978
input.addEventListener('change', () => {
906979
const value = parseNumberInput({ input, min: 0, fallback: 0 })
907-
if (!getActiveText()) return
980+
if (!getActiveTextTarget()) return
908981
if (!textBackgroundEnabledCheckbox.checked) return
909982

910983
applyTextStyle({ style: { [key]: value } })
@@ -926,7 +999,7 @@ export default ({ editorInstance, controls }) => {
926999
for (const { input, key } of radiusInputs) {
9271000
input.addEventListener('input', () => {
9281001
const value = parseNumberInput({ input, min: 0, fallback: 0 })
929-
if (!getActiveText()) return
1002+
if (!getActiveTextTarget()) return
9301003
if (!textBackgroundEnabledCheckbox.checked) return
9311004

9321005
applyTextStyle({
@@ -937,7 +1010,7 @@ export default ({ editorInstance, controls }) => {
9371010

9381011
input.addEventListener('change', () => {
9391012
const value = parseNumberInput({ input, min: 0, fallback: 0 })
940-
if (!getActiveText()) return
1013+
if (!getActiveTextTarget()) return
9411014
if (!textBackgroundEnabledCheckbox.checked) return
9421015

9431016
applyTextStyle({ style: { [key]: value } })
@@ -956,6 +1029,7 @@ export default ({ editorInstance, controls }) => {
9561029

9571030
return {
9581031
getActiveText,
1032+
getActiveTextTarget,
9591033
syncTextControls,
9601034
isTextboxObject
9611035
}

0 commit comments

Comments
 (0)