diff --git a/docs/git commit message Convention.pdf b/docs/git commit message Convention.pdf new file mode 100644 index 00000000..1df33833 Binary files /dev/null and b/docs/git commit message Convention.pdf differ diff --git a/src/app/layout.js b/src/app/layout.js index c3ac72de..30a6e8ee 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -10,10 +10,10 @@ import { ToastContainer } from 'react-toastify' import Header from '@/components/header/Header' import QModal from '@/components/common/modal/QModal' +import { QcastProvider } from './QcastProvider' import './globals.css' import '../styles/style.scss' -import { QcastProvider } from './QcastProvider' const inter = Inter({ subsets: ['latin'] }) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index d8b4c25e..fe79d2b5 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -42,6 +42,7 @@ import { SurfaceShapeModal } from '@/components/ui/SurfaceShape' import { changeAllGableRoof, drawDirectionStringToArrow } from '@/util/qpolygon-utils' import ThumbnailList from '@/components/ui/ThumbnailLIst' import ObjectPlacement from '@/components/ui/ObjectPlacement' +import { globalLocaleStore } from '@/store/localeAtom' export default function Roof2(props) { const { name, userId, email, isLoggedIn } = props @@ -58,7 +59,9 @@ export default function Roof2(props) { setBackImg, } = useCanvas('canvas') - const { get } = useAxios() + const globalLocaleState = useRecoilValue(globalLocaleStore) + + const { get } = useAxios(globalLocaleState) const canvasRef = useRef(null) diff --git a/src/components/auth/Login.jsx b/src/components/auth/Login.jsx index 326f5720..d71870e2 100644 --- a/src/components/auth/Login.jsx +++ b/src/components/auth/Login.jsx @@ -11,10 +11,9 @@ import { useRecoilState } from 'recoil' import { globalLocaleStore } from '@/store/localeAtom' import { modalContent, modalState } from '@/store/modalAtom' -export default function Login(props) { +export default function Login() { const { patch } = useAxios() - const { currentLocale } = props const { getMessage } = useMessage() const [globalLocaleState, setGlbalLocaleState] = useRecoilState(globalLocaleStore) const [isSelected, setIsSelected] = useState(globalLocaleState === 'ko' ? true : false) diff --git a/src/components/floor-plan/CanvasLayout.jsx b/src/components/floor-plan/CanvasLayout.jsx index 71c48845..9990aa21 100644 --- a/src/components/floor-plan/CanvasLayout.jsx +++ b/src/components/floor-plan/CanvasLayout.jsx @@ -1,15 +1,15 @@ 'use client' -import { useState } from 'react' +import { useEffect, useState } from 'react' import CanvasFrame from './CanvasFrame' import { useRecoilState, useRecoilValue } from 'recoil' import { currentMenuState, stepState } from '@/store/canvasAtom' export default function CanvasLayout() { const [plans, setPlans] = useState([ - { id: 0, name: 'Plan 1' }, - { id: 1, name: 'Plan 2' }, - { id: 2, name: 'Plan 3' }, + { id: 0, name: 'Plan 1', isCurrent: false }, + { id: 1, name: 'Plan 2', isCurrent: false }, + { id: 2, name: 'Plan 3', isCurrent: false }, ]) const [idxNum, setIdxNum] = useState(null) @@ -26,6 +26,12 @@ export default function CanvasLayout() { setPlans([...plans, { id: plans.length, name: `Plan ${plans.length + 1}` }]) } + useEffect(() => { + if (plans.length === 1) { + setPlans([{ id: 0, name: 'Plan 1', isCurrent: false }]) + } + }, []) + return (
diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 477cdfde..c916a0fc 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -1,19 +1,23 @@ 'use client' + import { useEffect, useState } from 'react' import MenuDepth01 from './MenuDepth01' import QSelectBox from '@/components/common/select/QSelectBox' import { useMessage } from '@/hooks/useMessage' import { post } from '@/lib/Axios' -import { useRecoilState } from 'recoil' -import { settingModalFirstOptionsState } from '@/store/settingAtom' +import { useRecoilState, useRecoilValue } from 'recoil' +import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' +import { canvasZoomState, verticalHorizontalModeState } from '@/store/canvasAtom' export default function CanvasMenu(props) { - const [objectNo] = useState('test123240912001') + const [objectNo] = useState('test123240912001') // 이후 삭제 필요 const { setShowCanvasSettingModal, showOutlineModal, setShowOutlineModal } = props const [menuNumber, setMenuNumber] = useState(null) + const [verticalHorizontalMode, setVerticalHorizontalMode] = useRecoilState(verticalHorizontalModeState) const [vertical, setVertical] = useState(true) const [type, setType] = useState('') const { getMessage } = useMessage() + const canvasZoom = useRecoilValue(canvasZoomState) const SelectOption = [{ name: '瓦53A' }, { name: '瓦53A' }] const onClickNav = (number) => { setMenuNumber(number) @@ -26,7 +30,8 @@ export default function CanvasMenu(props) { type, } - const settingsModalOptions = useRecoilState(settingModalFirstOptionsState) + const firstOptions = useRecoilState(settingModalFirstOptionsState) + const secondOptions = useRecoilState(settingModalSecondOptionsState) useEffect(() => {}, [menuNumber, type]) @@ -35,11 +40,19 @@ export default function CanvasMenu(props) { try { // 서버에 전송할 데이터 const dataToSend = { - option1: settingsModalOptions[0].option1.map((item) => ({ + firstOption1: firstOptions[0].option1.map((item) => ({ column: item.column, selected: item.selected, })), - option2: settingsModalOptions[0].option2.map((item) => ({ + firstOption2: firstOptions[0].option2.map((item) => ({ + column: item.column, + selected: item.selected, + })), + // secondOption1: secondOptions[0].option1.map((item) => ({ + // name: item.name, + // // 필요한 경우 추가 데이터 항목 + // })), + secondOption2: secondOptions[0].option2.map((item) => ({ column: item.column, selected: item.selected, })), @@ -47,20 +60,24 @@ export default function CanvasMenu(props) { const patternData = { objectNo, - assignDisplay: dataToSend.option1[0].selected, - drawDisplay: dataToSend.option1[1].selected, - gridDisplay: dataToSend.option1[2].selected, - charDisplay: dataToSend.option1[3].selected, - flowDisplay: dataToSend.option1[4].selected, - hallwayDimenDisplay: dataToSend.option1[5].selected, - actualDimenDisplay: dataToSend.option1[6].selected, - noDimenDisplay: dataToSend.option1[7].selected, - trestleDisplay: dataToSend.option1[8].selected, - coordiDisplay: dataToSend.option1[9].selected, - drawConverDisplay: dataToSend.option1[10].selected, - onlyBorder: dataToSend.option2[0].selected, - lineHatch: dataToSend.option2[1].selected, - allPainted: dataToSend.option2[2].selected, + assignDisplay: dataToSend.firstOption1[0].selected, + drawDisplay: dataToSend.firstOption1[1].selected, + gridDisplay: dataToSend.firstOption1[2].selected, + charDisplay: dataToSend.firstOption1[3].selected, + flowDisplay: dataToSend.firstOption1[4].selected, + hallwayDimenDisplay: dataToSend.firstOption1[5].selected, + actualDimenDisplay: dataToSend.firstOption1[6].selected, + noDimenDisplay: dataToSend.firstOption1[7].selected, + trestleDisplay: dataToSend.firstOption1[8].selected, + coordiDisplay: dataToSend.firstOption1[9].selected, + drawConverDisplay: dataToSend.firstOption1[10].selected, + onlyBorder: dataToSend.firstOption2[0].selected, + lineHatch: dataToSend.firstOption2[1].selected, + allPainted: dataToSend.firstOption2[2].selected, + adsorpRangeSmall: dataToSend.secondOption2[0].selected, + adsorpRangeSmallSemi: dataToSend.secondOption2[1].selected, + adsorpRangeMedium: dataToSend.secondOption2[2].selected, + adsorpRangeLarge: dataToSend.secondOption2[3].selected, } // HTTP POST 요청 보내기 @@ -135,9 +152,9 @@ export default function CanvasMenu(props) {
{menuNumber !== 4 && ( -
+
{getMessage('plan.mode.vertical.horizontal')} - +
)}
@@ -150,7 +167,7 @@ export default function CanvasMenu(props) {
- 100% + {canvasZoom}%
diff --git a/src/components/floor-plan/FloorPlan.jsx b/src/components/floor-plan/FloorPlan.jsx index 206c41c4..33e522ee 100644 --- a/src/components/floor-plan/FloorPlan.jsx +++ b/src/components/floor-plan/FloorPlan.jsx @@ -6,10 +6,15 @@ import CanvasLayout from '@/components/floor-plan/CanvasLayout' import '@/styles/contents.scss' import OuterLineWall from '@/components/floor-plan/modal/outerlinesetting/OuterLineWall' import { useEffect, useState } from 'react' +import { globalLocaleStore } from '@/store/localeAtom' +import { useRecoilValue } from 'recoil' +import { useAxios } from '@/hooks/useAxios' export default function FloorPlan() { const [showCanvasSettingModal, setShowCanvasSettingModal] = useState(false) const [showOutlineModal, setShowOutlineModal] = useState(false) + const globalLocaleState = useRecoilValue(globalLocaleStore) + const { get } = useAxios(globalLocaleState) const canvasSettingProps = { setShowCanvasSettingModal, diff --git a/src/components/floor-plan/modal/outerlinesetting/OuterLineWall.jsx b/src/components/floor-plan/modal/outerlinesetting/OuterLineWall.jsx index c8a61e11..05d7cb0c 100644 --- a/src/components/floor-plan/modal/outerlinesetting/OuterLineWall.jsx +++ b/src/components/floor-plan/modal/outerlinesetting/OuterLineWall.jsx @@ -5,7 +5,7 @@ import WithDraggable from '@/components/common/draggable/withDraggable' import { useRecoilState, useRecoilValue } from 'recoil' import { useMessage } from '@/hooks/useMessage' import { useEvent } from '@/hooks/useEvent' -import { canvasState } from '@/store/canvasAtom' +import { canvasState, verticalHorizontalModeState } from '@/store/canvasAtom' import { OUTER_LINE_TYPE, outerLineArrow1State, @@ -17,12 +17,15 @@ import { } from '@/store/outerLineAtom' import { QLine } from '@/components/fabric/QLine' import { useLine } from '@/hooks/useLine' +import { distanceBetweenPoints } from '@/util/canvas-util' export default function OuterLineWall(props) { const { setShowOutlineModal } = props const { getMessage } = useMessage() - const { addCanvasMouseEventListener, addDocumentEventListener, removeAllDocumentEventListeners } = useEvent() + const { addCanvasMouseEventListener, addDocumentEventListener, removeAllMouseEventListeners, removeAllDocumentEventListeners } = useEvent() const { addLineText, removeLineText } = useLine() + const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState) + const length1Ref = useRef(null) const length2Ref = useRef(null) const [length1, setLength1] = useRecoilState(outerLineLength1State) @@ -37,8 +40,9 @@ export default function OuterLineWall(props) { const canvas = useRecoilValue(canvasState) useEffect(() => { + removeAllMouseEventListeners() addCanvasMouseEventListener('mouse:down', mouseDown) - }, []) + }, [verticalHorizontalMode, points]) useEffect(() => { arrow1Ref.current = arrow1 @@ -64,8 +68,44 @@ export default function OuterLineWall(props) { const mouseDown = (e) => { const pointer = canvas.getPointer(e.e) + if (points.length === 0) { + setPoints((prev) => [...prev, pointer]) + } else { + const lastPoint = points[points.length - 1] + let newPoint = { x: pointer.x, y: pointer.y } + const length = distanceBetweenPoints(lastPoint, newPoint) + if (verticalHorizontalMode) { + const vector = { + x: pointer.x - points[points.length - 1].x, + y: pointer.y - points[points.length - 1].y, + } + const slope = Math.abs(vector.y / vector.x) // 기울기 계산 - setPoints((prev) => [...prev, pointer]) + let scaledVector + if (slope >= 1) { + // 기울기가 1 이상이면 x축 방향으로 그림 + scaledVector = { + x: 0, + y: vector.y >= 0 ? Number(length) : -Number(length), + } + } else { + // 기울기가 1 미만이면 y축 방향으로 그림 + scaledVector = { + x: vector.x >= 0 ? Number(length) : -Number(length), + y: 0, + } + } + + const verticalLength = scaledVector.y + const horizontalLength = scaledVector.x + + newPoint = { + x: lastPoint.x + horizontalLength, + y: lastPoint.y + verticalLength, + } + } + setPoints((prev) => [...prev, newPoint]) + } } useEffect(() => { @@ -76,7 +116,18 @@ export default function OuterLineWall(props) { canvas?.remove(obj) removeLineText(obj) }) + + canvas + ?.getObjects() + .filter((obj) => obj.name === 'helpGuideLine' || (obj.name === 'lengthTxt' && obj.parent?.name === 'helpGuideLine')) + .forEach((obj) => canvas?.remove(obj)) + canvas?.remove(canvas?.getObjects().find((obj) => obj.name === 'startPoint')) + + // point가 변경 될때마다 이벤트 리스너를 제거하고 다시 등록 + removeAllDocumentEventListeners() + addDocumentEventListener('keydown', document, keydown[type]) + if (points.length === 0) { return } @@ -100,13 +151,58 @@ export default function OuterLineWall(props) { } drawLine(points[idx - 1], point, idx) }) + + const lastPoint = points[points.length - 1] + const firstPoint = points[0] + + if (points.length < 3) { + return + } + + if (lastPoint.x === firstPoint.x && lastPoint.y === firstPoint.y) { + return + } + + if (lastPoint.x === firstPoint.x || lastPoint.y === firstPoint.y) { + const line = new QLine([lastPoint.x, lastPoint.y, firstPoint.x, firstPoint.y], { + stroke: 'grey', + strokeWidth: 1, + selectable: false, + name: 'helpGuideLine', + }) + + canvas?.add(line) + addLineText(line) + } else { + const guideLine1 = new QLine([lastPoint.x, lastPoint.y, lastPoint.x, firstPoint.y], { + stroke: 'grey', + strokeWidth: 1, + strokeDashArray: [1, 1, 1], + name: 'helpGuideLine', + }) + + const guideLine2 = new QLine([guideLine1.x2, guideLine1.y2, firstPoint.x, firstPoint.y], { + stroke: 'grey', + strokeWidth: 1, + strokeDashArray: [1, 1, 1], + name: 'helpGuideLine', + }) + if (guideLine1.length > 0) { + canvas?.add(guideLine1) + addLineText(guideLine1) + } + + canvas?.add(guideLine2) + + addLineText(guideLine2) + } } }, [points]) const drawLine = (point1, point2, idx) => { const line = new QLine([point1.x, point1.y, point2.x, point2.y], { stroke: 'black', - strokeWidth: 1, + strokeWidth: 3, idx: idx, selectable: false, name: 'outerLine', @@ -190,6 +286,9 @@ export default function OuterLineWall(props) { const keydown = { outerLine: (e) => { + if (points.length === 0) { + return + } const key = e.key if (!length1Ref.current) { @@ -245,11 +344,12 @@ export default function OuterLineWall(props) { } }, rightAngle: (e) => { + if (points.length === 0) { + return + } const key = e.key const activeElem = document.activeElement - const length1Num = Number(length1Ref.current.value) / 10 - const length2Num = Number(length2Ref.current.value) / 10 switch (key) { case 'Down': // IE/Edge에서 사용되는 값 @@ -339,6 +439,9 @@ export default function OuterLineWall(props) { } const handleFix = () => { + if (points.length < 3) { + return + } setPoints((prev) => { if (prev.length === 0) { return [] @@ -449,10 +552,10 @@ export default function OuterLineWall(props) { <> )}
- - ))} @@ -26,8 +64,8 @@ export default function SecondOption() {

{getMessage('modal.canvas.setting.font.plan.absorption')}

- {settingsModalOptions.option2.map((item) => ( - diff --git a/src/hooks/useAxios.js b/src/hooks/useAxios.js index d06d3a2e..852a1798 100644 --- a/src/hooks/useAxios.js +++ b/src/hooks/useAxios.js @@ -5,7 +5,7 @@ const AxiosType = { EXTERNAL: 'External', } -export function useAxios() { +export function useAxios(lang = '') { const getInstances = (url) => { let type = AxiosType.INTERNAL url.startsWith('http') ? (type = AxiosType.EXTERNAL) : '' @@ -14,6 +14,7 @@ export function useAxios() { baseURL: type === AxiosType.INTERNAL ? process.env.NEXT_PUBLIC_API_SERVER_PATH : '', headers: { Accept: 'application/json', + lang, }, }) } diff --git a/src/hooks/useEvent.js b/src/hooks/useEvent.js index 715a27b0..f3b81115 100644 --- a/src/hooks/useEvent.js +++ b/src/hooks/useEvent.js @@ -1,6 +1,6 @@ import { useEffect, useRef } from 'react' -import { useRecoilValue } from 'recoil' -import { canvasState, currentMenuState } from '@/store/canvasAtom' +import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' +import { canvasState, canvasZoomState, currentMenuState } from '@/store/canvasAtom' import { fabric } from 'fabric' export function useEvent() { @@ -8,16 +8,12 @@ export function useEvent() { const currentMenu = useRecoilValue(currentMenuState) const keyboardEventListeners = useRef([]) const mouseEventListeners = useRef([]) + const setCanvasZoom = useSetRecoilState(canvasZoomState) useEffect(() => { if (!canvas) { return } - Object.keys(canvas.__eventListeners).forEach((key) => { - if (key.indexOf('mouse') > -1) { - canvas.off(key) - } - }) removeAllMouseEventListeners() removeAllDocumentEventListeners() addDefaultEvent() @@ -27,9 +23,30 @@ export function useEvent() { //default Event 추가 addCanvasMouseEventListener('mouse:move', defaultMouseMoveEvent) addCanvasMouseEventListener('mouse:out', defaultMouseOutEvent) + addCanvasMouseEventListener('mouse:wheel', wheelEvent) addDocumentEventListener('keydown', document, defaultKeyboardEvent) } + const wheelEvent = (opt) => { + const delta = opt.e.deltaY // 휠 이동 값 (양수면 축소, 음수면 확대) + let zoom = canvas.getZoom() // 현재 줌 값 + + zoom += delta > 0 ? -0.1 : 0.1 + + // 줌 값 제한 (최소 0.5배, 최대 5배) + if (zoom > 5) zoom = 5 + if (zoom < 0.5) zoom = 0.5 + + setCanvasZoom(Number((zoom * 100).toFixed(0))) + + // 마우스 위치 기준으로 확대/축소 + canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom) + + // 이벤트의 기본 동작 방지 (스크롤 방지) + opt.e.preventDefault() + opt.e.stopPropagation() + } + const defaultMouseOutEvent = (e) => { removeMouseLine() } @@ -38,7 +55,7 @@ export function useEvent() { removeMouseLine() // 가로선 const pointer = canvas.getPointer(e.e) - const horizontalLine = new fabric.Line([0, pointer.y, 2 * canvas.width, pointer.y], { + const horizontalLine = new fabric.Line([-1 * canvas.width, pointer.y, 2 * canvas.width, pointer.y], { stroke: 'red', strokeWidth: 1, selectable: false, @@ -46,7 +63,7 @@ export function useEvent() { }) // 세로선 - const verticalLine = new fabric.Line([pointer.x, 0, pointer.x, 2 * canvas.height], { + const verticalLine = new fabric.Line([pointer.x, -1 * canvas.height, pointer.x, 2 * canvas.height], { stroke: 'red', strokeWidth: 1, selectable: false, @@ -112,6 +129,7 @@ export function useEvent() { return { addDocumentEventListener, addCanvasMouseEventListener, + removeAllMouseEventListeners, removeAllDocumentEventListeners, } } diff --git a/src/hooks/useLine.js b/src/hooks/useLine.js index 81ebd1db..e5ebcb41 100644 --- a/src/hooks/useLine.js +++ b/src/hooks/useLine.js @@ -1,22 +1,35 @@ import { useRecoilValue } from 'recoil' -import { canvasState, fontSizeState } from '@/store/canvasAtom' +import { canvasState, fontFamilyState, fontSizeState } from '@/store/canvasAtom' export const useLine = () => { const canvas = useRecoilValue(canvasState) const fontSize = useRecoilValue(fontSizeState) + const fontFamily = useRecoilValue(fontFamilyState) - const addLineText = (line) => { + const addLine = (points = [], options) => { + const line = new fabric.Line(points, { + ...options, + selectable: options.selectable ?? false, + }) + + canvas?.add(line) + return line + } + + const addLineText = (line, length = getLengthByLine(line)) => { removeLineText(line) - const text = new fabric.Text(getLengthByLine(line).toFixed(0), { + const text = new fabric.Text(length.toFixed(0), { left: (line.x2 + line.x1) / 2, top: (line.y2 + line.y1) / 2, parent: line, name: 'lengthTxt', fontSize: fontSize, + fontFamily: fontFamily, }) canvas?.add(text) + return text } const removeLineText = (line) => { @@ -33,7 +46,7 @@ export const useLine = () => { const dx = x2 - x1 const dy = y2 - y1 - return Number(Math.sqrt(dx * dx + dy * dy).toFixed(0)) * 10 + return Number(Math.sqrt(dx * dx + dy * dy).toFixed(1)) * 10 } return { diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index 72354443..60db96b9 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -1,8 +1,24 @@ -import { canvasState } from '@/store/canvasAtom' +import { canvasState, fontFamilyState, fontSizeState } from '@/store/canvasAtom' import { useRecoilValue } from 'recoil' export const usePolygon = () => { const canvas = useRecoilValue(canvasState) + const fontSize = useRecoilValue(fontSizeState) + const fontFamily = useRecoilValue(fontFamilyState) - return {} + const addPolygon = (points, options) => { + const polygon = new fabric.Polygon(points, { + ...options, + selectable: options.selectable ?? false, + }) + + canvas?.add(polygon) + } + + const addPolygonByLines = (lines) => {} + + return { + addPolygon, + addPolygonByLines, + } } diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index 48dced68..2d9ef2dd 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -12,6 +12,11 @@ export const textState = atom({ default: 'test text', }) +export const canvasZoomState = atom({ + key: 'canvasZoomState', + default: 100, +}) + export const modeState = atom({ key: 'modeState', default: 'default', @@ -22,6 +27,11 @@ export const guideModeLineState = atom({ default: false, }) +export const fontFamilyState = atom({ + key: 'fontFamilyState', + default: 'Noto Sans KR', +}) + export const fontSizeState = atom({ key: 'fontSizeState', default: 16, @@ -185,3 +195,9 @@ export const currentMenuState = atom({ key: 'currentMenu', default: MENU.INITIAL_CANVAS_SETTING, }) + +// 수직 수평 모드 +export const verticalHorizontalModeState = atom({ + key: 'verticalHorizontalMode', + default: true, +}) diff --git a/src/store/settingAtom.js b/src/store/settingAtom.js index 26afc275..2e09ba2e 100644 --- a/src/store/settingAtom.js +++ b/src/store/settingAtom.js @@ -35,10 +35,10 @@ export const settingModalSecondOptionsState = atom({ { id: 4, name: 'modal.canvas.setting.font.plan.edit.circuit.num' }, ], option2: [ - { id: 1, name: 'modal.canvas.setting.font.plan.absorption.small', selected: false }, - { id: 2, name: 'modal.canvas.setting.font.plan.absorption.small.semi', selected: false }, - { id: 3, name: 'modal.canvas.setting.font.plan.absorption.medium', selected: false }, - { id: 4, name: 'modal.canvas.setting.font.plan.absorption.large', selected: false }, + { id: 1, column: 'adsorpRangeSmall', name: 'modal.canvas.setting.font.plan.absorption.small', selected: true }, + { id: 2, column: 'adsorpRangeSmallSemi', name: 'modal.canvas.setting.font.plan.absorption.small.semi', selected: false }, + { id: 3, column: 'adsorpRangeMedium', name: 'modal.canvas.setting.font.plan.absorption.medium', selected: false }, + { id: 4, column: 'adsorpRangeLarge', name: 'modal.canvas.setting.font.plan.absorption.large', selected: false }, ], }, dangerouslyAllowMutability: true,