ESG 스크롤 복귀와 기술 역량 이미지 정렬·지도 표시 개선

- ESG 푸터에서 위로 스크롤하면 문서 영역이 먼저 복귀하도록 처리
- 섹션 전환 중 문서 내부 스크롤을 막아 상단 잘림 방지
- 기술 역량 이미지의 상단 여백과 가용 높이를 본문 기준으로 정렬
- 이미지 진입 애니메이션을 고려해 텍스트 겹침과 화면 이탈 방지
- 기술 역량 프로젝트 순서·설명 및 개별 이미지 배치 설정 정리
- 기술 역량 데이터에 맞춰 검색용 정적 HTML 동기화
- 지도 검색용 도로명 주소와 층·호수 안내를 분리해 건물 위치 핀 표시
- 지도 기본 확대 수준을 16으로 설정하고 한국어 표시 적용
- 회사 소개·조직도와 개인정보 동의 거부 안내 문구 정리

검증:
- JavaScript 구문 검사 및 git diff --check 통과
- ESG 세 문서의 푸터 복귀·내부 스크롤·키보드 이동 확인
- 기술 역량 29개 슬라이드의 데스크톱 이미지 정렬 및 모바일 이동 확인
- 본사·지사 지도 위치 핀, 상세 주소, 외부 지도 링크 확인
This commit is contained in:
2026-09-30 17:55:10 +09:00
parent 51932269c7
commit 239f61c506
7 changed files with 73 additions and 102 deletions

View File

@@ -16,7 +16,7 @@ MATLAB Simulink를 활용한 Model 기반 Application Software 설계 및 검증
ISO 26262 기능 안전 개발 프로세스 기반 업무 (ASIL, FMEA, DFA) 를 수행하였습니다.
`,
scope: "Safety mechanism · Platform",
scope: "Side Body Control Module",
output: "SW module · Verification",
image: "assets/images/automotive/automotive_01_background.jpeg",
objectImage: "assets/images/automotive/automotive_01_object.png",
@@ -44,6 +44,27 @@ RTE( Runtime Environment)를 Generate하고 BSW 영역과 연계하여 Applicati
output: "Issue report · Tool flow",
image: "assets/images/automotive/automotive_02_background.png",
objectImage: "assets/images/automotive/automotive_02_object.png",
},
// P.15
{
id: "hvac-autosar-bsw-development",
type: "automotive",
category: "AUTOSAR BSW DEVELOPMENT",
title: "차량용 공조제어기 SW 개발",
subtitle: "H-VAC Controller Basic Software",
description: `차량용 공조제어기의 안정적인 소프트웨어 동작과 차량 전장 시스템과의 원활한 연계를 위해 AUTOSAR 기반의 BSW 및 Middleware를 개발하고, 제어기의 핵심 기능과 진단·보안·업데이트 기능을 통합 구현하였습니다.
FBL(Flash Boot Loader) 기능을 구현하고 Sleep & Wake-up 사양을 개발하여 차량의 전원 상태 변화에 따른 제어기의 안정적인 동작 환경을 확보하였습니다. BSW Configuration 및 Implementation을 수행하고 Middleware를 구현하였으며, M-CAL Port를 비롯하여 ADC, PWM, ICU, IoHwAb, OS 등 주요 AUTOSAR 모듈을 설정하고 제어기 사양에 맞게 통합하였습니다.
또한 CAN 요구사항을 반영하여 관련 DB를 Import하고 Generate 및 Harmonize 과정을 수행함으로써 차량 네트워크 환경과 제어기 소프트웨어 간의 통신 연계성을 구현하였습니다.
보안 기능 강화를 위해 HSM, ASK, SFM 및 Crypto Library를 포팅하고 기능 검증을 수행하여 차량용 제어기에 요구되는 보안 기능을 안정적으로 적용하였습니다. 진단 영역에서는 DiagDCM 및 DEM Configuration을 수행하고 관련 기능을 검증하여 차량 진단 시스템과 제어기 간의 안정적인 진단 환경을 구축하였습니다.
OTA(Over-The-Air) 기반 Background 및 Reprogramming 기능을 개발하고 검증하여 차량 소프트웨어를 안정적으로 업데이트할 수 있는 환경을 구현하였습니다. Watch-Dog 요구사항을 반영 개발하였습니다.`,
scope: "H-VAC Controller Basic Software",
output: "Control module · QA",
image: "assets/images/automotive/automotive_04_background.jpeg",
objectImage: "assets/images/automotive/automotive_04_object.png",
},
// P.14
{
@@ -67,27 +88,6 @@ ISO 및 OEM 요구사항을 기반으로 DoCAN 및 DoIP Stack을 개발하여 CA
image: "assets/images/automotive/automotive_03_background.png",
objectImage: "assets/images/automotive/automotive_03_object.png",
},
// P.15
{
id: "hvac-autosar-bsw-development",
type: "automotive",
category: "AUTOSAR BSW DEVELOPMENT",
title: "차량용 공조제어기 SW 개발",
subtitle: "H-VAC Controller Basic Software",
description: `차량용 공조제어기의 안정적인 소프트웨어 동작과 차량 전장 시스템과의 원활한 연계를 위해 AUTOSAR 기반의 BSW 및 Middleware를 개발하고, 제어기의 핵심 기능과 진단·보안·업데이트 기능을 통합 구현하였습니다.
FBL(Flash Boot Loader) 기능을 구현하고 Sleep & Wake-up 사양을 개발하여 차량의 전원 상태 변화에 따른 제어기의 안정적인 동작 환경을 확보하였습니다. BSW Configuration 및 Implementation을 수행하고 Middleware를 구현하였으며, M-CAL Port를 비롯하여 ADC, PWM, ICU, IoHwAb, OS 등 주요 AUTOSAR 모듈을 설정하고 제어기 사양에 맞게 통합하였습니다.
또한 CAN 요구사항을 반영하여 관련 DB를 Import하고 Generate 및 Harmonize 과정을 수행함으로써 차량 네트워크 환경과 제어기 소프트웨어 간의 통신 연계성을 구현하였습니다.
보안 기능 강화를 위해 HSM, ASK, SFM 및 Crypto Library를 포팅하고 기능 검증을 수행하여 차량용 제어기에 요구되는 보안 기능을 안정적으로 적용하였습니다. 진단 영역에서는 DiagDCM 및 DEM Configuration을 수행하고 관련 기능을 검증하여 차량 진단 시스템과 제어기 간의 안정적인 진단 환경을 구축하였습니다.
OTA(Over-The-Air) 기반 Background 및 Reprogramming 기능을 개발하고 검증하여 차량 소프트웨어를 안정적으로 업데이트할 수 있는 환경을 구현하였습니다. Watch-Dog 요구사항을 반영 개발하였습니다.`,
scope: "H-VAC Controller Basic Software",
output: "Control module · QA",
image: "assets/images/automotive/automotive_04_background.jpeg",
objectImage: "assets/images/automotive/automotive_04_object.png",
},
// P.16
{
id: "a-spice-swe5-integration-verification",
@@ -427,13 +427,6 @@ GPS 기반의 위치 정보를 활용하여 대중교통의 이동 상황을 실
output: "Control room · Alert",
image: "assets/images/solution/solution_05_background.png",
objectImage: "assets/images/solution/solution_05_object.png",
objectLayout: {
x: "50%",
y: "50%",
anchorX: "-50%",
anchorY: "-50%",
maxHeight: "560px",
},
},
// P.33
{
@@ -454,13 +447,6 @@ GPS 기반의 위치 정보를 활용하여 대중교통의 이동 상황을 실
output: "Capture flow · Viewer",
image: "assets/images/solution/solution_06_background.jpeg",
objectImage: "assets/images/solution/solution_06_object.png",
objectLayout: {
x: "50%",
y: "50%",
anchorX: "-50%",
anchorY: "-50%",
maxHeight: "560px",
},
},
// P.34
{
@@ -481,13 +467,6 @@ GPS 기반의 위치 정보를 활용하여 대중교통의 이동 상황을 실
output: "Pipeline · Dashboard",
image: "assets/images/solution/solution_07_background.jpeg",
objectImage: "assets/images/solution/solution_07_object.png",
objectLayout: {
x: "50%",
y: "50%",
anchorX: "-50%",
anchorY: "-50%",
maxHeight: "560px",
},
},
// P.35
{
@@ -508,13 +487,7 @@ GPS 기반의 위치 정보를 활용하여 대중교통의 이동 상황을 실
output: "Recognition module",
image: "assets/images/solution/solution_08_background.jpg",
objectImage: "assets/images/solution/solution_08_object.png",
objectLayout: {
x: "50%",
y: "50%",
anchorX: "-50%",
anchorY: "-50%",
maxHeight: "560px",
},
},
// Certifications
{
@@ -589,13 +562,6 @@ AUTOSAR 표준 기반의 플랫폼 환경에서 ECU 기능에 필요한 모듈
output: "Admin · Approval flow",
image: "assets/images/si/si_02_background.jpg",
objectImage: "assets/images/si/si_02_object.png",
objectLayout: {
x: "50%",
y: "50%",
anchorX: "-50%",
anchorY: "-50%",
maxHeight: "560px",
},
},
// P.40
{
@@ -642,13 +608,6 @@ AUTOSAR 표준 기반의 플랫폼 환경에서 ECU 기능에 필요한 모듈
output: "iOS/Android · API",
image: "assets/images/si/si_04_background.png",
objectImage: "assets/images/si/si_04_object.png",
objectLayout: {
x: "50%",
y: "50%",
anchorX: "-50%",
anchorY: "-50%",
maxHeight: "560px",
},
},
// P.42
{
@@ -711,13 +670,13 @@ GPS 기반의 자녀 안심존 관리 기능을 통해 지정된 안전 구역
output: "Backend · Docs",
image: "assets/images/si/si_07_background.png",
objectImage: "assets/images/si/si_07_object.png",
objectLayout: {
x: "50%",
y: "50%",
anchorX: "-50%",
anchorY: "-50%",
maxHeight: "560px",
},
// objectLayout: {
// x: "50%",
// y: "50%",
// anchorX: "-50%",
// anchorY: "-50%",
// maxHeight: "560px",
// },
},
// P.45
{
@@ -740,12 +699,5 @@ GPS 기반의 자녀 안심존 관리 기능을 통해 지정된 안전 구역
output: "Backend · Docs",
image: "assets/images/si/si_08_background.png",
objectImage: "assets/images/si/si_08_object.png",
objectLayout: {
x: "50%",
y: "50%",
anchorX: "-50%",
anchorY: "-50%",
maxHeight: "560px",
},
},
];

View File

@@ -176,6 +176,10 @@
function canScrollPolicy(target, direction) {
const panel = target.closest(".esg-policy-panel");
if (!panel || panel.hidden) return false;
const workspace = panel.closest(".esg-workspace");
// Restore the whole reader below the header before scrolling its document.
if (workspace && Math.abs(window.scrollY - sectionStop(workspace)) > 4) return false;
if (performance.now() < transitionUntil) return false;
const remaining = panel.scrollHeight - panel.clientHeight - panel.scrollTop;
return direction > 0 ? remaining > 2 : panel.scrollTop > 2;
}
@@ -238,10 +242,8 @@
<p>수집된 개인정보는 문의 처리 완료 후 1년간 보관하며, 보유 기간이 지나면 지체 없이 파기합니다.</p>
<h3>4. 정보 제공 및 처리 위탁</h3>
<p>제공된 정보는 문의 응대 목적으로 사용합니다. 외부 서비스에 처리를 위탁하는 경우 해당 서비스와 처리 범위를 운영 방침에 명시합니다.</p>
<h3>5. 동의 거부 및 정보 확인</h3>
<p>개인정보 수집 및 이용에 동의하지 않을 수 있습니다. 동의하지 않으면 온라인 문의를 전송할 수 없으며, 고객센터로 직접 연락할 수 있습니다. 제공한 정보의 확인, 수정, 삭제 요청도 고객센터로 문의할 수 있습니다.</p>
<h3>6. 개인정보 관련 문의</h3>
<p>주식회사 모비핀테크놀러지 · 고객센터 <a href="tel:0532140592">053-214-0592</a><br />평일 09:00 ~ 18:00</p>`,
<h3>5. 동의 거부</h3>
<p>개인정보 수집 및 이용에 동의하지 않을 수 있습니다. 다만, 동의하지 않을 경우 온라인 문의 서비스를 이용할 수 없습니다.</p>`,
},
sitemap: {
title: "사이트맵",
@@ -350,10 +352,11 @@
trigger.addEventListener("click", () => {
const office = trigger.dataset.mapTitle;
const address = trigger.dataset.mapAddress;
const query = encodeURIComponent(address);
// Search for the building; floor/unit details can prevent a map pin from resolving.
const query = encodeURIComponent(trigger.dataset.mapQuery || address);
title.textContent = `${office} 오시는 길`;
frame.title = `${office} 위치 지도`;
frame.src = `https://maps.google.com/maps?q=${query}&z=15&output=embed`;
frame.src = `https://maps.google.com/maps?q=${query}&z=16&hl=ko&output=embed`;
addressLabel.textContent = address;
mapLink.href = `https://www.google.com/maps/search/?api=1&query=${query}`;
dialog.showModal();
@@ -752,29 +755,43 @@
const titleBottom = featureTitle.getBoundingClientRect().bottom - stageBounds.top;
capabilitiesWorkbench.style.setProperty("--certificate-top", `${titleBottom + 24}px`);
}
const contentRight = featureContent.getBoundingClientRect().right + 32;
const contentBounds = featureContent.getBoundingClientRect();
const contentRight = contentBounds.right + 32;
const contentTop = contentBounds.top;
const contentBottom = stageBounds.bottom - parseFloat(window.getComputedStyle(stage).paddingBottom);
[featureObject, featureObjectSecondary].forEach((element) => {
if (!element) return;
element.style.removeProperty("width");
element.style.removeProperty("height");
element.style.removeProperty("--object-fit-x");
element.style.removeProperty("--object-fit-y");
if (!desktop || !hasDescription || !element.getAttribute("src")) return;
const style = window.getComputedStyle(element);
const width = parseFloat(style.width);
const height = parseFloat(style.height);
const available = Math.max(0, stageBounds.right - contentRight);
const availableHeight = Math.max(0, contentBottom - contentTop);
if (!width || !height) return;
// Fit the actual image ratio, not the potentially letterboxed CSS rectangle.
const naturalWidth = element.naturalWidth;
const naturalHeight = element.naturalHeight;
if (!naturalWidth || !naturalHeight) return;
const ratio = Math.min(width / naturalWidth, height / naturalHeight, available / naturalWidth);
const ratio = Math.min(width / naturalWidth, height / naturalHeight,
available / naturalWidth, availableHeight / naturalHeight);
element.style.width = `${naturalWidth * ratio}px`;
element.style.height = `${naturalHeight * ratio}px`;
const bounds = element.getBoundingClientRect();
const motionX = parseFloat(window.getComputedStyle(element).translate) || 0;
const settledLeft = bounds.left - motionX;
const fittedStyle = window.getComputedStyle(element);
const [motionX = 0, motionY = 0] = fittedStyle.translate.split(" ").map(parseFloat);
const transform = new DOMMatrixReadOnly(fittedStyle.transform);
const [originX, originY] = fittedStyle.transformOrigin.split(" ").map(parseFloat);
// Measure the final position, excluding entry translation and scale.
const settledLeft = bounds.left - motionX + (transform.a - 1) * originX;
const settledTop = bounds.top - motionY + (transform.d - 1) * originY;
const settledBottom = settledTop + naturalHeight * ratio;
element.style.setProperty("--object-fit-x", `${Math.max(0, contentRight - settledLeft)}px`);
element.style.setProperty("--object-fit-y", `${Math.max(contentTop - settledTop,
Math.min(0, contentBottom - settledBottom))}px`);
});
}