Merge branch 'dev' into feature/test-jy

This commit is contained in:
Jaeyoung Lee 2024-10-02 11:13:17 +09:00
commit b1c4338a73
30 changed files with 2625 additions and 1252 deletions

View File

@ -53,8 +53,9 @@ export const Mode = {
export const LINE_TYPE = { export const LINE_TYPE = {
WALLLINE: { WALLLINE: {
/** /**
* 처마 / 캐라바 / / 팔작지붕 / 반절처 / 한쪽흐름 * 없음 / 처마 / 캐라바 / / 팔작지붕 / 반절처 / 한쪽흐름
*/ */
DEFAULT: 'default',
EAVES: 'eaves', EAVES: 'eaves',
GABLE: 'gable', GABLE: 'gable',
WALL: 'wall', WALL: 'wall',

View File

@ -3,9 +3,12 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue } from 'recoil'
import CanvasFrame from './CanvasFrame' import CanvasFrame from './CanvasFrame'
import { useMessage } from '@/hooks/useMessage'
import { useSwal } from '@/hooks/useSwal'
import { usePlan } from '@/hooks/usePlan' import { usePlan } from '@/hooks/usePlan'
import { globalLocaleStore } from '@/store/localeAtom' import { globalLocaleStore } from '@/store/localeAtom'
import { currentCanvasPlanState, initCanvasPlansState } from '@/store/canvasAtom' import { currentCanvasPlanState, initCanvasPlansState } from '@/store/canvasAtom'
import { sessionStore } from '@/store/commonAtom'
export default function CanvasLayout() { export default function CanvasLayout() {
const [objectNo, setObjectNo] = useState('test123240822001') // const [objectNo, setObjectNo] = useState('test123240822001') //
@ -14,8 +17,11 @@ export default function CanvasLayout() {
const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState) const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
const [initCanvasPlans, setInitCanvasPlans] = useRecoilState(initCanvasPlansState) const [initCanvasPlans, setInitCanvasPlans] = useRecoilState(initCanvasPlansState)
const globalLocaleState = useRecoilValue(globalLocaleStore) const globalLocaleState = useRecoilValue(globalLocaleStore)
const sessionState = useRecoilValue(sessionStore)
const { getCanvasByObjectNo } = usePlan() const { getMessage } = useMessage()
const { swalFire } = useSwal()
const { getCanvasByObjectNo, delCanvasById } = usePlan()
const handleCurrentPlan = (newCurrentId) => { const handleCurrentPlan = (newCurrentId) => {
if (!currentCanvasPlan?.id || currentCanvasPlan.id !== newCurrentId) { if (!currentCanvasPlan?.id || currentCanvasPlan.id !== newCurrentId) {
@ -38,21 +44,29 @@ export default function CanvasLayout() {
const handleDeletePlan = (e, id) => { const handleDeletePlan = (e, id) => {
e.stopPropagation() // e.stopPropagation() //
// if (initCanvasPlans.some((plan) => plan.id === id)) {
const filterInitPlans = initCanvasPlans.filter((plan) => plan.id !== id) delCanvasById(id)
setInitCanvasPlans(filterInitPlans) .then((res) => {
const filterAddPlans = addCanvasPlans.filter((plan) => plan.id !== id) swalFire({ text: getMessage('common.message.delete') })
setAddCanvasPlans(filterAddPlans) console.log('[DELETE] canvas-statuses res :::::::: %o', res)
setInitCanvasPlans((initCanvasPlans) => initCanvasPlans.filter((plan) => plan.id !== id))
const combinedPlans = [...filterInitPlans, ...filterAddPlans] })
if (combinedPlans.length === 0) { .catch((error) => {
// swalFire({ text: error.message, icon: 'error' })
setPlanNum(0) console.error('[DELETE] canvas-statuses res error :::::::: %o', error)
})
} else { } else {
const lastPlanId = combinedPlans.at(-1).id setAddCanvasPlans(addCanvasPlans.filter((plan) => plan.id !== id))
if (id !== lastPlanId) { swalFire({ text: getMessage('common.message.delete') })
handleCurrentPlan(lastPlanId)
} }
// last
const lastPlan = [...initCanvasPlans, ...addCanvasPlans].filter((plan) => plan.id !== id).at(-1)
if (!lastPlan) {
setPlanNum(0)
setCurrentCanvasPlan(null)
} else if (id !== lastPlan.id) {
handleCurrentPlan(lastPlan.id)
} }
} }
@ -63,7 +77,7 @@ export default function CanvasLayout() {
} }
useEffect(() => { useEffect(() => {
getCanvasByObjectNo(objectNo).then((res) => { getCanvasByObjectNo(sessionState.userId, objectNo).then((res) => {
console.log('canvas 목록 ', res) console.log('canvas 목록 ', res)
if (res.length > 0) { if (res.length > 0) {
setInitCanvasPlans(res) setInitCanvasPlans(res)
@ -82,7 +96,18 @@ export default function CanvasLayout() {
{[...initCanvasPlans, ...addCanvasPlans].map((plan) => ( {[...initCanvasPlans, ...addCanvasPlans].map((plan) => (
<button key={plan.id} className={`canvas-page-box ${plan.isCurrent === true ? 'on' : ''}`} onClick={() => handleCurrentPlan(plan.id)}> <button key={plan.id} className={`canvas-page-box ${plan.isCurrent === true ? 'on' : ''}`} onClick={() => handleCurrentPlan(plan.id)}>
<span>{plan.name}</span> <span>{plan.name}</span>
<i className="close" onClick={(e) => handleDeletePlan(e, plan.id)}></i> <i
className="close"
onClick={(e) =>
swalFire({
html: getMessage('common.message.confirm.delete') + `</br>${plan.name}`,
type: 'confirm',
confirmFn: () => {
handleDeletePlan(e, plan.id)
},
})
}
></i>
</button> </button>
))} ))}
</div> </div>

View File

@ -9,7 +9,8 @@ import QSelectBox from '@/components/common/select/QSelectBox'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { usePlan } from '@/hooks/usePlan' import { usePlan } from '@/hooks/usePlan'
import { canvasState, canvasZoomState, currentMenuState, verticalHorizontalModeState } from '@/store/canvasAtom' import { useSwal } from '@/hooks/useSwal'
import { canvasState, canvasZoomState, currentMenuState, currentCanvasPlanState, verticalHorizontalModeState } from '@/store/canvasAtom'
import { sessionStore } from '@/store/commonAtom' import { sessionStore } from '@/store/commonAtom'
import { outerLinePointsState } from '@/store/outerLineAtom' import { outerLinePointsState } from '@/store/outerLineAtom'
import { appMessageStore, globalLocaleStore } from '@/store/localeAtom' import { appMessageStore, globalLocaleStore } from '@/store/localeAtom'
@ -40,6 +41,7 @@ export default function CanvasMenu(props) {
const setCurrentMenu = useSetRecoilState(currentMenuState) const setCurrentMenu = useSetRecoilState(currentMenuState)
const setPoints = useSetRecoilState(outerLinePointsState) const setPoints = useSetRecoilState(outerLinePointsState)
const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState) const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState)
const [currentCanvasPlan, setcurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
const globalLocale = useRecoilValue(globalLocaleStore) const globalLocale = useRecoilValue(globalLocaleStore)
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
@ -47,6 +49,7 @@ export default function CanvasMenu(props) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { saveCanvas } = usePlan() const { saveCanvas } = usePlan()
const { swalFire } = useSwal()
const SelectOption = [{ name: '瓦53A' }, { name: '瓦53A' }] const SelectOption = [{ name: '瓦53A' }, { name: '瓦53A' }]
const onClickNav = (menu) => { const onClickNav = (menu) => {
@ -78,7 +81,13 @@ export default function CanvasMenu(props) {
// (btn08) // (btn08)
const handleSaveCanvas = () => { const handleSaveCanvas = () => {
swalFire({
html: getMessage('common.message.confirm.save') + `</br>${currentCanvasPlan.name}`,
type: 'confirm',
confirmFn: () => {
saveCanvas(sessionState.userId) saveCanvas(sessionState.userId)
},
})
} }
const handleClear = () => { const handleClear = () => {

View File

@ -11,10 +11,12 @@ import SettingModal01 from '@/components/floor-plan/modal/setting01/SettingModal
import CanvasLayout from '@/components/floor-plan/CanvasLayout' import CanvasLayout from '@/components/floor-plan/CanvasLayout'
import DotLineGrid from '@/components/floor-plan/modal/grid/DotLineGrid' import DotLineGrid from '@/components/floor-plan/modal/grid/DotLineGrid'
import WallLineSetting from '@/components/floor-plan/modal/outerlinesetting/WallLineSetting' import WallLineSetting from '@/components/floor-plan/modal/outerlinesetting/WallLineSetting'
import PropertiesSetting from '@/components/floor-plan/modal/outerlinesetting/PropertiesSetting'
export default function FloorPlan() { export default function FloorPlan() {
const [showCanvasSettingModal, setShowCanvasSettingModal] = useState(false) const [showCanvasSettingModal, setShowCanvasSettingModal] = useState(false)
const [showOutlineModal, setShowOutlineModal] = useState(false) const [showOutlineModal, setShowOutlineModal] = useState(false)
const [showPropertiesSettingModal, setShowPropertiesSettingModal] = useState(false)
const globalLocaleState = useRecoilValue(globalLocaleStore) const globalLocaleState = useRecoilValue(globalLocaleStore)
const { get } = useAxios(globalLocaleState) const { get } = useAxios(globalLocaleState)
@ -32,6 +34,7 @@ export default function FloorPlan() {
const outlineProps = { const outlineProps = {
setShowOutlineModal, setShowOutlineModal,
setShowPropertiesSettingModal,
} }
const modalProps = { const modalProps = {
@ -75,6 +78,10 @@ export default function FloorPlan() {
setShowDotLineGridModal, setShowDotLineGridModal,
} }
const propertiesSettingProps = {
setShowPropertiesSettingModal,
}
useEffect(() => {}, [showOutlineModal]) useEffect(() => {}, [showOutlineModal])
return ( return (
@ -87,6 +94,7 @@ export default function FloorPlan() {
{/*{showOutlineModal && <OuterLineWall {...outlineProps} />}*/} {/*{showOutlineModal && <OuterLineWall {...outlineProps} />}*/}
{showOutlineModal && <WallLineSetting {...outlineProps} />} {showOutlineModal && <WallLineSetting {...outlineProps} />}
{showDotLineGridModal && <DotLineGrid {...dotLineProps} />} {showDotLineGridModal && <DotLineGrid {...dotLineProps} />}
{showPropertiesSettingModal && <PropertiesSetting {...propertiesSettingProps} />}
</div> </div>
</div> </div>
</> </>

View File

@ -1,4 +1,4 @@
import WithDraggable from '@/components/common/draggable/withDraggable' import WithDraggable from '@/components/common/draggable/WithDraggable'
import QSelectBox from '@/components/common/select/QSelectBox' import QSelectBox from '@/components/common/select/QSelectBox'
import { useState } from 'react' import { useState } from 'react'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'

View File

@ -1,4 +1,4 @@
import WithDraggable from '@/components/common/draggable/withDraggable' import WithDraggable from '@/components/common/draggable/WithDraggable'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
export default function GridCopy(props) { export default function GridCopy(props) {

View File

@ -1,4 +1,4 @@
import WithDraggable from '@/components/common/draggable/withDraggable' import WithDraggable from '@/components/common/draggable/WithDraggable'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
export default function GridMove(props) { export default function GridMove(props) {

View File

@ -1,8 +1,11 @@
import Image from 'next/image' import Image from 'next/image'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { onlyNumberInputChange, onlyNumberWithDotInputChange } from '@/util/input-utils'
export default function Angle() { export default function Angle({ props }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { angle1, setAngle1, angle1Ref, length1, setLength1, length1Ref } = props
return ( return (
<> <>
<div className="outline-wrap"> <div className="outline-wrap">
@ -11,16 +14,40 @@ export default function Angle() {
<div className="outline-form"> <div className="outline-form">
<span className="mr10">{getMessage('modal.cover.outline.angle')}</span> <span className="mr10">{getMessage('modal.cover.outline.angle')}</span>
<div className="input-grid" style={{ width: '63px' }}> <div className="input-grid" style={{ width: '63px' }}>
<input type="text" className="input-origin block" defaultValue={4} /> <input
type="text"
className="input-origin block"
value={angle1}
ref={angle1Ref}
onChange={(e) => onlyNumberWithDotInputChange(e, setAngle1)}
placeholder="45"
/>
</div> </div>
<button className="reset-btn"></button> <button
className="reset-btn"
onClick={(e) => {
setAngle1(0)
}}
></button>
</div> </div>
<div className="outline-form"> <div className="outline-form">
<span className="mr10">{getMessage('modal.cover.outline.arrow')}</span> <span className="mr10">{getMessage('modal.cover.outline.length')}</span>
<div className="input-grid" style={{ width: '63px' }}> <div className="input-grid" style={{ width: '63px' }}>
<input type="text" className="input-origin block" defaultValue={5000} /> <input
type="text"
className="input-origin block"
value={length1}
ref={length1Ref}
onChange={(e) => onlyNumberInputChange(e, setLength1)}
placeholder="3000"
/>
</div> </div>
<button className="reset-btn"></button> <button
className="reset-btn"
onClick={() => {
setLength1(0)
}}
></button>
</div> </div>
</div> </div>
<div className="cul-box"> <div className="cul-box">

View File

@ -1,7 +1,24 @@
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { onlyNumberInputChange } from '@/util/input-utils'
export default function Diagonal() { export default function Diagonal({ props }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const {
length1,
setLength1,
length1Ref,
length2,
setLength2,
length2Ref,
outerLineDiagonalLength,
setOuterLineDiagonalLength,
outerLineDiagonalLengthRef,
arrow1,
setArrow1,
arrow2,
setArrow2,
} = props
return ( return (
<> <>
<div className="outline-wrap"> <div className="outline-wrap">
@ -13,26 +30,77 @@ export default function Diagonal() {
{getMessage('modal.cover.outline.length')} {getMessage('modal.cover.outline.length')}
</span> </span>
<div className="input-grid" style={{ width: '63px' }}> <div className="input-grid" style={{ width: '63px' }}>
<input type="text" className="input-origin block" defaultValue={1000} /> <input
type="text"
className="input-origin block"
value={outerLineDiagonalLength}
ref={outerLineDiagonalLengthRef}
onChange={(e) => onlyNumberInputChange(e, setOuterLineDiagonalLength)}
placeholder="3000"
/>
</div> </div>
<button className="reset-btn"></button> <button
className="reset-btn"
onClick={() => {
setOuterLineDiagonalLength(0)
}}
></button>
</div> </div>
</div> </div>
<div className="outline-inner"> <div className="outline-inner">
<div className="outline-form"> <div className="outline-form">
<span className="mr10"> {getMessage('modal.cover.outline.length')}</span> <span className="mr10"> {getMessage('modal.cover.outline.length')}</span>
<div className="input-grid" style={{ width: '63px' }}> <div className="input-grid" style={{ width: '63px' }}>
<input type="text" className="input-origin block" defaultValue={5000} /> <input
type="text"
className="input-origin block"
value={length1}
ref={length1Ref}
onChange={(e) => onlyNumberInputChange(e, setLength1)}
placeholder="3000"
/>
</div> </div>
<button className="reset-btn"></button> <button
className="reset-btn"
onClick={() => {
setLength1(0)
setLength2(0)
setArrow1('')
setArrow2('')
}}
></button>
</div> </div>
<div className="outline-form"> <div className="outline-form">
<span> {getMessage('modal.cover.outline.arrow')}</span> <span> {getMessage('modal.cover.outline.arrow')}</span>
<div className="grid-direction"> <div className="grid-direction">
<button className="direction up"></button> <button
<button className="direction down act"></button> className={`direction up ${arrow1 === '↑' ? 'act' : ''}`}
<button className="direction left"></button> onClick={() => {
<button className="direction right"></button> setArrow1('↑')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }))
}}
></button>
<button
className={`direction down ${arrow1 === '↓' ? 'act' : ''}`}
onClick={() => {
setArrow1('↓')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }))
}}
></button>
<button
className={`direction left ${arrow1 === '←' ? 'act' : ''}`}
onClick={() => {
setArrow1('←')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }))
}}
></button>
<button
className={`direction right ${arrow1 === '→' ? 'act' : ''}`}
onClick={() => {
setArrow1('→')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))
}}
></button>
</div> </div>
</div> </div>
</div> </div>
@ -40,16 +108,48 @@ export default function Diagonal() {
<div className="outline-form"> <div className="outline-form">
<span className="mr10"> {getMessage('modal.cover.outline.length')}</span> <span className="mr10"> {getMessage('modal.cover.outline.length')}</span>
<div className="input-grid" style={{ width: '98px' }}> <div className="input-grid" style={{ width: '98px' }}>
<input type="text" className="input-origin block" defaultValue={8000} /> <input
type="text"
className="input-origin block"
value={length2}
ref={length2Ref}
onChange={(e) => onlyNumberInputChange(e, setLength2)}
readOnly={true}
placeholder="3000"
/>
</div> </div>
</div> </div>
<div className="outline-form"> <div className="outline-form">
<span> {getMessage('modal.cover.outline.arrow')}</span> <span> {getMessage('modal.cover.outline.arrow')}</span>
<div className="grid-direction"> <div className="grid-direction">
<button className="direction up"></button> <button
<button className="direction down act"></button> className={`direction up ${arrow2 === '↑' ? 'act' : ''}`}
<button className="direction left"></button> onClick={() => {
<button className="direction right"></button> setArrow2('↑')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }))
}}
></button>
<button
className={`direction down ${arrow2 === '↓' ? 'act' : ''}`}
onClick={() => {
setArrow2('↓')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }))
}}
></button>
<button
className={`direction left ${arrow2 === '←' ? 'act' : ''}`}
onClick={() => {
setArrow2('←')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }))
}}
></button>
<button
className={`direction right ${arrow2 === '→' ? 'act' : ''}`}
onClick={() => {
setArrow2('→')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))
}}
></button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,7 +1,48 @@
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { onlyNumberInputChange, onlyNumberWithDotInputChange } from '@/util/input-utils'
import { getDegreeByChon } from '@/util/canvas-util'
export default function DoublePitch() { export default function DoublePitch({ props }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const {
angle1,
setAngle1,
angle1Ref,
angle2,
setAngle2,
angle2Ref,
length1,
setLength1,
length1Ref,
length2,
setLength2,
length2Ref,
arrow1,
setArrow1,
arrow2,
setArrow2,
arrow1Ref,
arrow2Ref,
} = props
const getLength2 = () => {
const angle1Value = angle1Ref.current.value
const angle2Value = angle2Ref.current.value
const length1Value = length1Ref.current.value
const arrow1Value = arrow1Ref.current
const arrow2Value = arrow2Ref.current
if (angle1Value !== 0 && length1Value !== 0 && angle2Value !== 0 && arrow1Value !== '') {
const radian1 = (getDegreeByChon(angle1Value) * Math.PI) / 180
const radian2 = (getDegreeByChon(angle2Value) * Math.PI) / 180
return Math.floor((Math.tan(radian1) * length1Value) / Math.tan(radian2))
}
return 0
}
return ( return (
<> <>
<div className="outline-wrap"> <div className="outline-wrap">
@ -9,26 +50,70 @@ export default function DoublePitch() {
<div className="outline-form"> <div className="outline-form">
<span className="mr10">{getMessage('modal.cover.outline.angle')}</span> <span className="mr10">{getMessage('modal.cover.outline.angle')}</span>
<div className="input-grid" style={{ width: '63px' }}> <div className="input-grid" style={{ width: '63px' }}>
<input type="text" className="input-origin block" defaultValue={4} /> <input
type="text"
className="input-origin block"
value={angle1}
ref={angle1Ref}
onChange={(e) => onlyNumberWithDotInputChange(e, setAngle1)}
placeholder="45"
/>
</div> </div>
<button className="reset-btn"></button> <button className="reset-btn" onClick={() => setAngle1(0)}></button>
</div> </div>
</div> </div>
<div className="outline-inner"> <div className="outline-inner">
<div className="outline-form"> <div className="outline-form">
<span className="mr10">{getMessage('modal.cover.outline.length')}</span> <span className="mr10">{getMessage('modal.cover.outline.length')}</span>
<div className="input-grid" style={{ width: '63px' }}> <div className="input-grid" style={{ width: '63px' }}>
<input type="text" className="input-origin block" defaultValue={5000} /> <input
type="text"
className="input-origin block"
value={length1}
ref={length1Ref}
onChange={(e) => onlyNumberInputChange(e, setLength1)}
placeholder="3000"
/>
</div> </div>
<button className="reset-btn"></button> <button
className="reset-btn"
onClick={() => {
setLength1(0)
setArrow1('')
}}
></button>
</div> </div>
<div className="outline-form"> <div className="outline-form">
<span>{getMessage('modal.cover.outline.arrow')}</span> <span>{getMessage('modal.cover.outline.arrow')}</span>
<div className="grid-direction"> <div className="grid-direction">
<button className="direction up"></button> <button
<button className="direction down act"></button> className={`direction up ${arrow1 === '↑' ? 'act' : ''}`}
<button className="direction left"></button> onClick={() => {
<button className="direction right"></button> setArrow1('↑')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }))
}}
></button>
<button
className={`direction down ${arrow1 === '↓' ? 'act' : ''}`}
onClick={() => {
setArrow1('↓')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }))
}}
></button>
<button
className={`direction left ${arrow1 === '←' ? 'act' : ''}`}
onClick={() => {
setArrow1('←')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }))
}}
></button>
<button
className={`direction right ${arrow1 === '→' ? 'act' : ''}`}
onClick={() => {
setArrow1('→')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))
}}
></button>
</div> </div>
</div> </div>
</div> </div>
@ -38,26 +123,80 @@ export default function DoublePitch() {
<div className="outline-form"> <div className="outline-form">
<span className="mr10">{getMessage('modal.cover.outline.angle')}</span> <span className="mr10">{getMessage('modal.cover.outline.angle')}</span>
<div className="input-grid" style={{ width: '63px' }}> <div className="input-grid" style={{ width: '63px' }}>
<input type="text" className="input-origin block" defaultValue={6} /> <input
type="text"
className="input-origin block"
value={angle2}
ref={angle2Ref}
onChange={(e) => {
onlyNumberWithDotInputChange(e, setAngle2)
console.log(getLength2())
setLength2(getLength2())
}}
placeholder="45"
/>
</div> </div>
<button className="reset-btn"></button> <button
className="reset-btn"
onClick={() => {
setAngle2(0)
}}
></button>
</div> </div>
</div> </div>
<div className="outline-inner"> <div className="outline-inner">
<div className="outline-form"> <div className="outline-form">
<span className="mr10">{getMessage('modal.cover.outline.length')}</span> <span className="mr10">{getMessage('modal.cover.outline.length')}</span>
<div className="input-grid" style={{ width: '63px' }}> <div className="input-grid" style={{ width: '63px' }}>
<input type="text" className="input-origin block" defaultValue={3000} /> <input
type="text"
className="input-origin block"
value={length2}
ref={length2Ref}
onChange={(e) => onlyNumberInputChange(e, setLength2)}
readOnly={true}
placeholder="3000"
/>
</div> </div>
<button className="reset-btn"></button> <button
className="reset-btn"
onClick={() => {
setLength2(0)
setArrow2('')
}}
></button>
</div> </div>
<div className="outline-form"> <div className="outline-form">
<span>{getMessage('modal.cover.outline.arrow')}</span> <span>{getMessage('modal.cover.outline.arrow')}</span>
<div className="grid-direction"> <div className="grid-direction">
<button className="direction up"></button> <button
<button className="direction down act"></button> className={`direction up ${arrow2 === '↑' ? 'act' : ''}`}
<button className="direction left"></button> onClick={() => {
<button className="direction right"></button> setArrow2('↑')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }))
}}
></button>
<button
className={`direction down ${arrow2 === '↓' ? 'act' : ''}`}
onClick={() => {
setArrow2('↓')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }))
}}
></button>
<button
className={`direction left ${arrow2 === '←' ? 'act' : ''}`}
onClick={() => {
setArrow2('←')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }))
}}
></button>
<button
className={`direction right ${arrow2 === '→' ? 'act' : ''}`}
onClick={() => {
setArrow2('→')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))
}}
></button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,12 +1,12 @@
'use client' 'use client'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { useOuterLineWall } from '@/hooks/roofcover/useOuterLineWall'
import { onlyNumberInputChange } from '@/util/input-utils' import { onlyNumberInputChange } from '@/util/input-utils'
export default function OuterLineWall(props) { export default function OuterLineWall({ props }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { length1, setLength1, length1Ref, arrow1, setArrow1 } = useOuterLineWall()
const { length1, setLength1, length1Ref, arrow1, setArrow1 } = props
return ( return (
<div className="outline-wrap"> <div className="outline-wrap">
<div className="outline-inner"> <div className="outline-inner">
@ -22,15 +22,39 @@ export default function OuterLineWall(props) {
placeholder="3000" placeholder="3000"
/> />
</div> </div>
<button className="reset-btn"></button> <button className="reset-btn" onClick={() => setLength1(0)}></button>
</div> </div>
<div className="outline-form"> <div className="outline-form">
<span>{getMessage('modal.cover.outline.arrow')}</span> <span>{getMessage('modal.cover.outline.arrow')}</span>
<div className="grid-direction"> <div className="grid-direction">
<button className={`direction up ${arrow1 === '↑' ? 'act' : ''}`} onClick={() => setArrow1('↑')}></button> <button
<button className={`direction down ${arrow1 === '↓' ? 'act' : ''}`} onClick={() => setArrow1('↓')}></button> className={`direction up ${arrow1 === '↑' ? 'act' : ''}`}
<button className={`direction left ${arrow1 === '←' ? 'act' : ''}`} onClick={() => setArrow1('←')}></button> onClick={() => {
<button className={`direction right ${arrow1 === '→' ? 'act' : ''}`} onClick={() => setArrow1('→')}></button> setArrow1('↑')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }))
}}
></button>
<button
className={`direction down ${arrow1 === '↓' ? 'act' : ''}`}
onClick={() => {
setArrow1('↓')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }))
}}
></button>
<button
className={`direction left ${arrow1 === '←' ? 'act' : ''}`}
onClick={() => {
setArrow1('←')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }))
}}
></button>
<button
className={`direction right ${arrow1 === '→' ? 'act' : ''}`}
onClick={() => {
setArrow1('→')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))
}}
></button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,56 @@
import WithDraggable from '@/components/common/draggable/WithDraggable'
import { useMessage } from '@/hooks/useMessage'
import { usePropertiesSetting } from '@/hooks/roofcover/usePropertiesSetting'
export default function PropertiesSetting(props) {
const { getMessage } = useMessage()
const { setShowPropertiesSettingModal } = props
const { handleSetEaves, handleSetGable, handleRollback, handleFix, closeModal } = usePropertiesSetting()
return (
<WithDraggable isShow={true}>
<div className={`modal-pop-wrap ssm`}>
<div className="modal-head">
<h1 className="title">{getMessage('modal.canvas.setting.wallline.properties.setting')}</h1>
<button
className="modal-close"
onClick={() => {
closeModal(setShowPropertiesSettingModal)
}}
>
닫기
</button>
</div>
<div className="modal-body">
<div className="properties-guide">{getMessage('modal.canvas.setting.wallline.properties.setting.info')}</div>
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('setting')}</div>
<div className="setting-btn-wrap">
<button className="setting-btn green mr5" onClick={handleSetEaves}>
{getMessage('modal.canvas.setting.wallline.properties.setting.eaves')}
</button>
<button className="setting-btn blue" onClick={handleSetGable}>
{getMessage('modal.canvas.setting.wallline.properties.setting.edge')}
</button>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={handleRollback}>
{getMessage('modal.cover.outline.rollback')}
</button>
<button
className="btn-frame modal act"
onClick={() => {
handleFix()
setShowPropertiesSettingModal(false)
}}
>
{getMessage('modal.cover.outline.finish')}
</button>
</div>
</div>
</div>
</WithDraggable>
)
}

View File

@ -1,24 +1,63 @@
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { onlyNumberInputChange } from '@/util/input-utils'
export default function RightAngle() { export default function RightAngle({ props }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { length1, setLength1, length1Ref, length2, setLength2, length2Ref, arrow1, setArrow1, arrow2, setArrow2 } = props
return ( return (
<div className="outline-wrap"> <div className="outline-wrap">
<div className="outline-inner"> <div className="outline-inner">
<div className="outline-form"> <div className="outline-form">
<span className="mr10">{getMessage('modal.cover.outline.length')}</span> <span className="mr10">{getMessage('modal.cover.outline.length')}</span>
<div className="input-grid" style={{ width: '63px' }}> <div className="input-grid" style={{ width: '63px' }}>
<input type="text" className="input-origin block" defaultValue={1000} /> <input
type="text"
className="input-origin block"
value={length1}
ref={length1Ref}
onChange={(e) => onlyNumberInputChange(e, setLength1)}
placeholder="3000"
/>
</div> </div>
<button className="reset-btn"></button> <button
className="reset-btn"
onClick={() => {
setLength1(0)
setArrow1('')
}}
></button>
</div> </div>
<div className="outline-form"> <div className="outline-form">
<span>{getMessage('modal.cover.outline.arrow')}</span> <span>{getMessage('modal.cover.outline.arrow')}</span>
<div className="grid-direction"> <div className="grid-direction">
<button className="direction up"></button> <button
<button className="direction down act"></button> className={`direction up ${arrow1 === '↑' ? 'act' : ''}`}
<button className="direction left"></button> onClick={() => {
<button className="direction right"></button> setArrow1('↑')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }))
}}
></button>
<button
className={`direction down ${arrow1 === '↓' ? 'act' : ''}`}
onClick={() => {
setArrow1('↓')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }))
}}
></button>
<button
className={`direction left ${arrow1 === '←' ? 'act' : ''}`}
onClick={() => {
setArrow1('←')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }))
}}
></button>
<button
className={`direction right ${arrow1 === '→' ? 'act' : ''}`}
onClick={() => {
setArrow1('→')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))
}}
></button>
</div> </div>
</div> </div>
</div> </div>
@ -26,17 +65,53 @@ export default function RightAngle() {
<div className="outline-form"> <div className="outline-form">
<span className="mr10">{getMessage('modal.cover.outline.length')}</span> <span className="mr10">{getMessage('modal.cover.outline.length')}</span>
<div className="input-grid" style={{ width: '63px' }}> <div className="input-grid" style={{ width: '63px' }}>
<input type="text" className="input-origin block" defaultValue={1000} /> <input
type="text"
className="input-origin block"
value={length2}
ref={length2Ref}
onChange={(e) => onlyNumberInputChange(e, setLength2)}
placeholder="3000"
/>
</div> </div>
<button className="reset-btn"></button> <button
className="reset-btn"
onClick={() => {
setLength2(0)
}}
></button>
</div> </div>
<div className="outline-form"> <div className="outline-form">
<span>{getMessage('modal.cover.outline.arrow')}</span> <span>{getMessage('modal.cover.outline.arrow')}</span>
<div className="grid-direction"> <div className="grid-direction">
<button className="direction up"></button> <button
<button className="direction down act"></button> className={`direction up ${arrow2 === '↑' ? 'act' : ''}`}
<button className="direction left"></button> onClick={() => {
<button className="direction right"></button> setArrow2('↑')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }))
}}
></button>
<button
className={`direction down ${arrow2 === '↓' ? 'act' : ''}`}
onClick={() => {
setArrow2('↓')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }))
}}
></button>
<button
className={`direction left ${arrow2 === '←' ? 'act' : ''}`}
onClick={() => {
setArrow2('←')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }))
}}
></button>
<button
className={`direction right ${arrow2 === '→' ? 'act' : ''}`}
onClick={() => {
setArrow2('→')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))
}}
></button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,6 +1,6 @@
'use client' 'use client'
import WithDraggable from '@/components/common/draggable/withDraggable' import WithDraggable from '@/components/common/draggable/WithDraggable'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { OUTER_LINE_TYPE } from '@/store/outerLineAtom' import { OUTER_LINE_TYPE } from '@/store/outerLineAtom'
import { useOuterLineWall } from '@/hooks/roofcover/useOuterLineWall' import { useOuterLineWall } from '@/hooks/roofcover/useOuterLineWall'
@ -11,9 +11,102 @@ import DoublePitch from '@/components/floor-plan/modal/outerlinesetting/DoublePi
import Diagonal from '@/components/floor-plan/modal/outerlinesetting/Diagonal' import Diagonal from '@/components/floor-plan/modal/outerlinesetting/Diagonal'
export default function WallLineSetting(props) { export default function WallLineSetting(props) {
const { setShowOutlineModal } = props const { setShowOutlineModal, setShowPropertiesSettingModal } = props
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { type, setType, handleFix, handleRollback } = useOuterLineWall() const {
length1,
setLength1,
length2,
setLength2,
length1Ref,
length2Ref,
arrow1,
setArrow1,
arrow2,
setArrow2,
angle1,
setAngle1,
angle1Ref,
angle2,
setAngle2,
angle2Ref,
type,
setType,
arrow1Ref,
arrow2Ref,
outerLineDiagonalLength,
setOuterLineDiagonalLength,
outerLineDiagonalLengthRef,
handleRollback,
handleFix,
} = useOuterLineWall()
const outerLineProps = {
length1,
setLength1,
length1Ref,
arrow1,
setArrow1,
}
const rightAngleProps = {
length1,
setLength1,
length1Ref,
length2,
setLength2,
length2Ref,
arrow1,
setArrow1,
arrow2,
setArrow2,
}
const doublePitchProps = {
angle1,
setAngle1,
angle1Ref,
angle2,
setAngle2,
angle2Ref,
length1,
setLength1,
length1Ref,
length2,
setLength2,
length2Ref,
arrow1,
setArrow1,
arrow2,
setArrow2,
arrow1Ref,
arrow2Ref,
}
const angleProps = {
angle1,
setAngle1,
angle1Ref,
length1,
setLength1,
length1Ref,
}
const diagonalLineProps = {
length1,
setLength1,
length1Ref,
length2,
setLength2,
length2Ref,
outerLineDiagonalLength,
setOuterLineDiagonalLength,
outerLineDiagonalLengthRef,
arrow1,
setArrow1,
arrow2,
setArrow2,
}
return ( return (
<WithDraggable isShow={true} pos={{ x: -1390, y: 30 }}> <WithDraggable isShow={true} pos={{ x: -1390, y: 30 }}>
@ -55,24 +148,33 @@ export default function WallLineSetting(props) {
{getMessage('modal.cover.outline.diagonal')} {getMessage('modal.cover.outline.diagonal')}
</button> </button>
</div> </div>
<div className="properties-setting-wrap outer">
<div className="setting-tit">{getMessage('modal.cover.outline.setting')}</div>
{type === OUTER_LINE_TYPE.OUTER_LINE ? ( {type === OUTER_LINE_TYPE.OUTER_LINE ? (
<OuterLineWall /> <OuterLineWall props={outerLineProps} />
) : type === OUTER_LINE_TYPE.RIGHT_ANGLE ? ( ) : type === OUTER_LINE_TYPE.RIGHT_ANGLE ? (
<RightAngle /> <RightAngle props={rightAngleProps} />
) : type === OUTER_LINE_TYPE.DOUBLE_PITCH ? ( ) : type === OUTER_LINE_TYPE.DOUBLE_PITCH ? (
<DoublePitch /> <DoublePitch props={doublePitchProps} />
) : type === OUTER_LINE_TYPE.ANGLE ? ( ) : type === OUTER_LINE_TYPE.ANGLE ? (
<Angle /> <Angle props={angleProps} />
) : type === OUTER_LINE_TYPE.DIAGONAL_LINE ? ( ) : type === OUTER_LINE_TYPE.DIAGONAL_LINE ? (
<Diagonal /> <Diagonal props={diagonalLineProps} />
) : ( ) : (
<></> <></>
)} )}
</div>
<div className="grid-btn-wrap"> <div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={handleRollback}> <button className="btn-frame modal mr5" onClick={handleRollback}>
{getMessage('modal.cover.outline.rollback')} {getMessage('modal.cover.outline.rollback')}
</button> </button>
<button className="btn-frame modal act" onClick={handleFix}> <button
className="btn-frame modal act"
onClick={() => {
handleFix(setShowOutlineModal)
setShowPropertiesSettingModal(true)
}}
>
{getMessage('modal.cover.outline.fix')} {getMessage('modal.cover.outline.fix')}
</button> </button>
</div> </div>

View File

@ -2,7 +2,7 @@
import { useState } from 'react' import { useState } from 'react'
import FirstOption from './FirstOption' import FirstOption from './FirstOption'
import WithDraggable from '@/components/common/draggable/withDraggable' import WithDraggable from '@/components/common/draggable/WithDraggable'
import SecondOption from '@/components/floor-plan/modal/setting01/SecondOption' import SecondOption from '@/components/floor-plan/modal/setting01/SecondOption'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import GridOption from '@/components/floor-plan/modal/setting01/GridOption' import GridOption from '@/components/floor-plan/modal/setting01/GridOption'

View File

@ -1,5 +1,5 @@
import { useEffect, useRef } from 'react' import { useEffect, useRef } from 'react'
import { distanceBetweenPoints } from '@/util/canvas-util' import { distanceBetweenPoints, getDegreeByChon } from '@/util/canvas-util'
import { useRecoilState, useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue } from 'recoil'
import { import {
adsorptionPointAddModeState, adsorptionPointAddModeState,
@ -16,14 +16,17 @@ import { useTempGrid } from '@/hooks/useTempGrid'
import { usePolygon } from '@/hooks/usePolygon' import { usePolygon } from '@/hooks/usePolygon'
import { import {
outerLineAngle1State, outerLineAngle1State,
outerLineAngle2State,
outerLineArrow1State, outerLineArrow1State,
outerLineArrow2State, outerLineArrow2State,
outerLineDiagonalState,
outerLineLength1State, outerLineLength1State,
outerLineLength2State, outerLineLength2State,
outerLinePointsState, outerLinePointsState,
outerLineTypeState, outerLineTypeState,
} from '@/store/outerLineAtom' } from '@/store/outerLineAtom'
import { calculateAngle } from '@/util/qpolygon-utils' import { calculateAngle } from '@/util/qpolygon-utils'
import { fabric } from 'fabric'
export function useOuterLineWall() { export function useOuterLineWall() {
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
@ -33,6 +36,7 @@ export function useOuterLineWall() {
const { addLine, removeLine } = useLine() const { addLine, removeLine } = useLine()
const { tempGridMode } = useTempGrid() const { tempGridMode } = useTempGrid()
const { addPolygonByLines } = usePolygon() const { addPolygonByLines } = usePolygon()
const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState) const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState)
const adsorptionPointAddMode = useRecoilValue(adsorptionPointAddModeState) const adsorptionPointAddMode = useRecoilValue(adsorptionPointAddModeState)
const adsorptionPointMode = useRecoilValue(adsorptionPointModeState) const adsorptionPointMode = useRecoilValue(adsorptionPointModeState)
@ -42,28 +46,31 @@ export function useOuterLineWall() {
const length1Ref = useRef(null) const length1Ref = useRef(null)
const length2Ref = useRef(null) const length2Ref = useRef(null)
const angle1Ref = useRef(null) const angle1Ref = useRef(null)
const angle2Ref = useRef(null)
const [length1, setLength1] = useRecoilState(outerLineLength1State) const [length1, setLength1] = useRecoilState(outerLineLength1State)
const [length2, setLength2] = useRecoilState(outerLineLength2State) const [length2, setLength2] = useRecoilState(outerLineLength2State)
const [arrow1, setArrow1] = useRecoilState(outerLineArrow1State) const [arrow1, setArrow1] = useRecoilState(outerLineArrow1State)
const [arrow2, setArrow2] = useRecoilState(outerLineArrow2State) const [arrow2, setArrow2] = useRecoilState(outerLineArrow2State)
const [points, setPoints] = useRecoilState(outerLinePointsState) const [points, setPoints] = useRecoilState(outerLinePointsState)
const [type, setType] = useRecoilState(outerLineTypeState) const [type, setType] = useRecoilState(outerLineTypeState)
const [angle1, setAngle1] = useRecoilState(outerLineAngle1State)
const [angle2, setAngle2] = useRecoilState(outerLineAngle2State)
const [outerLineDiagonalLength, setOuterLineDiagonalLength] = useRecoilState(outerLineDiagonalState)
const arrow1Ref = useRef(arrow1) const arrow1Ref = useRef(arrow1)
const arrow2Ref = useRef(arrow2) const arrow2Ref = useRef(arrow2)
const outerLineDiagonalLengthRef = useRef(null)
const isFix = useRef(false) const isFix = useRef(false)
const [angle1, setAngle1] = useRecoilState(outerLineAngle1State) const closeModalFn = useRef(null)
useEffect(() => { useEffect(() => {
if (adsorptionPointAddMode || tempGridMode) { if (adsorptionPointAddMode || tempGridMode) {
return return
} }
removeMouseEvent('mouse:down', mouseDown)
addCanvasMouseEventListener('mouse:down', mouseDown) addCanvasMouseEventListener('mouse:down', mouseDown)
clear() clear()
return () => {
removeAllMouseEventListeners()
}
}, [verticalHorizontalMode, points, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, interval, tempGridMode]) }, [verticalHorizontalMode, points, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, interval, tempGridMode])
useEffect(() => { useEffect(() => {
@ -75,9 +82,8 @@ export function useOuterLineWall() {
}, [arrow2]) }, [arrow2])
useEffect(() => { useEffect(() => {
removeAllDocumentEventListeners()
addDocumentEventListener('keydown', document, keydown[type])
clear() clear()
addDocumentEventListener('keydown', document, keydown[type])
}, [type]) }, [type])
const clear = () => { const clear = () => {
@ -88,6 +94,9 @@ export function useOuterLineWall() {
setArrow2('') setArrow2('')
setAngle1(0) setAngle1(0)
setAngle2(0)
setOuterLineDiagonalLength(0)
} }
const mouseDown = (e) => { const mouseDown = (e) => {
@ -143,14 +152,13 @@ export function useOuterLineWall() {
canvas?.remove(canvas?.getObjects().find((obj) => obj.name === 'startPoint')) canvas?.remove(canvas?.getObjects().find((obj) => obj.name === 'startPoint'))
// point가 변경 될때마다 이벤트 리스너를 제거하고 다시 등록
removeAllDocumentEventListeners()
addDocumentEventListener('keydown', document, keydown[type])
if (points.length === 0) { if (points.length === 0) {
removeAllDocumentEventListeners()
return return
} }
addDocumentEventListener('keydown', document, keydown[type])
if (points.length === 1) { if (points.length === 1) {
const point = new fabric.Circle({ const point = new fabric.Circle({
radius: 5, radius: 5,
@ -174,6 +182,13 @@ export function useOuterLineWall() {
const lastPoint = points[points.length - 1] const lastPoint = points[points.length - 1]
const firstPoint = points[0] const firstPoint = points[0]
if (isFix.current) {
canvas?.renderAll()
closeModalFn.current(false)
removeAllMouseEventListeners()
removeAllDocumentEventListeners()
}
if (points.length < 3) { if (points.length < 3) {
return return
} }
@ -241,7 +256,7 @@ export function useOuterLineWall() {
stroke: 'black', stroke: 'black',
strokeWidth: 3, strokeWidth: 3,
idx: idx, idx: idx,
selectable: false, selectable: true,
name: 'outerLine', name: 'outerLine',
}) })
} }
@ -261,7 +276,26 @@ export function useOuterLineWall() {
} }
// 직각 완료될 경우 확인 // 직각 완료될 경우 확인
const checkRightAngle = () => { const checkRightAngle = (direction) => {
const activeElem = document.activeElement
const canDirection =
direction === '↓' || direction === '↑'
? arrow1Ref.current === '←' || arrow1Ref.current === '→'
: arrow1Ref.current === '↓' || arrow1Ref.current === '↑'
if (activeElem === length1Ref.current || activeElem === angle1Ref.current) {
setArrow1(direction)
arrow1Ref.current = direction
length2Ref.current.focus()
} else if (activeElem === length2Ref.current || activeElem === angle2Ref.current) {
if (!canDirection) {
return
}
setArrow2(direction)
arrow2Ref.current = direction
}
const length1Num = Number(length1Ref.current.value) / 10 const length1Num = Number(length1Ref.current.value) / 10
const length2Num = Number(length2Ref.current.value) / 10 const length2Num = Number(length2Ref.current.value) / 10
@ -332,6 +366,191 @@ export function useOuterLineWall() {
} }
} }
//이구배 완료될 경우 확인 ↓, ↑, ←, →
const checkDoublePitch = (direction) => {
const activeElem = document.activeElement
const canDirection =
direction === '↓' || direction === '↑'
? arrow1Ref.current === '←' || arrow1Ref.current === '→'
: arrow1Ref.current === '↓' || arrow1Ref.current === '↑'
if (activeElem === length1Ref.current || activeElem === angle1Ref.current) {
setArrow1(direction)
arrow1Ref.current = direction
angle2Ref.current.focus()
} else if (activeElem === length2Ref.current || activeElem === angle2Ref.current) {
if (!canDirection) {
return
}
setArrow2(direction)
arrow2Ref.current = direction
}
const angle1Value = angle1Ref.current.value
const angle2Value = angle2Ref.current.value
const length1Value = length1Ref.current.value
const length2Value = length2Ref.current.value
const arrow1Value = arrow1Ref.current
const arrow2Value = arrow2Ref.current
if (angle1Value !== 0 && length1Value !== 0 && angle2Value !== 0 && arrow1Value !== '' && arrow2Value !== '') {
if (arrow1Value === '↓' && arrow2Value === '→') {
setPoints((prev) => {
if (prev.length === 0) {
return []
}
return [...prev, { x: prev[prev.length - 1].x + length1Value / 10, y: prev[prev.length - 1].y + length2Value / 10 }]
})
} else if (arrow1Value === '↓' && arrow2Value === '←') {
setPoints((prev) => {
if (prev.length === 0) {
return []
}
return [...prev, { x: prev[prev.length - 1].x - length1Value / 10, y: prev[prev.length - 1].y + length2Value / 10 }]
})
} else if (arrow1Value === '↑' && arrow2Value === '→') {
setPoints((prev) => {
if (prev.length === 0) {
return []
}
return [...prev, { x: prev[prev.length - 1].x + length1Value / 10, y: prev[prev.length - 1].y - length2Value / 10 }]
})
} else if (arrow1Value === '↑' && arrow2Value === '←') {
setPoints((prev) => {
if (prev.length === 0) {
return []
}
return [...prev, { x: prev[prev.length - 1].x - length1Value / 10, y: prev[prev.length - 1].y - length2Value / 10 }]
})
} else if (arrow1Value === '→' && arrow2Value === '↓') {
setPoints((prev) => {
if (prev.length === 0) {
return []
}
return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }]
})
} else if (arrow1Value === '→' && arrow2Value === '↑') {
setPoints((prev) => {
if (prev.length === 0) {
return []
}
return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }]
})
} else if (arrow1Value === '←' && arrow2Value === '↓') {
setPoints((prev) => {
if (prev.length === 0) {
return []
}
return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }]
})
} else if (arrow1Value === '←' && arrow2Value === '↑') {
setPoints((prev) => {
if (prev.length === 0) {
return []
}
return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }]
})
}
angle1Ref.current.focus()
}
}
//대각선 완료될 경우 확인
const checkDiagonal = (direction) => {
const activeElem = document.activeElement
const canDirection =
direction === '↓' || direction === '↑'
? arrow1Ref.current === '←' || arrow1Ref.current === '→'
: arrow1Ref.current === '↓' || arrow1Ref.current === '↑'
if (activeElem === length1Ref.current) {
setArrow1(direction)
arrow1Ref.current = direction
} else if (activeElem === length2Ref.current || activeElem === angle2Ref.current) {
if (!canDirection) {
return
}
setArrow2(direction)
arrow2Ref.current = direction
}
const diagonalLength = outerLineDiagonalLengthRef.current.value // 대각선 길이
const length1Value = length1Ref.current.value
const arrow1Value = arrow1Ref.current
const arrow2Value = arrow2Ref.current
const getLength2 = () => {
return Math.floor(Math.sqrt(diagonalLength ** 2 - length1Value ** 2))
}
const length2Value = getLength2()
console.log(length2Value)
if (diagonalLength !== 0 && length1Value !== 0 && arrow1Value !== '') {
setLength2(getLength2())
length2Ref.current.focus()
}
if (length1Value !== 0 && length2Value !== 0 && arrow1Value !== '' && arrow2Value !== '') {
if (arrow1Value === '↓' && arrow2Value === '→') {
setPoints((prev) => {
if (prev.length === 0) {
return []
}
return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }]
})
} else if (arrow1Value === '↓' && arrow2Value === '←') {
setPoints((prev) => {
if (prev.length === 0) {
return []
}
return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }]
})
} else if (arrow1Value === '↑' && arrow2Value === '→') {
setPoints((prev) => {
if (prev.length === 0) {
return []
}
return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }]
})
} else if (arrow1Value === '↑' && arrow2Value === '←') {
setPoints((prev) => {
if (prev.length === 0) {
return []
}
return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }]
})
} else if (arrow1Value === '→' && arrow2Value === '↓') {
setPoints((prev) => {
if (prev.length === 0) {
return []
}
return [...prev, { x: prev[prev.length - 1].x + length1Value / 10, y: prev[prev.length - 1].y + length2Value / 10 }]
})
} else if (arrow1Value === '→' && arrow2Value === '↑') {
setPoints((prev) => {
if (prev.length === 0) {
return []
}
return [
...prev,
{
x: prev[prev.length - 1].x + length1Value / 10,
y: prev[prev.length - 1].y - length2Value / 10,
},
]
})
}
}
}
const keydown = { const keydown = {
outerLine: (e) => { outerLine: (e) => {
if (points.length === 0) { if (points.length === 0) {
@ -411,75 +630,52 @@ export function useOuterLineWall() {
switch (key) { switch (key) {
case 'Down': // IE/Edge에서 사용되는 값 case 'Down': // IE/Edge에서 사용되는 값
case 'ArrowDown': { case 'ArrowDown': {
if (activeElem === length1Ref.current) { checkRightAngle('↓')
setArrow1('↓')
arrow1Ref.current = '↓'
length2Ref.current.focus()
} else if (activeElem === length2Ref.current) {
if (arrow1Ref.current === '↓' || arrow1Ref.current === '↑') {
break
}
setArrow2('↓')
arrow2Ref.current = '↓'
checkRightAngle()
}
break break
} }
case 'Up': // IE/Edge에서 사용되는 값 case 'Up': // IE/Edge에서 사용되는 값
case 'ArrowUp': case 'ArrowUp':
if (activeElem === length1Ref.current) { checkRightAngle('↑')
setArrow1('↑')
arrow1Ref.current = '↑'
length2Ref.current.focus()
} else if (activeElem === length2Ref.current) {
if (arrow1Ref.current === '↓' || arrow1Ref.current === '↑') {
break
}
setArrow2('↑')
arrow2Ref.current = '↑'
checkRightAngle()
}
break break
case 'Left': // IE/Edge에서 사용되는 값 case 'Left': // IE/Edge에서 사용되는 값
case 'ArrowLeft': case 'ArrowLeft':
if (activeElem === length1Ref.current) { checkRightAngle('←')
setArrow1('←')
arrow1Ref.current = '←'
length2Ref.current.focus()
} else if (activeElem === length2Ref.current) {
if (arrow1Ref.current === '←' || arrow1Ref.current === '→') {
break
}
setArrow2('←')
arrow2Ref.current = '←'
checkRightAngle()
}
break break
case 'Right': // IE/Edge에서 사용되는 값 case 'Right': // IE/Edge에서 사용되는 값
case 'ArrowRight': case 'ArrowRight':
if (activeElem === length1Ref.current) { checkRightAngle('→')
setArrow1('→')
arrow1Ref.current = '→'
length2Ref.current.focus()
} else if (activeElem === length2Ref.current) {
if (arrow1Ref.current === '←' || arrow1Ref.current === '→') {
break
}
setArrow2('→')
arrow2Ref.current = '→'
checkRightAngle()
}
break break
} }
}, },
leeGubae: (e) => { doublePitch: (e) => {
console.log('leegubae') if (points.length === 0) {
return
}
const key = e.key
switch (key) {
case 'Down': // IE/Edge에서 사용되는 값
case 'ArrowDown': {
checkDoublePitch('↓')
break
}
case 'Up': // IE/Edge에서 사용되는 값
case 'ArrowUp':
checkDoublePitch('↑')
break
case 'Left': // IE/Edge에서 사용되는 값
case 'ArrowLeft':
checkDoublePitch('←')
break
case 'Right': // IE/Edge에서 사용되는 값
case 'ArrowRight':
checkDoublePitch('→')
break
}
}, },
angle: (e) => { angle: (e) => {
if (points.length === 0) {
return
}
const key = e.key const key = e.key
switch (key) { switch (key) {
case 'Enter': { case 'Enter': {
@ -501,7 +697,30 @@ export function useOuterLineWall() {
} }
}, },
diagonalLine: (e) => { diagonalLine: (e) => {
console.log('diagonalLine') if (points.length === 0) {
return
}
const key = e.key
switch (key) {
case 'Down': // IE/Edge에서 사용되는 값
case 'ArrowDown': {
checkDiagonal('↓')
break
}
case 'Up': // IE/Edge에서 사용되는 값
case 'ArrowUp':
checkDiagonal('↑')
break
case 'Left': // IE/Edge에서 사용되는 값
case 'ArrowLeft':
checkDiagonal('←')
break
case 'Right': // IE/Edge에서 사용되는 값
case 'ArrowRight':
checkDiagonal('→')
break
}
}, },
} }
@ -513,7 +732,7 @@ export function useOuterLineWall() {
setPoints((prev) => prev.slice(0, prev.length - 1)) setPoints((prev) => prev.slice(0, prev.length - 1))
} }
const handleFix = () => { const handleFix = (fn) => {
if (points.length < 3) { if (points.length < 3) {
return return
} }
@ -541,6 +760,9 @@ export function useOuterLineWall() {
setPoints((prev) => { setPoints((prev) => {
return [...prev, { x: prev[0].x, y: prev[0].y }] return [...prev, { x: prev[0].x, y: prev[0].y }]
}) })
isFix.current = true
closeModalFn.current = fn
} }
return { return {
@ -558,6 +780,15 @@ export function useOuterLineWall() {
setArrow2, setArrow2,
arrow1Ref, arrow1Ref,
arrow2Ref, arrow2Ref,
angle1,
setAngle1,
angle1Ref,
angle2,
setAngle2,
angle2Ref,
outerLineDiagonalLength,
setOuterLineDiagonalLength,
outerLineDiagonalLengthRef,
type, type,
setType, setType,
handleFix, handleFix,

View File

@ -0,0 +1,129 @@
import { useEffect, useRef } from 'react'
import { LINE_TYPE } from '@/common/common'
import { useRecoilValue } from 'recoil'
import { canvasState } from '@/store/canvasAtom'
export function usePropertiesSetting() {
const currentLine = useRef(null)
const currentIdx = useRef(-1)
const canvas = useRecoilValue(canvasState)
useEffect(() => {
selectNextLine()
}, [])
const handleSetEaves = () => {
currentLine.current.set({
stroke: '#45CD7D',
strokeWidth: 4,
attributes: {
offset: 500,
type: LINE_TYPE.WALLLINE.EAVES,
pitch: 4,
},
})
canvas.renderAll()
selectNextLine()
}
const handleSetGable = () => {
currentLine.current.set({
stroke: '#3FBAE6',
strokeWidth: 4,
attributes: {
offset: 300,
type: LINE_TYPE.WALLLINE.GABLE,
},
})
canvas.renderAll()
selectNextLine()
}
const selectNextLine = () => {
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
currentIdx.current++
if (currentIdx.current >= lines.length) {
currentIdx.current = lines.length
currentLine.current = lines[currentIdx.current - 1]
return
}
currentLine.current = lines[currentIdx.current]
currentLine.current.set({
stroke: '#EA10AC',
strokeWidth: 4,
})
canvas.renderAll()
}
const selectPrevLine = () => {
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
currentIdx.current--
if (currentIdx.current <= -1) {
currentIdx.current = -1
selectNextLine()
return
} else {
lines.forEach((line, index) => {
if (index >= currentIdx.current) {
delete line.attributes
line.set({
stroke: '#000000',
strokeWidth: 4,
})
}
currentIdx.current--
canvas.renderAll()
selectNextLine()
})
}
}
const handleRollback = () => {
selectPrevLine()
}
const handleFix = () => {
if (!confirm('외벽선 속성 설정을 완료하시겠습니까?')) {
return
}
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
lines.forEach((line) => {
line.set({
attributes: line.attributes ? line.attributes : { offset: 0, type: LINE_TYPE.WALLLINE.WALL },
stroke: '#000000',
strokeWidth: 4,
})
})
canvas.renderAll()
}
const closeModal = (fn) => {
if (!confirm('외벽선 속성 설정을 종료 하시겠습니까?')) {
return
}
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
lines.forEach((line) => {
line.set({
attributes: { offset: 0, type: LINE_TYPE.WALLLINE.WALL },
stroke: '#000000',
strokeWidth: 4,
})
})
canvas.renderAll()
fn(false)
}
return { handleSetEaves, handleSetGable, handleRollback, handleFix, closeModal }
}

View File

@ -26,7 +26,7 @@ export function useAdsorptionPoint() {
top: pointer.y - 3, top: pointer.y - 3,
x: pointer.x, x: pointer.x,
y: pointer.y, y: pointer.y,
selectable: false, selectable: true,
name: 'adsorptionPoint', name: 'adsorptionPoint',
}) })

View File

@ -79,5 +79,9 @@ export function useAxios(lang = '') {
.catch(console.error) .catch(console.error)
} }
return { get, promiseGet, post, promisePost, put, promisePut, patch, del } const promiseDel = async ({ url }) => {
return await getInstances(url).delete(url)
}
return { get, promiseGet, post, promisePost, put, promisePut, patch, del, promiseDel }
} }

View File

@ -36,6 +36,7 @@ export function useCanvas(id) {
setCanvas(c) setCanvas(c)
setCanvasForEvent(c) setCanvasForEvent(c)
attachDefaultEventOnCanvas()
return () => { return () => {
// c.dispose() // c.dispose()
@ -45,7 +46,6 @@ export function useCanvas(id) {
useEffect(() => { useEffect(() => {
// canvas 사이즈가 변경되면 다시 // canvas 사이즈가 변경되면 다시
attachDefaultEventOnCanvas()
}, [canvasSize]) }, [canvasSize])
useEffect(() => { useEffect(() => {
@ -91,6 +91,13 @@ export function useCanvas(id) {
// settings for all canvas in the app // settings for all canvas in the app
fabric.Object.prototype.transparentCorners = false fabric.Object.prototype.transparentCorners = false
fabric.Object.prototype.id = uuidv4() fabric.Object.prototype.id = uuidv4()
fabric.Object.prototype.selectable = true
fabric.Object.prototype.lockMovementX = true
fabric.Object.prototype.lockMovementY = true
fabric.Object.prototype.lockRotation = true
fabric.Object.prototype.lockScalingX = true
fabric.Object.prototype.lockScalingY = true
fabric.Object.prototype.cornerColor = '#2BEBC8' fabric.Object.prototype.cornerColor = '#2BEBC8'
fabric.Object.prototype.cornerStyle = 'rect' fabric.Object.prototype.cornerStyle = 'rect'
fabric.Object.prototype.cornerStrokeColor = '#2BEBC8' fabric.Object.prototype.cornerStrokeColor = '#2BEBC8'

View File

@ -6,6 +6,7 @@ import { gridColorState } from '@/store/gridAtom'
export function useDotLineGrid() { export function useDotLineGrid() {
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
const gridColor = useRecoilValue(gridColorState) const gridColor = useRecoilValue(gridColorState)
const [dotLineGridSetting, setDotLineGridSettingState] = useRecoilState(dotLineGridSettingState) const [dotLineGridSetting, setDotLineGridSettingState] = useRecoilState(dotLineGridSettingState)
const interval = useRecoilValue(dotLineIntervalSelector) // 가로 세로 간격 const interval = useRecoilValue(dotLineIntervalSelector) // 가로 세로 간격

View File

@ -1,24 +1,16 @@
import { useEffect, useRef } from 'react' import { useEffect, useRef } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue } from 'recoil'
import { import { canvasState, canvasZoomState, currentMenuState } from '@/store/canvasAtom'
adsorptionPointAddModeState,
adsorptionPointModeState,
adsorptionRangeState,
canvasState,
canvasZoomState,
currentMenuState,
} from '@/store/canvasAtom'
import { fabric } from 'fabric' import { fabric } from 'fabric'
import { calculateDistance, calculateIntersection, distanceBetweenPoints, findClosestPoint } from '@/util/canvas-util' import { calculateDistance, distanceBetweenPoints, findClosestPoint } from '@/util/canvas-util'
import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint' import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint'
import { useMouse } from '@/hooks/useMouse'
import { useDotLineGrid } from '@/hooks/useDotLineGrid' import { useDotLineGrid } from '@/hooks/useDotLineGrid'
import { useTempGrid } from '@/hooks/useTempGrid' import { useTempGrid } from '@/hooks/useTempGrid'
export function useEvent() { export function useEvent() {
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
const currentMenu = useRecoilValue(currentMenuState) const currentMenu = useRecoilValue(currentMenuState)
const keyboardEventListeners = useRef([]) const documentEventListeners = useRef([])
const mouseEventListeners = useRef([]) const mouseEventListeners = useRef([])
const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState) const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState)
@ -30,9 +22,8 @@ export function useEvent() {
if (!canvas) { if (!canvas) {
return return
} }
removeAllMouseEventListeners()
removeAllDocumentEventListeners() removeAllDocumentEventListeners()
removeAllMouseEventListeners()
/** /**
* wheelEvent * wheelEvent
*/ */
@ -193,13 +184,14 @@ export function useEvent() {
} }
const addCanvasMouseEventListener = (eventType, handler) => { const addCanvasMouseEventListener = (eventType, handler) => {
canvas.off(eventType)
canvas.on(eventType, handler) canvas.on(eventType, handler)
mouseEventListeners.current.push({ eventType, handler }) mouseEventListeners.current.push({ eventType, handler })
} }
const removeAllMouseEventListeners = () => { const removeAllMouseEventListeners = () => {
mouseEventListeners.current.forEach(({ eventType, handler }) => { mouseEventListeners.current.forEach(({ eventType, handler }) => {
canvas.off(eventType, handler) canvas.off(eventType)
}) })
mouseEventListeners.current.length = 0 // 배열 초기화 mouseEventListeners.current.length = 0 // 배열 초기화
} }
@ -211,24 +203,36 @@ export function useEvent() {
* @param handler * @param handler
*/ */
const addDocumentEventListener = (eventType, element, handler) => { const addDocumentEventListener = (eventType, element, handler) => {
removeDocumentEvent(eventType)
element.addEventListener(eventType, handler) element.addEventListener(eventType, handler)
keyboardEventListeners.current.push({ eventType, element, handler }) documentEventListeners.current.push({ eventType, element, handler })
} }
/** /**
* document에 등록되는 event 제거 * document에 등록되는 event 제거
*/ */
const removeAllDocumentEventListeners = () => { const removeAllDocumentEventListeners = () => {
keyboardEventListeners.current.forEach(({ eventType, element, handler }) => { documentEventListeners.current.forEach(({ eventType, element, handler }) => {
element.removeEventListener(eventType, handler) element.removeEventListener(eventType, handler)
}) })
keyboardEventListeners.current.length = 0 // 배열 초기화 documentEventListeners.current.length = 0 // 배열 초기화
} }
const removeMouseEvent = (type, handler) => { const removeMouseEvent = (type) => {
mouseEventListeners.current = mouseEventListeners.current.filter((event) => { mouseEventListeners.current = mouseEventListeners.current.filter((event) => {
if (event.type === type && event.handler === handler) { if (event.eventType === type) {
canvas.off(type, handler) canvas.off(type, event.handler)
return false
}
return true
})
}
const removeDocumentEvent = (type) => {
documentEventListeners.current = documentEventListeners.current.filter((event) => {
if (event.eventType === type) {
console.log(type)
event.element.removeEventListener(type, event.handler)
return false return false
} }
return true return true

View File

@ -38,6 +38,7 @@ export const useLine = () => {
const removeLine = (line) => { const removeLine = (line) => {
removeLineText(line) removeLineText(line)
canvas?.remove(line) canvas?.remove(line)
canvas?.renderAll()
} }
const removeLineText = (line) => { const removeLineText = (line) => {

View File

@ -39,6 +39,7 @@ import * as turf from '@turf/turf'
import { INPUT_TYPE, Mode } from '@/common/common' import { INPUT_TYPE, Mode } from '@/common/common'
import { m } from 'framer-motion' import { m } from 'framer-motion'
import { set } from 'react-hook-form' import { set } from 'react-hook-form'
import { FaWineGlassEmpty } from 'react-icons/fa6'
export function useMode() { export function useMode() {
const [mode, setMode] = useRecoilState(modeState) const [mode, setMode] = useRecoilState(modeState)
@ -4851,6 +4852,12 @@ export function useMode() {
) )
} }
const coordToTurfPolygon = (points) => {
const coordinates = points.map((point) => [point.x, point.y])
coordinates.push(coordinates[0])
return turf.polygon([coordinates])
}
/** /**
* trestle에서 영역을 가져와 mouse:move 이벤트로 해당 영역에 진입했을때 booleanPointInPolygon 진입여부를 확인 * trestle에서 영역을 가져와 mouse:move 이벤트로 해당 영역에 진입했을때 booleanPointInPolygon 진입여부를 확인
* 확인 셀을 이동시킴 * 확인 셀을 이동시킴
@ -4859,29 +4866,19 @@ export function useMode() {
const trestlePolygons = canvas?.getObjects().filter((obj) => obj.name === 'trestle') //가대를 가져옴 const trestlePolygons = canvas?.getObjects().filter((obj) => obj.name === 'trestle') //가대를 가져옴
if (trestlePolygons.length !== 0) { if (trestlePolygons.length !== 0) {
let lastPointPosition = { x: 0, y: 0 }
let fabricPolygon = null let fabricPolygon = null
let inside = false let inside = false
let turfPolygon let turfPolygon
let manualDrawCells = drewRoofCells // let manualDrawCells = drewRoofCells // 앞에서 자동으로 했을때 추가됨
let direction
canvas.on('mouse:move', (e) => { canvas.on('mouse:move', (e) => {
//마우스 이벤트 삭제 후 재추가 //마우스 이벤트 삭제 후 재추가
const mousePoint = canvas.getPointer(e.e) const mousePoint = canvas.getPointer(e.e)
const turfPoint = turf.point([mousePoint.x, mousePoint.y])
for (let i = 0; i < trestlePolygons.length; i++) { for (let i = 0; i < trestlePolygons.length; i++) {
turfPolygon = polygonToTurfPolygon(trestlePolygons[i]) turfPolygon = polygonToTurfPolygon(trestlePolygons[i])
if (turf.booleanPointInPolygon(turfPoint, turfPolygon)) { direction = trestlePolygons[i].direction //도형의 방향
//turf에 보면 폴리곤안에 포인트가 있는지 함수가 있다 let width = direction === 'south' || direction === 'north' ? 172 : 113
const direction = trestlePolygons[i].direction //도형의 방향 let height = direction === 'south' || direction === 'north' ? 113 : 172
let width = direction === 'south' || direction === 'north' ? 172.2 : 113.4
let height = direction === 'south' || direction === 'north' ? 113.4 : 172.2
if (Math.abs(mousePoint.x - lastPointPosition.x) >= 5 || Math.abs(mousePoint.y - lastPointPosition.y) >= 5) {
let isDrawing = false
if (isDrawing) return
canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tmpCell')) //움직일때 일단 지워가면서 움직임
const points = [ const points = [
{ x: mousePoint.x - width / 2, y: mousePoint.y - height / 2 }, { x: mousePoint.x - width / 2, y: mousePoint.y - height / 2 },
@ -4890,9 +4887,21 @@ export function useMode() {
{ x: mousePoint.x - width / 2, y: mousePoint.y + height / 2 }, { x: mousePoint.x - width / 2, y: mousePoint.y + height / 2 },
] ]
const turfPoints = coordToTurfPolygon(points)
if (turf.booleanWithin(turfPoints, turfPolygon)) {
//turf에 보면 폴리곤안에 포인트가 있는지 함수가 있다
// if (Math.abs(mousePoint.x - lastPointPosition.x) >= 5 || Math.abs(mousePoint.y - lastPointPosition.y) >= 5) {
let isDrawing = false
if (isDrawing) return
canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tmpCell')) //움직일때 일단 지워가면서 움직임
fabricPolygon = new QPolygon(points, { fabricPolygon = new QPolygon(points, {
fill: '#BFFD9F', fill: '#BFFD9F',
stroke: 'black', // stroke: 'black',
// strokeWidth: 1,
selectable: false, // 선택 가능하게 설정 selectable: false, // 선택 가능하게 설정
lockMovementX: true, // X 축 이동 잠금 lockMovementX: true, // X 축 이동 잠금
lockMovementY: true, // Y 축 이동 잠금 lockMovementY: true, // Y 축 이동 잠금
@ -4905,12 +4914,77 @@ export function useMode() {
}) })
canvas?.add(fabricPolygon) //움직여가면서 추가됨 canvas?.add(fabricPolygon) //움직여가면서 추가됨
lastPointPosition = { x: mousePoint.x, y: mousePoint.y }
/**
* 스냅기능
*/
let snapDistance = 20
const bigLeft = trestlePolygons[i].left
const bigTop = trestlePolygons[i].top
const bigRight = bigLeft + trestlePolygons[i].width * trestlePolygons[i].scaleX
const bigBottom = bigTop + trestlePolygons[i].height * trestlePolygons[i].scaleY
const bigCenter = (bigTop + bigTop + trestlePolygons[i].height) / 2
// 작은 폴리곤의 경계 좌표 계산
const smallLeft = fabricPolygon.left
const smallTop = fabricPolygon.top
const smallRight = smallLeft + fabricPolygon.width * fabricPolygon.scaleX
const smallBottom = smallTop + fabricPolygon.height * fabricPolygon.scaleY
const smallCenter = smallLeft + (fabricPolygon.width * fabricPolygon.scaleX) / 2
// 위쪽 변에 스냅
if (Math.abs(smallTop - bigTop) < snapDistance) {
fabricPolygon.top = bigTop
} }
// 아래쪽 변에 스냅
if (Math.abs(smallTop + fabricPolygon.height * fabricPolygon.scaleY - (bigTop + trestlePolygons[i].height)) < snapDistance) {
fabricPolygon.top = bigTop + trestlePolygons[i].height - fabricPolygon.height * fabricPolygon.scaleY
}
// 왼쪽변에 스냅
if (Math.abs(smallLeft - bigLeft) < snapDistance) {
fabricPolygon.left = bigLeft
}
//오른쪽 변에 스냅
if (Math.abs(smallRight - bigRight) < snapDistance) {
fabricPolygon.left = bigRight - fabricPolygon.width * fabricPolygon.scaleX
}
if (direction === 'south' || direction === 'north') {
// 모듈왼쪽이 세로중앙선에 붙게 스냅
if (Math.abs(smallLeft - (bigLeft + trestlePolygons[i].width / 2)) < snapDistance) {
fabricPolygon.left = bigLeft + trestlePolygons[i].width / 2
}
// 모듈이 가운데가 세로중앙선에 붙게 스냅
if (Math.abs(smallCenter - (bigLeft + trestlePolygons[i].width / 2)) < snapDistance) {
fabricPolygon.left = bigLeft + trestlePolygons[i].width / 2 - (fabricPolygon.width * fabricPolygon.scaleX) / 2
}
// 모듈오른쪽이 세로중앙선에 붙게 스냅
if (Math.abs(smallRight - (bigLeft + trestlePolygons[i].width / 2)) < snapDistance) {
fabricPolygon.left = bigLeft + trestlePolygons[i].width / 2 - fabricPolygon.width * fabricPolygon.scaleX
}
} else {
// 모듈이 가로중앙선에 스냅
if (Math.abs(smallTop + fabricPolygon.height / 2 - bigCenter) < snapDistance) {
fabricPolygon.top = bigCenter - fabricPolygon.height / 2
}
if (Math.abs(smallTop - (bigTop + trestlePolygons[i].height / 2)) < snapDistance) {
fabricPolygon.top = bigTop + trestlePolygons[i].height / 2
}
// 모듈 밑면이 가로중앙선에 스냅
if (Math.abs(smallBottom - (bigTop + trestlePolygons[i].height / 2)) < snapDistance) {
fabricPolygon.top = bigTop + trestlePolygons[i].height / 2 - fabricPolygon.height * fabricPolygon.scaleY
}
}
fabricPolygon.setCoords()
canvas?.renderAll() canvas?.renderAll()
inside = true inside = true
break
} else { } else {
inside = false inside = false
} }
@ -4926,20 +5000,26 @@ export function useMode() {
if (!inside) return if (!inside) return
if (fabricPolygon) { if (fabricPolygon) {
const turfCellPolygon = polygonToTurfPolygon(fabricPolygon) const turfCellPolygon = polygonToTurfPolygon(fabricPolygon)
fabricPolygon.setCoords() //좌표 재정렬
if (turf.booleanWithin(turfCellPolygon, turfPolygon)) { if (turf.booleanWithin(turfCellPolygon, turfPolygon)) {
//마우스 클릭시 set으로 해당 위치에 셀을 넣음 //마우스 클릭시 set으로 해당 위치에 셀을 넣음
manualDrawCells.forEach((cell) => {
console.log('cells', cell.points)
})
console.log('turfCellPolygon', turfCellPolygon.geometry.coordinates)
const isOverlap = manualDrawCells.some((cell) => turf.booleanOverlap(turfCellPolygon, polygonToTurfPolygon(cell))) const isOverlap = manualDrawCells.some((cell) => turf.booleanOverlap(turfCellPolygon, polygonToTurfPolygon(cell)))
if (!isOverlap) { if (!isOverlap) {
//안겹치면 넣는다 //안겹치면 넣는다
fabricPolygon.set({ name: 'cell' })
fabricPolygon.setCoords() fabricPolygon.setCoords()
fabricPolygon.set({ name: 'cell' })
manualDrawCells.push(fabricPolygon) manualDrawCells.push(fabricPolygon)
} else { } else {
alert('셀끼리 겹치면 안되죠?') alert('셀끼리 겹치면 안되죠?')
} }
} else { // } else {
alert('나갔으요!!') // alert('나갔으요!!')
} }
setDrewRoofCells(manualDrawCells) setDrewRoofCells(manualDrawCells)
} }
@ -5016,27 +5096,6 @@ export function useMode() {
// console.log('bbox', bbox) // console.log('bbox', bbox)
const boxes = []
const installedCellsArray = []
for (let x = bbox[0]; x < bbox[2]; x += width) {
for (let y = bbox[1]; y < bbox[3]; y += height) {
const box = turf.polygon([
[
[x, y],
[x + width, y],
[x + width, y + height],
[x, y + height],
[x, y],
],
])
if (turf.booleanWithin(box, turfTrestlePolygon)) {
boxes.push(box)
}
}
}
for (let col = 0; col <= cols; col++) { for (let col = 0; col <= cols; col++) {
for (let row = 0; row <= rows; row++) { for (let row = 0; row <= rows; row++) {
let x = 0, let x = 0,
@ -5086,20 +5145,6 @@ export function useMode() {
const squarePolygon = turf.polygon([square]) const squarePolygon = turf.polygon([square])
// console.log('turfTrestlePolygon', turfTrestlePolygon)
// console.log('squarePolygon', squarePolygon)
const areaSize = turf.area(turfTrestlePolygon)
// console.log('areaSize', areaSize)
const objSize = turf.area(squarePolygon)
// console.log('objSize', objSize)
const maxObject = Math.floor(areaSize / objSize)
// console.log('maxObjectSize', maxObject)
const disjointFromTrestle = turf.booleanContains(turfTrestlePolygon, squarePolygon) || turf.booleanWithin(squarePolygon, turfTrestlePolygon) const disjointFromTrestle = turf.booleanContains(turfTrestlePolygon, squarePolygon) || turf.booleanWithin(squarePolygon, turfTrestlePolygon)
if (disjointFromTrestle) { if (disjointFromTrestle) {
@ -5140,6 +5185,8 @@ export function useMode() {
lockScalingY: true, // Y 축 크기 조정 잠금 lockScalingY: true, // Y 축 크기 조정 잠금
opacity: 0.8, opacity: 0.8,
parentId: trestle.parentId, parentId: trestle.parentId,
lineCol: col,
lineRow: row,
}) })
canvas?.add(fabricPolygon) canvas?.add(fabricPolygon)
drawCellsArray.push(fabricPolygon) drawCellsArray.push(fabricPolygon)

View File

@ -2,18 +2,15 @@ import { useRecoilState } from 'recoil'
import { canvasState, currentCanvasPlanState, initCanvasPlansState } from '@/store/canvasAtom' import { canvasState, currentCanvasPlanState, initCanvasPlansState } from '@/store/canvasAtom'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { toastUp } from '@/hooks/useToast' import { useSwal } from '@/hooks/useSwal'
import { sessionStore } from '@/store/commonAtom'
import { useState } from 'react'
export function usePlan() { export function usePlan() {
const [canvas, setCanvas] = useRecoilState(canvasState) const [canvas, setCanvas] = useRecoilState(canvasState)
const [currentCanvasPlan, setcurrentCanvasPlan] = useRecoilState(currentCanvasPlanState) const [currentCanvasPlan, setcurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
const [initCanvasPlans, setInitCanvasPlans] = useRecoilState(initCanvasPlansState) const [initCanvasPlans, setInitCanvasPlans] = useRecoilState(initCanvasPlansState)
const { swalFire } = useSwal()
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { get, promisePost, promisePut } = useAxios() const { get, promisePost, promisePut, promiseDel } = useAxios()
const [sessionState, setSessionState] = useRecoilState(sessionStore)
const [userId, setUserId] = useState(sessionState.userId)
/** /**
* 마우스 포인터의 가이드라인을 제거합니다. * 마우스 포인터의 가이드라인을 제거합니다.
@ -103,14 +100,14 @@ export function usePlan() {
await promisePut({ url: '/api/canvas-management/canvas-statuses', data: planData }) await promisePut({ url: '/api/canvas-management/canvas-statuses', data: planData })
.then((res) => { .then((res) => {
toastUp({ message: getMessage('common.message.save'), type: 'success' }) // 성공 시 메세지 없음 swalFire({ text: getMessage('common.message.save') })
console.log('[PUT] canvas-statuses res :::::::: %o', res) console.log('[PUT] canvas-statuses res :::::::: %o', res)
setInitCanvasPlans((initCanvasPlans) => setInitCanvasPlans((initCanvasPlans) =>
initCanvasPlans.map((plan) => (plan.id === currentCanvasPlan.id ? { ...plan, canvasStatus: canvasStatus } : plan)), initCanvasPlans.map((plan) => (plan.id === currentCanvasPlan.id ? { ...plan, canvasStatus: canvasStatus } : plan)),
) )
}) })
.catch((error) => { .catch((error) => {
toastUp({ message: error.message, type: 'error' }) swalFire({ text: error.message, icon: 'error' })
console.error('[PUT] canvas-statuses error :::::::: %o', error) console.error('[PUT] canvas-statuses error :::::::: %o', error)
}) })
} else { } else {
@ -124,11 +121,11 @@ export function usePlan() {
await promisePost({ url: '/api/canvas-management/canvas-statuses', data: planData }) await promisePost({ url: '/api/canvas-management/canvas-statuses', data: planData })
.then((res) => { .then((res) => {
toastUp({ message: getMessage('common.message.save'), type: 'success' }) // 성공 시 메세지 없음 swalFire({ text: getMessage('common.message.save') })
console.log('[POST] canvas-statuses response :::::::: %o', res) console.log('[POST] canvas-statuses response :::::::: %o', res)
}) })
.catch((error) => { .catch((error) => {
toastUp({ message: error.message, type: 'error' }) swalFire({ text: error.message, icon: 'error' })
console.error('[POST] canvas-statuses res error :::::::: %o', error) console.error('[POST] canvas-statuses res error :::::::: %o', error)
}) })
} }
@ -137,7 +134,7 @@ export function usePlan() {
/** /**
* objectNo에 해당하는 canvas 목록을 조회하는 함수 * objectNo에 해당하는 canvas 목록을 조회하는 함수
*/ */
const getCanvasByObjectNo = async (objectNo) => { const getCanvasByObjectNo = async (userId, objectNo) => {
return get({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}/${userId}` }).then((res) => return get({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}/${userId}` }).then((res) =>
res.map((item) => ({ res.map((item) => ({
id: item.id, id: item.id,
@ -149,11 +146,26 @@ export function usePlan() {
) )
} }
/**
* id에 해당하는 canvas 데이터를 삭제하는 함수
*/
const delCanvasById = (id) => {
return promiseDel({ url: `/api/canvas-management/canvas-statuses/by-id/${id}` })
}
/**
* objectNo에 해당하는 canvas 데이터들을 삭제하는 함수
*/
const delCanvasByObjectNo = (objectNo) => {
return promiseDel({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}` })
}
return { return {
canvas, canvas,
removeMouseLines, removeMouseLines,
saveCanvas, saveCanvas,
addCanvas, addCanvas,
getCanvasByObjectNo, getCanvasByObjectNo,
delCanvasById,
} }
} }

View File

@ -32,6 +32,7 @@
"modal.cover.outline.arrow": "方向 (矢印)", "modal.cover.outline.arrow": "方向 (矢印)",
"modal.cover.outline.fix": "外壁線確定", "modal.cover.outline.fix": "外壁線確定",
"modal.cover.outline.rollback": "一変戦に戻る", "modal.cover.outline.rollback": "一変戦に戻る",
"modal.cover.outline.finish": "設定完了",
"modal.cover.outline.remove": "外壁の削除", "modal.cover.outline.remove": "外壁の削除",
"modal.cover.outline.select.move": "外壁の選択、移動", "modal.cover.outline.select.move": "外壁の選択、移動",
"plan.menu.roof.cover.roof.setting": "屋根形状設定", "plan.menu.roof.cover.roof.setting": "屋根形状設定",
@ -115,6 +116,11 @@
"modal.canvas.setting.first.option.border": "ボーダーのみ", "modal.canvas.setting.first.option.border": "ボーダーのみ",
"modal.canvas.setting.first.option.line": "ラインハッチ", "modal.canvas.setting.first.option.line": "ラインハッチ",
"modal.canvas.setting.first.option.all": "All painted", "modal.canvas.setting.first.option.all": "All painted",
"modal.canvas.setting.wallline.properties.setting": "外壁のプロパティの設定",
"modal.canvas.setting.wallline.properties.setting.info": "※属性を変更する外壁線を選択し、軒で設定またはケラバで設定 ボタンをクリックして設定値を適用します。",
"modal.canvas.setting.wallline.properties.setting.eaves": "軒で設定",
"modal.canvas.setting.wallline.properties.setting.edge": "ケラバに設定",
"setting": "設定",
"common.message.no.data": "No data", "common.message.no.data": "No data",
"common.message.no.dataDown": "ダウンロードするデータがありません", "common.message.no.dataDown": "ダウンロードするデータがありません",
"common.message.noData": "表示するデータがありません", "common.message.noData": "表示するデータがありません",

View File

@ -36,6 +36,7 @@
"modal.cover.outline.arrow": "방향(화살표)", "modal.cover.outline.arrow": "방향(화살표)",
"modal.cover.outline.fix": "외벽선 확정", "modal.cover.outline.fix": "외벽선 확정",
"modal.cover.outline.rollback": "일변전으로 돌아가기", "modal.cover.outline.rollback": "일변전으로 돌아가기",
"modal.cover.outline.finish": "설정완료",
"modal.cover.outline.remove": "외벽 제거", "modal.cover.outline.remove": "외벽 제거",
"modal.cover.outline.select.move": "외벽 선택, 이동", "modal.cover.outline.select.move": "외벽 선택, 이동",
"plan.menu.placement.surface": "배치면", "plan.menu.placement.surface": "배치면",
@ -116,6 +117,11 @@
"modal.canvas.setting.first.option.border": "테두리만", "modal.canvas.setting.first.option.border": "테두리만",
"modal.canvas.setting.first.option.line": "라인해치", "modal.canvas.setting.first.option.line": "라인해치",
"modal.canvas.setting.first.option.all": "All painted", "modal.canvas.setting.first.option.all": "All painted",
"modal.canvas.setting.wallline.properties.setting": "외벽선 속성 설정",
"modal.canvas.setting.wallline.properties.setting.info": "※ 속성을 변경할 외벽선을 선택하고, 처마로 설정 또는 케라바로 설정\n 버튼을 클릭하여 설정값을 적용하십시오.\n",
"modal.canvas.setting.wallline.properties.setting.eaves": "처마로 설정",
"modal.canvas.setting.wallline.properties.setting.edge": "케라바로 설정",
"setting": "설정",
"common.message.no.data": "No data", "common.message.no.data": "No data",
"common.message.no.dataDown": "No data to download", "common.message.no.dataDown": "No data to download",
"common.message.noData": "No data to display", "common.message.noData": "No data to display",

View File

@ -4,16 +4,29 @@ $pop-bold-weight: 500;
$pop-normal-size: 12px; $pop-normal-size: 12px;
$alert-color: #101010; $alert-color: #101010;
@keyframes mountpop{ @keyframes mountpop {
from{opacity: 0; scale: 0.95;} from {
to{opacity: 1; scale: 1;} opacity: 0;
} scale: 0.95;
@keyframes unmountpop{ }
from{opacity: 1; scale: 1;} to {
to{opacity: 0; scale: 0.95;} opacity: 1;
scale: 1;
}
} }
.modal-pop-wrap{ @keyframes unmountpop {
from {
opacity: 1;
scale: 1;
}
to {
opacity: 0;
scale: 0.95;
}
}
.modal-pop-wrap {
position: fixed; position: fixed;
top: 200px; top: 200px;
right: 100px; right: 100px;
@ -27,50 +40,66 @@ $alert-color: #101010;
background-color: #272727; background-color: #272727;
z-index: 9999999; z-index: 9999999;
overflow: hidden; overflow: hidden;
&.r{
&.r {
width: 400px; width: 400px;
} }
&.sm{
&.lr {
width: 440px;
}
&.sm {
width: 580px; width: 580px;
} }
&.ssm{
&.ssm {
width: 380px; width: 380px;
} }
&.xm{
&.xm {
width: 300px; width: 300px;
} }
&.l{
&.l {
width: 800px; width: 800px;
} }
&.mount{
&.mount {
animation: mountpop .17s ease-in-out forwards; animation: mountpop .17s ease-in-out forwards;
} }
&.unmount{
&.unmount {
animation: unmountpop .17s ease-in-out forwards; animation: unmountpop .17s ease-in-out forwards;
} }
&.alert{
&.alert {
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
background-color: transparent; background-color: transparent;
border: none; border: none;
.modal-head{
.modal-head {
background-color: transparent; background-color: transparent;
padding: 0 0 8px; padding: 0 0 8px;
.modal-close{
.modal-close {
width: 20px; width: 20px;
height: 20px; height: 20px;
background: url(../../public/static/images/canvas/alert_close.svg)no-repeat center; background: url(../../public/static/images/canvas/alert_close.svg) no-repeat center;
} }
} }
.modal-body{
.modal-body {
background-color: #fff; background-color: #fff;
padding: 22px; padding: 22px;
border-radius: 4px; border-radius: 4px;
border: 1px solid #101010; border: 1px solid #101010;
color: $alert-color; color: $alert-color;
.alert-title{
.alert-title {
font-size: 13px; font-size: 13px;
font-weight: 700; font-weight: 700;
color: $alert-color; color: $alert-color;
@ -79,82 +108,108 @@ $alert-color: #101010;
} }
} }
} }
.modal-head{
.modal-head {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 10px 24px; padding: 10px 24px;
background-color: #000; background-color: #000;
h1.title{
h1.title {
font-size: 13px; font-size: 13px;
color: $pop-color; color: $pop-color;
font-weight: 700; font-weight: 700;
} }
.modal-close{
.modal-close {
margin-left: auto; margin-left: auto;
color: $pop-color; color: $pop-color;
text-indent: -999999999px; text-indent: -999999999px;
width: 10px; width: 10px;
height: 10px; height: 10px;
background: url(../../public/static/images/canvas/modal_close.svg)no-repeat center; background: url(../../public/static/images/canvas/modal_close.svg) no-repeat center;
} }
} }
.modal-body{
.modal-body {
padding: 24px; padding: 24px;
.modal-btn-wrap{
.modal-btn-wrap {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 5px; gap: 5px;
button{
button {
flex: 1; flex: 1;
} }
&.sub {
button {
flex: 1 1 auto;
padding: 0;
} }
.modal-check-btn-wrap{ }
}
.modal-check-btn-wrap {
margin-top: 15px; margin-top: 15px;
.check-wrap-title{
.check-wrap-title {
font-size: $pop-normal-size; font-size: $pop-normal-size;
color: $pop-color; color: $pop-color;
font-weight: 600; font-weight: 600;
&.light{
&.light {
font-weight: $pop-normal-weight; font-weight: $pop-normal-weight;
} }
} }
.flex-check-box{
.flex-check-box {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 10px; gap: 10px;
margin-top: 15px; margin-top: 15px;
&.for2{
&.for2 {
justify-content: flex-end; justify-content: flex-end;
button{
button {
width: calc(50% - 5px); width: calc(50% - 5px);
} }
&.btn{
&.btn {
gap: 5px; gap: 5px;
button{
button {
width: calc(50% - 2.5px); width: calc(50% - 2.5px);
} }
} }
} }
&.for-line{
button{ &.for-line {
button {
flex: 1; flex: 1;
} }
} }
} }
} }
.outer-line-wrap{
.outer-line-wrap {
border-top: 1px solid #3C3C3C; border-top: 1px solid #3C3C3C;
margin-top: 10px; margin-top: 10px;
padding-top: 15px; padding-top: 15px;
margin-bottom: 15px; margin-bottom: 15px;
> div{
> div {
margin-bottom: 15px; margin-bottom: 15px;
&:last-child{
&:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
} }
} }
.modal-guide{
.modal-guide {
display: block; display: block;
font-size: $pop-normal-size; font-size: $pop-normal-size;
color: $alert-color; color: $alert-color;
@ -162,7 +217,7 @@ $alert-color: #101010;
} }
} }
.adsorption-point{ .adsorption-point {
display: flex; display: flex;
align-items: center; align-items: center;
background-color: #3A3A3A; background-color: #3A3A3A;
@ -170,11 +225,13 @@ $alert-color: #101010;
padding-left: 11px; padding-left: 11px;
overflow: hidden; overflow: hidden;
transition: all 0.17s ease-in-out; transition: all 0.17s ease-in-out;
span{
span {
font-size: $pop-normal-size; font-size: $pop-normal-size;
color: #898989; color: #898989;
} }
i{
i {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 0 7px; padding: 0 7px;
@ -183,8 +240,9 @@ $alert-color: #101010;
font-size: 13px; font-size: 13px;
color: #898989; color: #898989;
} }
&.act{
i{ &.act {
i {
color: $pop-color; color: $pop-color;
background-color: #1083E3; background-color: #1083E3;
} }
@ -192,17 +250,19 @@ $alert-color: #101010;
} }
// grid-option // grid-option
.grid-check-form{ .grid-check-form {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 15px; gap: 15px;
padding-bottom: 15px; padding-bottom: 15px;
border-bottom: 1px solid #3C3C3C; border-bottom: 1px solid #3C3C3C;
} }
.grid-option-wrap{
.grid-option-wrap {
padding: 15px 0; padding: 15px 0;
border-bottom: 1px solid #3C3C3C; border-bottom: 1px solid #3C3C3C;
.grid-option-box{
.grid-option-box {
display: flex; display: flex;
align-items: center; align-items: center;
background-color: #3D3D3D; background-color: #3D3D3D;
@ -210,57 +270,68 @@ $alert-color: #101010;
padding: 10px; padding: 10px;
gap: 20px; gap: 20px;
margin-bottom: 5px; margin-bottom: 5px;
.grid-input-form{
.grid-input-form {
display: flex; display: flex;
align-items: center; align-items: center;
span{
span {
flex: none; flex: none;
font-size: $pop-normal-size; font-size: $pop-normal-size;
color: $pop-color; color: $pop-color;
font-weight: $pop-bold-weight; font-weight: $pop-bold-weight;
} }
.input-grid{
.input-grid {
width: 54px; width: 54px;
input{
input {
width: 100%; width: 100%;
} }
} }
} }
&:last-child{
&:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
} }
} }
.grid-select{
.grid-select {
flex: 1; flex: 1;
.sort-select{
.sort-select {
width: 100%; width: 100%;
background-color: #313131; background-color: #313131;
} }
} }
.grid-btn-wrap{
.grid-btn-wrap {
padding-top: 15px; padding-top: 15px;
text-align: right; text-align: right;
button{
button {
padding: 0 20px; padding: 0 20px;
} }
} }
// grid copy // grid copy
.grid-option-tit{ .grid-option-tit {
font-size: $pop-normal-size; font-size: $pop-normal-size;
color: $pop-color; color: $pop-color;
font-weight: $pop-normal-weight; font-weight: $pop-normal-weight;
padding-bottom: 15px; padding-bottom: 15px;
border-bottom: 1px solid #3C3C3C; border-bottom: 1px solid #3C3C3C;
} }
.grid-direction{
.grid-direction {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 5px; gap: 5px;
flex: 1; flex: 1;
} }
.direction{
.direction {
width: 22px; width: 22px;
height: 22px; height: 22px;
background-color: #757575; background-color: #757575;
@ -271,39 +342,54 @@ $alert-color: #101010;
border-radius: 50%; border-radius: 50%;
transition: all .15s ease-in-out; transition: all .15s ease-in-out;
opacity: 0.6; opacity: 0.6;
&.down{transform: rotate(180deg);}
&.left{transform: rotate(-90deg);} &.down {
&.right{transform: rotate(90deg);} transform: rotate(180deg);
}
&.left {
transform: rotate(-90deg);
}
&.right {
transform: rotate(90deg);
}
&:hover, &:hover,
&.act{ &.act {
opacity: 1; opacity: 1;
} }
} }
// grid-move // grid-move
.move-form{ .move-form {
p{ p {
font-size: $pop-normal-size; font-size: $pop-normal-size;
color: $pop-color; color: $pop-color;
font-weight: $pop-bold-weight; font-weight: $pop-bold-weight;
} }
} }
.input-move-wrap{
.input-move-wrap {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 5px; gap: 5px;
span{
span {
color: $pop-color; color: $pop-color;
font-size: $pop-normal-size; font-size: $pop-normal-size;
} }
.input-move{
.input-move {
width: 130px; width: 130px;
input{
input {
width: 100%; width: 100%;
} }
} }
} }
.direction-move-wrap{
.direction-move-wrap {
flex: none; flex: none;
display: grid; display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
@ -311,11 +397,12 @@ $alert-color: #101010;
} }
// 배치면 초기 설정 // 배치면 초기 설정
.placement-table{ .placement-table {
table{ table {
table-layout: fixed; table-layout: fixed;
tr{
th{ tr {
th {
display: flex; display: flex;
align-items: center; align-items: center;
font-size: $pop-normal-size; font-size: $pop-normal-size;
@ -324,49 +411,57 @@ $alert-color: #101010;
padding: 18px 0; padding: 18px 0;
border-bottom: 1px solid #424242; border-bottom: 1px solid #424242;
} }
td{
td {
font-size: $pop-normal-size; font-size: $pop-normal-size;
color: $pop-color; color: $pop-color;
border-bottom: 1px solid #424242; border-bottom: 1px solid #424242;
padding-left: 20px; padding-left: 20px;
} }
&:first-child{
&:first-child {
td, td,
th{ th {
padding-top: 0; padding-top: 0;
} }
} }
} }
} }
.tooltip{
.tooltip {
position: relative; position: relative;
display: block; display: block;
width: 15px; width: 15px;
height: 15px; height: 15px;
margin-left: 5px; margin-left: 5px;
background: url(../../public/static/images/canvas/pop_tip.svg)no-repeat center; background: url(../../public/static/images/canvas/pop_tip.svg) no-repeat center;
background-size: cover; background-size: cover;
} }
&.light{
&.light {
padding: 0; padding: 0;
th,td{
th, td {
color: $alert-color; color: $alert-color;
border-bottom: none; border-bottom: none;
border-top: 1px solid #EFEFEF; border-top: 1px solid #EFEFEF;
} }
th{
th {
padding: 14px 0; padding: 14px 0;
} }
tr{
&:first-child{ tr {
&:first-child {
td, td,
th{ th {
padding-top: 14px; padding-top: 14px;
} }
} }
&:last-child{
&:last-child {
td, td,
th{ th {
padding-bottom: 0px; padding-bottom: 0px;
} }
} }
@ -374,26 +469,30 @@ $alert-color: #101010;
} }
} }
.pop-form-radio{ .pop-form-radio {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 10px;
} }
.placement-option{
.placement-option {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 20px; gap: 20px;
} }
.select-wrap{
div{ .select-wrap {
div {
width: 100%; width: 100%;
} }
} }
.flex-ment{
.flex-ment {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 5px; gap: 5px;
span{
span {
font-size: $pop-normal-size; font-size: $pop-normal-size;
color: $pop-color; color: $pop-color;
font-weight: $pop-normal-weight; font-weight: $pop-normal-weight;
@ -401,32 +500,45 @@ $alert-color: #101010;
} }
// 외벽선 그리기 // 외벽선 그리기
.outline-wrap{ .outline-wrap {
padding: 24px 0; padding: 24px 0;
border-top: 1px solid #424242;
border-bottom: 1px solid #424242; border-bottom: 1px solid #424242;
.outline-inner{
.outline-inner {
display: flex; display: flex;
align-items: center; align-items: center;
margin-bottom: 14px; margin-bottom: 14px;
&:last-child{
&:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
.outline-form {
width: 50%;
}
} }
} }
.outline-form{
width: 50%; .outline-form {
display: flex; display: flex;
align-items: center; align-items: center;
margin-right: 15px; margin-right: 15px;
span{
span {
width: 60px; width: 60px;
flex: none; flex: none;
font-size: $pop-normal-size; font-size: $pop-normal-size;
font-weight: $pop-bold-weight; font-weight: $pop-bold-weight;
color: $pop-color; color: $pop-color;
margin-right: 10px; margin-right: 10px;
&.thin {
font-weight: & $pop-normal-weight;
} }
.reset-btn{ }
.reset-btn {
flex: none; flex: none;
width: 30px; width: 30px;
height: 30px; height: 30px;
@ -439,31 +551,152 @@ $alert-color: #101010;
background-size: 12px 12px; background-size: 12px 12px;
background-position: center; background-position: center;
} }
&:last-child{
&:last-child {
margin-right: 0; margin-right: 0;
} }
} }
.cul-wrap{ .cul-wrap {
display: flex; display: flex;
.outline-box{
.outline-box {
width: 50%; width: 50%;
margin-right: 15px; margin-right: 15px;
.outline-form{
.outline-form {
width: 100%; width: 100%;
margin-bottom: 14px; margin-bottom: 14px;
margin-right: 0; margin-right: 0;
&:last-child{
&:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
} }
} }
.cul-box{
.cul-box {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 50%; width: 50%;
background-color: #3D3D3D; background-color: #3D3D3D;
border-radius: 2px ; border-radius: 2px;
} }
} }
// 외벽선 속성 설정
.properties-guide {
font-size: $pop-normal-size;
color: #AAA;
font-weight: $pop-normal-weight;
margin-bottom: 14px;
}
.properties-setting-wrap {
&.outer {
margin-top: 24px;
}
.setting-tit {
font-size: 13px;
color: $pop-color;
font-weight: $pop-bold-weight;
margin-bottom: 10px;
}
.setting-btn-wrap {
display: flex;
align-items: center;
padding: 14px 0;
border-top: 1px solid #424242;
border-bottom: 1px solid #424242;
.setting-btn {
display: block;
width: 100%;
height: 40px;
font-size: 13px;
color: #fff;
font-weight: 700;
border-radius: 2px;
transition: all .15s ease-in-out;
&.green {
background-color: #305941;
border: 1px solid #45CD7D;
&:hover {
background-color: #3a6b4e;
}
}
&.blue {
background-color: #2E5360;
border: 1px solid #3FBAE6;
&:hover {
background-color: #365f6e;
}
}
}
}
}
// 지붕형상 설정
.roof-shape-menu {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr;
gap: 24px 10px;
margin-bottom: 24px;
.shape-box {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 13px;
background-color: #3D3D3D;
transition: background .15s ease-in-out;
img {
max-width: 100%;
}
}
.shape-title {
font-size: $pop-normal-size;
font-weight: $pop-bold-weight;
color: $pop-color;
margin-top: 10px;
text-align: center;
transition: color .15s ease-in-out;
}
.shape-menu-box {
&.act,
&:hover {
.shape-box {
background-color: #008BFF;
}
.shape-title {
color: #008BFF;
}
}
}
}
.setting-box {
padding: 14px 0;
border-top: 1px solid #424242;
border-bottom: 1px solid #424242;
}
.discrimination-box {
padding: 16px 12px;
border: 1px solid #3D3D3D;
border-radius: 2px;
margin-top: 14px;
}

View File

@ -1,18 +1,21 @@
* { * {
-webkit-text-size-adjust:none; -webkit-text-size-adjust: none;
-moz-text-size-adjust:none; -moz-text-size-adjust: none;
-ms-text-size-adjust:none; -ms-text-size-adjust: none;
text-size-adjust: none; text-size-adjust: none;
box-sizing: content-box box-sizing: content-box
} }
*, ::after, ::before { *, ::after, ::before {
box-sizing: border-box; box-sizing: border-box;
} }
html, body{
html, body {
width: 100%; width: 100%;
height: 100%; height: 100%;
font-size: 16px; font-size: 16px;
} }
html, body, div, span, applet, object, iframe, html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre, h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code, a, abbr, acronym, address, big, cite, code,
@ -36,86 +39,105 @@ time, mark, audio, video {
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
font-smooth: never; font-smooth: never;
} }
/* HTML5 display-role reset for older browsers */ /* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section { footer, header, hgroup, menu, nav, section {
display: block; display: block;
} }
body { body {
line-height: 1.4; line-height: 1.4;
} }
body:first-of-type caption { display:none;}
body:first-of-type caption {
display: none;
}
ol, ul { ol, ul {
list-style: none; list-style: none;
} }
blockquote, q { blockquote, q {
quotes: none; quotes: none;
} }
blockquote:before, blockquote:after, blockquote:before, blockquote:after,
q:before, q:after { q:before, q:after {
content: ''; content: '';
content: none; content: none;
} }
table { table {
width: 100%; width: 100%;
border-collapse: separate; border-collapse: separate;
border-spacing:0; border-spacing: 0;
border:0 none; border: 0 none;
} }
caption, th, td { caption, th, td {
text-align:left; text-align: left;
font-weight: normal; font-weight: normal;
border:0; border: 0;
} }
a { a {
cursor:pointer; cursor: pointer;
color:#000; color: #000;
} }
a, a:hover, a:active { a, a:hover, a:active {
text-decoration:none; text-decoration: none;
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: transparent;
} }
/*form_style*/ /*form_style*/
input, select, textarea, button, a, label { input, select, textarea, button, a, label {
-webkit-tap-highlight-color:rgba(0,0,0,0); -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
} }
button,input[type=text], input[type=button] {
button, input[type=text], input[type=button] {
-webkit-appearance: none; -webkit-appearance: none;
-webkit-border-radius: 0; -webkit-border-radius: 0;
-webkit-appearance:none; -webkit-appearance: none;
appearance: none; appearance: none;
border-radius: 0 border-radius: 0
} }
input[type=checkbox], input[type=radio] { input[type=checkbox], input[type=radio] {
box-sizing: border-box; box-sizing: border-box;
padding: 0; padding: 0;
} }
input, select, button { input, select, button {
border:0 none; border: 0 none;
outline:none; outline: none;
margin:0; margin: 0;
} }
select { select {
-webkit-appearance: none; -webkit-appearance: none;
-moz-appearance: none; -moz-appearance: none;
appearance: none; appearance: none;
} }
select::-ms-expand { select::-ms-expand {
display: none; display: none;
} }
::-webkit-input-placeholder { ::-webkit-input-placeholder {
line-height:1; line-height: 1;
font-weight:300; font-weight: 300;
font-size:0.938rem; font-size: 0.938rem;
letter-spacing:-0.6px; letter-spacing: -0.6px;
color:#8b8b8b; color: #8b8b8b;
} }
.log-box ::-webkit-input-placeholder{
color:#8b8b8b; .log-box ::-webkit-input-placeholder {
color: #8b8b8b;
} }
button{
button {
background: transparent; background: transparent;
font-family: 'Noto Sans JP', sans-serif; font-family: 'Noto Sans JP', sans-serif;
border: none; border: none;
@ -126,22 +148,46 @@ button{
outline: none; outline: none;
cursor: pointer; cursor: pointer;
} }
.pre{
.pre {
font-family: 'Pretendard', sans-serif !important; font-family: 'Pretendard', sans-serif !important;
} }
// margin // margin
.mt5{margin-top: 5px !important;} .mt5 {
.mt10{margin-top: 10px !important;} margin-top: 5px !important;
.mb5{margin-bottom: 5px !important;} }
.mb10{margin-bottom: 10px !important;}
.mr5{margin-right: 5px !important;} .mt10 {
.mr10{margin-right: 10px !important;} margin-top: 10px !important;
.ml5{margin-left: 5px !important;} }
.ml10{margin-left: 10px !important;}
.mb5 {
margin-bottom: 5px !important;
}
.mb10 {
margin-bottom: 10px !important;
}
.mr5 {
margin-right: 5px !important;
}
.mr10 {
margin-right: 10px !important;
}
.ml5 {
margin-left: 5px !important;
}
.ml10 {
margin-left: 10px !important;
}
// button // button
.btn-frame{ .btn-frame {
display: inline-block; display: inline-block;
padding: 0 7px; padding: 0 7px;
height: 34px; height: 34px;
@ -155,65 +201,94 @@ button{
font-family: 'Pretendard', sans-serif; font-family: 'Pretendard', sans-serif;
transition: all .17s ease-in-out; transition: all .17s ease-in-out;
cursor: pointer; cursor: pointer;
&.block{
&.block {
width: 100%; width: 100%;
} }
&.small{
&.small {
font-family: 'Noto Sans JP', sans-serif; font-family: 'Noto Sans JP', sans-serif;
height: 30px; height: 30px;
line-height: 30px; line-height: 30px;
font-size: 13px; font-size: 13px;
} }
&.deepgray{ &.deepgray {
background-color: #2C2C2C; background-color: #2C2C2C;
border: 1px solid #484848; border: 1px solid #484848;
} }
&.gray{
&.gray {
background-color: #3C3C3C; background-color: #3C3C3C;
border: 1px solid #545454; border: 1px solid #545454;
} }
&.dark{
&.dark {
background-color: #1C1C1C; background-color: #1C1C1C;
border: 1px solid #484848; border: 1px solid #484848;
} }
&.modal{
&.modal {
font-family: 'Noto Sans JP', sans-serif; font-family: 'Noto Sans JP', sans-serif;
background-color: #272727; background-color: #272727;
border: 1px solid #484848; border: 1px solid #484848;
color: #aaa; color: #aaa;
&:hover{
&:hover {
background-color: #1083E3; background-color: #1083E3;
border: 1px solid #1083E3; border: 1px solid #1083E3;
color: #fff; color: #fff;
font-weight: 500; font-weight: 500;
} }
} }
&.sub-tab {
height: 30px;
padding: 0 10px;
line-height: 28px;
font-family: 'Noto Sans JP', sans-serif;
background-color: #2D2D2D;
border: 1px solid #393939;
color: #aaa;
&.act,
&:hover {
background-color: #414E6C;
border: 1px solid #414E6C;
color: #fff;
font-weight: 500;
}
}
&:hover, &:hover,
&.act{ &.act {
background-color: #1083E3; background-color: #1083E3;
border: 1px solid #1083E3; border: 1px solid #1083E3;
color: #fff; color: #fff;
font-weight: 500; font-weight: 500;
} }
&.block{
&.block {
display: block; display: block;
width: 100%; width: 100%;
} }
&.ico-flx{
&.ico-flx {
display: flex; display: flex;
align-items: center; align-items: center;
.ico{
.ico {
margin-right: 10px; margin-right: 10px;
} }
&:hover, &:hover,
&.act{ &.act {
font-weight: 400; font-weight: 400;
} }
} }
} }
.btn-origin{ .btn-origin {
display: inline-block; display: inline-block;
height: 30px; height: 30px;
padding: 0 14px; padding: 0 14px;
@ -223,22 +298,26 @@ button{
font-size: 13px; font-size: 13px;
font-weight: 400; font-weight: 400;
transition: all .15s ease-in-out; transition: all .15s ease-in-out;
&.navy{
&.navy {
background-color: #304961; background-color: #304961;
&:hover{
&:hover {
background-color: #1083E3; background-color: #1083E3;
} }
} }
&.grey{
&.grey {
background-color: #94A0AD; background-color: #94A0AD;
&:hover{
&:hover {
background-color: #607F9A; background-color: #607F9A;
} }
} }
} }
// select // select
.sort-select{ .sort-select {
position: relative; position: relative;
display: inline-block; display: inline-block;
min-width: 100px; min-width: 100px;
@ -251,16 +330,18 @@ button{
border-top-left-radius: 2px; border-top-left-radius: 2px;
color: #fff; color: #fff;
cursor: pointer; cursor: pointer;
p{
p {
font-size: 13px; font-size: 13px;
color: #fff; color: #fff;
height: 100%; height: 100%;
} }
.select-item-wrap{
.select-item-wrap {
position: absolute; position: absolute;
top: 100%; top: 100%;
left: -1px; left: -1px;
clip-path:inset(0 0 100% 0); clip-path: inset(0 0 100% 0);
width: calc(100% + 2px); width: calc(100% + 2px);
padding: 8px 0; padding: 8px 0;
background-color: #373737; background-color: #373737;
@ -268,23 +349,27 @@ button{
border-radius: 2px; border-radius: 2px;
transition: all 0.17s ease-in-out; transition: all 0.17s ease-in-out;
visibility: hidden; visibility: hidden;
.select-item{
.select-item {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 8px 20px; padding: 8px 20px;
line-height: 1.4; line-height: 1.4;
transition: all .17s ease-in-out; transition: all .17s ease-in-out;
button{
button {
font-size: 12px; font-size: 12px;
color: #fff; color: #fff;
line-height: 1.4; line-height: 1.4;
} }
&:hover{
&:hover {
background-color: #2C2C2C; background-color: #2C2C2C;
} }
} }
} }
&::after{
&::after {
content: ''; content: '';
position: absolute; position: absolute;
top: 50%; top: 50%;
@ -296,18 +381,20 @@ button{
background-size: cover; background-size: cover;
transition: all .17s ease-in-out; transition: all .17s ease-in-out;
} }
&.active{
.select-item-wrap{ &.active {
.select-item-wrap {
clip-path: inset(0 0 0 0); clip-path: inset(0 0 0 0);
visibility: visible; visibility: visible;
} }
&:after{
&:after {
transform: translateY(-50%) rotate(-180deg); transform: translateY(-50%) rotate(-180deg);
} }
} }
} }
.select-light{ .select-light {
position: relative; position: relative;
display: block; display: block;
width: 100%; width: 100%;
@ -320,16 +407,19 @@ button{
color: #45576F; color: #45576F;
font-family: 'Noto Sans JP', sans-serif; font-family: 'Noto Sans JP', sans-serif;
cursor: pointer; cursor: pointer;
&:disabled{
&:disabled {
opacity: 1; opacity: 1;
background-color: #FAFAFA; background-color: #FAFAFA;
color: #999; color: #999;
cursor: default; cursor: default;
} }
&.black{
&.black {
color: #101010; color: #101010;
} }
&.dark{
&.dark {
background: #323234 url(../../public/static/images/common/select_dark_arr.svg) calc(100% - 11px) center no-repeat; background: #323234 url(../../public/static/images/common/select_dark_arr.svg) calc(100% - 11px) center no-repeat;
color: #898989; color: #898989;
font-size: 12px; font-size: 12px;
@ -340,8 +430,8 @@ button{
// input // input
.form-input{ .form-input {
label{ label {
display: block; display: block;
color: #aaa; color: #aaa;
font-size: 12px; font-size: 12px;
@ -349,9 +439,10 @@ button{
margin-bottom: 10px; margin-bottom: 10px;
} }
} }
input[type=number], input[type=number],
input[type=text]{ input[type=text] {
&.input-origin{ &.input-origin {
display: inline-block; display: inline-block;
height: 30px; height: 30px;
line-height: 30px; line-height: 30px;
@ -364,16 +455,19 @@ input[type=text]{
padding: 0 10px; padding: 0 10px;
letter-spacing: 0px; letter-spacing: 0px;
text-align: right; text-align: right;
&::placeholder{
&::placeholder {
opacity: 1; opacity: 1;
font-size: 12px; font-size: 12px;
letter-spacing: 0px; letter-spacing: 0px;
} }
&.block{
&.block {
width: 100%; width: 100%;
} }
} }
&.input-light{
&.input-light {
display: block; display: block;
width: 100%; width: 100%;
height: 30px; height: 30px;
@ -387,7 +481,8 @@ input[type=text]{
font-weight: normal; font-weight: normal;
transition: border-color .17s ease-in-out; transition: border-color .17s ease-in-out;
text-align: left; text-align: left;
&:read-only{
&:read-only {
background-color: #FAFAFA; background-color: #FAFAFA;
color: #999999; color: #999999;
} }
@ -395,40 +490,45 @@ input[type=text]{
} }
// check-btn // check-btn
.check-btn{ .check-btn {
display: flex; display: flex;
align-items: center; align-items: center;
height: 30px; height: 30px;
background-color: #3A3A3A; background-color: #3A3A3A;
border-radius: 3px; border-radius: 3px;
transition: all .17s ease-in-out; transition: all .17s ease-in-out;
.check-area{
.check-area {
flex: none; flex: none;
width: 30px; width: 30px;
height: 100%; height: 100%;
border-right: 1px solid #272727; border-right: 1px solid #272727;
background: url(../../public/static/images/canvas/check-grey.svg)no-repeat center; background: url(../../public/static/images/canvas/check-grey.svg) no-repeat center;
background-size: 11px 9px; background-size: 11px 9px;
} }
.title-area{
.title-area {
padding: 0 10px; padding: 0 10px;
font-size: 12px; font-size: 12px;
color: #898989; color: #898989;
font-weight: 400; font-weight: 400;
} }
&.block{
&.block {
width: 100%; width: 100%;
} }
&:hover, &:hover,
&.act{ &.act {
background-color: #fff; background-color: #fff;
.check-area{
.check-area {
border-right: 1px solid #101010; border-right: 1px solid #101010;
background: url(../../public/static/images/canvas/check-black.svg)no-repeat center; background: url(../../public/static/images/canvas/check-black.svg) no-repeat center;
} }
.title-area{
.title-area {
color: #101010; color: #101010;
font-weight: 600; font-weight: 600;
} }
@ -436,7 +536,7 @@ input[type=text]{
} }
// arr-btn // arr-btn
.arr-btn{ .arr-btn {
display: block; display: block;
height: 30px; height: 30px;
border-radius: 3px; border-radius: 3px;
@ -444,13 +544,15 @@ input[type=text]{
padding: 0 11px; padding: 0 11px;
text-align: left; text-align: left;
transition: all .17s ease-in-out; transition: all .17s ease-in-out;
span{
span {
position: relative; position: relative;
font-size: 12px; font-size: 12px;
color: #898989; color: #898989;
font-weight: 400; font-weight: 400;
padding-right: 15px; padding-right: 15px;
&:after{
&:after {
content: ''; content: '';
position: absolute; position: absolute;
top: 50%; top: 50%;
@ -458,32 +560,39 @@ input[type=text]{
transform: translateY(-50%); transform: translateY(-50%);
width: 5px; width: 5px;
height: 8px; height: 8px;
background: url(../../public/static/images/canvas/arr_btn_ico.svg)no-repeat center; background: url(../../public/static/images/canvas/arr_btn_ico.svg) no-repeat center;
} }
} }
&:hover, &:hover,
&.act{ &.act {
background-color: #fff; background-color: #fff;
span{
span {
color: #101010; color: #101010;
font-weight: 500; font-weight: 500;
&:after{
background: url(../../public/static/images/canvas/arr_btn_ico_black.svg)no-repeat center; &:after {
background: url(../../public/static/images/canvas/arr_btn_ico_black.svg) no-repeat center;
} }
} }
} }
&.dark{
&.dark {
text-align: center; text-align: center;
background-color: #272727; background-color: #272727;
border: 1px solid #484848; border: 1px solid #484848;
span{
span {
color: #Fff; color: #Fff;
&:after{
background: url(../../public/static/images/canvas/arr_btn_ico_white.svg)no-repeat center; &:after {
background: url(../../public/static/images/canvas/arr_btn_ico_white.svg) no-repeat center;
} }
} }
&:hover, &:hover,
&.act{ &.act {
background-color: #1083E3; background-color: #1083E3;
border: 1px solid #1083E3; border: 1px solid #1083E3;
} }
@ -492,11 +601,12 @@ input[type=text]{
// radio // radio
.d-check-radio, .d-check-radio,
.d-check-box{ .d-check-box {
line-height: 1.1; line-height: 1.1;
cursor: pointer; cursor: pointer;
input[type=checkbox], input[type=checkbox],
input[type=radio]{ input[type=radio] {
position: static; position: static;
margin-left: 0; margin-left: 0;
cursor: pointer; cursor: pointer;
@ -504,7 +614,8 @@ input[type=text]{
z-index: 1; z-index: 1;
flex: 0 0 auto; flex: 0 0 auto;
} }
label{
label {
position: relative; position: relative;
padding-left: 10px; padding-left: 10px;
margin-bottom: 0; margin-bottom: 0;
@ -517,81 +628,89 @@ input[type=text]{
font-weight: 400; font-weight: 400;
cursor: pointer; cursor: pointer;
} }
&.light{
label{ &.light {
label {
color: #45576F; color: #45576F;
} }
} }
&.no-text{
label{ &.no-text {
label {
padding-left: 0; padding-left: 0;
} }
} }
} }
.d-check-radio { .d-check-radio {
label{ label {
&::before{ &::before {
cursor: pointer; cursor: pointer;
content: ""; content: "";
display: inline-block; display: inline-block;
position: absolute; position: absolute;
width: 17px; width: 17px;
height: 17px; height: 17px;
top:2px; top: 2px;
left: 0; left: 0;
margin-left: -12px; margin-left: -12px;
border: 1px solid #999999; border: 1px solid #999999;
border-radius: 100%; border-radius: 100%;
background-color: transparent; background-color: transparent;
text-align:center; text-align: center;
font-size:13px; font-size: 13px;
line-height:1.4; line-height: 1.4;
transition: border 0.15s ease-in-out, color 0.15s ease-in-out; transition: border 0.15s ease-in-out, color 0.15s ease-in-out;
} }
&::after{
&::after {
cursor: pointer; cursor: pointer;
content: ""; content: "";
display: inline-block; display: inline-block;
position: absolute; position: absolute;
width: 9px; width: 9px;
height: 9px; height: 9px;
top:6px; top: 6px;
left: 4px; left: 4px;
margin-left: -12px; margin-left: -12px;
border: none; border: none;
border-radius: 100%; border-radius: 100%;
background-color: #fff; background-color: #fff;
text-align:center; text-align: center;
font-size:13px; font-size: 13px;
line-height:1.4; line-height: 1.4;
opacity: 0; opacity: 0;
visibility: hidden; visibility: hidden;
transition: opacity 0.15s ease-in-out, color 0.15s ease-in-out; transition: opacity 0.15s ease-in-out, color 0.15s ease-in-out;
} }
} }
&.light{
label{ &.light {
&:before{ label {
&:before {
border-color: #D6D6D7; border-color: #D6D6D7;
} }
&:after{
&:after {
background-color: #697C8F; background-color: #697C8F;
} }
} }
} }
input[type=radio]:checked + label::after{
input[type=radio]:checked + label::after {
opacity: 1; opacity: 1;
visibility: visible; visibility: visible;
} }
&.pop{
label{ &.pop {
&:before{ label {
&:before {
width: 16px; width: 16px;
height: 16px; height: 16px;
border-color: #fff; border-color: #fff;
} }
&:after{
&:after {
width: 8px; width: 8px;
height: 8px; height: 8px;
background-color: #fff; background-color: #fff;
@ -601,9 +720,9 @@ input[type=text]{
} }
// check-box // check-box
.d-check-box{ .d-check-box {
label{ label {
&::before{ &::before {
cursor: pointer; cursor: pointer;
content: ""; content: "";
display: inline-block; display: inline-block;
@ -617,20 +736,22 @@ input[type=text]{
background-color: transparent; background-color: transparent;
transition: border 0.15s ease-in-out, color 0.15s ease-in-out; transition: border 0.15s ease-in-out, color 0.15s ease-in-out;
} }
&:after{
&:after {
cursor: pointer; cursor: pointer;
content: ""; content: "";
display: inline-block; display: inline-block;
position: absolute; position: absolute;
width: 16px; width: 16px;
height: 16px; height: 16px;
top:0; top: 0;
left: 0; left: 0;
margin-left: -.8rem; margin-left: -.8rem;
transition: border 0.05s ease-in-out, color 0.05s ease-in-out; transition: border 0.05s ease-in-out, color 0.05s ease-in-out;
} }
} }
input[type=checkbox]:checked + label::after{
input[type=checkbox]:checked + label::after {
content: ""; content: "";
display: inline-block; display: inline-block;
position: absolute; position: absolute;
@ -641,23 +762,28 @@ input[type=text]{
border: 2px solid #697C8F; border: 2px solid #697C8F;
border-left: none; border-left: none;
border-top: none; border-top: none;
transform: translate(7.75px,4.5px) rotate(45deg); transform: translate(7.75px, 4.5px) rotate(45deg);
-ms-transform: translate(7.75px,4.5px) rotate(45deg); -ms-transform: translate(7.75px, 4.5px) rotate(45deg);
} }
&.pop{
input[type=checkbox]:checked + label::after{ &.pop {
input[type=checkbox]:checked + label::after {
border-color: #fff; border-color: #fff;
} }
} }
} }
// date-picker // date-picker
.date-picker{ .date-picker {
svg{display: none;} svg {
.react-datepicker-wrapper{ display: none;
}
.react-datepicker-wrapper {
width: 100%; width: 100%;
} }
input[type=text]{
input[type=text] {
display: block; display: block;
width: 100%; width: 100%;
height: 30px; height: 30px;