3. 클릭한 페이지에서 Get Font 클릭 (이미 받은 폰트가 적용했을경우 Remove라 나올텐데 클릭하면 다시 Get Font가 나온다)
4. 다운형식, import형식 택1
5-1.embed code (@import 형식)
Style.css
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100..900&display=swap');
body {
font-family: 'Noto Sans KR', sans-serif; /* 폰트 적용 */
}
하단과 같은 형태로 진행하면 되나 import할때까지 대기시간이 발생하며 페이지가 로딩된 시점에서 어긋나는 느낌을 주기에 별로 추천되지 않는다.
5-2. Download 방식
zip을 압축 해제한뒤 ttf파일을 resourecs에 위치시킨뒤 url에 해당 파일위치 지정
참고용 depth
Style.css
@font-face {
font-family: 'Noto Sans KR';
src: url('/FONT/NotoSansKR-VariableFont_wght.ttf') format('truetype'); /* TTF 폰트 사용 */
font-weight: 100 900;
font-style: normal;
}body {
font-family: 'Noto Sans KR', sans-serif; /* 폰트 적용 */
}
구글에 "고양이" 를 검색했을때 버튼이 나타나며 이것을 클릭했을때 현재 마우스 클릭위치를 기준으로 고양이 발바닥이 나타나는 이스터에그가 존재한다.
이것을 만들어볼거다...
기초 흐름
1. 사용할 img를 정한다
2. 클릭을 했을때 특정한 구역(box 등)에 나타난다
3. 랜덤하게 회전된 모습으로 출력한다.
조건
1. 이미지는 겹쳐지도록 만들어야한다.
2. 사이즈는 200,200으로 잡았다.
3. 구역의 사이즈는 동적페이지로 구성해야한다 (화면이 커져도 작아져도 그에 맞춰지도록)
enjoy.jsp
<section name="form-section">
<form id="fileUploadForm" enctype="multipart/form-data">
<input type="file" name="file" id="file" onchange="previewImage(this);" />
<img id="preview" style="max-width: 200px; max-height: 200px;">
<button type="button" onclick="uploadFile()">Upload</button>
</form>
</section>
//이미지가 나올 컨테이너
<figure id="img-section"></figure>
<button id="loadImage">버튼을 클릭하세요</button>
<button id="clear">삭제하기</button>
<script>
let uploadedImageUrl = null;
//업로드 이미지 미리보기
function previewImage(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
uploadedImageUrl = e.target.result; // 업로드된 이미지의 URL 저장
document.getElementById('preview').src = uploadedImageUrl;
}
reader.readAsDataURL(input.files[0]);
}
}
//이미지 랜덤 배치하기
document.getElementById('loadImage').addEventListener('click', function() {
if (uploadedImageUrl) {
const imgSection = document.getElementById('img-section');
const img = document.createElement('img');
img.src = uploadedImageUrl;
// 이미지의 크기를 200x200 픽셀로 설정
img.style.width = '200px';
img.style.height = '200px';
img.style.position = 'absolute';
//양 끝 위치에 배치시 잘릴 우려가 있어 이미지 크기만큼 제외
const maxTop = imgSection.clientHeight - 200;
const maxLeft = imgSection.clientWidth - 200;
img.style.top = Math.floor(Math.random() * maxTop) + 'px';
img.style.left = Math.floor(Math.random() * maxLeft) + 'px';
// 이미지에 랜덤한 회전 각도 적용
const rotationDegree = Math.floor(Math.random() * 360); // 0도에서 359도 사이의 랜덤한 값
//ES6 이전 버전이라 이렇게 작성
//ES6 이후는 밑의 주석처리 코드로 작성
//img.style.transform = `rotate(${rotationDegree}deg)`;
img.style.transform = 'rotate(' + rotationDegree + 'deg)';
let scale = 0;
let opacity = 0;
const scaleStep = 0.05;
const opacityStep = 0.05;
function animate() {
scale += scaleStep;
opacity += opacityStep;
if (scale < 1) {
img.style.transform = `rotate(${rotationDegree}deg) scale(${scale})`;
img.style.opacity = opacity;
requestAnimationFrame(animate);
} else {
img.style.transform = `rotate(${rotationDegree}deg) scale(1)`;
img.style.opacity = 1;
}
}
requestAnimationFrame(animate);
imgSection.appendChild(img);
} else {
alert('먼저 이미지를 업로드해주세요.');
}
});
//삭제 애니메이션
document.getElementById('clear').addEventListener('click', function() {
var imgSection = document.getElementById('img-section');
// 높이와 투명도를 0으로 변경
imgSection.style.height = '0px';
imgSection.style.opacity = '0';
// 전환 효과가 완료되면 내용 삭제
imgSection.addEventListener('transitionend', function() {
imgSection.innerHTML = '';
imgSection.style.height = '';
imgSection.style.opacity = '1';
}, { once: true });
});
</script>
CSS
#img-section {
width: 100vw;
height: 100vh; /* 뷰포트 높이의 80%로 설정 */
justify-content: center; /* 가로 중앙 정렬 */
align-items: center;
margin: 10px;
position: relative; /* 이미지들이 이 요소 내에서 절대 위치를 가짐 */
overflow: hidden; /* 내부 요소가 밖으로 넘치지 않도록 함 */
transition: height 0.5s ease, opacity 0.5s ease; /* 높이와 투명도 변화에 대한 전환 효과 적용 */
}