이번에도 간단한 배열 메소드를 연습하는 프로젝트.
some, every, find, findIndex 메소드 사용
선을 그릴 때마다 색깔과 선 두께가 바뀌는 HTML 캔버스 구현 프로젝트.
<canvas id="draw" width="800" height="800"></canvas>
canvas 태그의 속성은 width와 height 뿐(디폴트 300px, 150px)이며 DOM을 통해서 추후 조절이 가능하다.
또 주의할 것! canvas는 셀프클로징이 불가능한 태그라고 한다. 닫는 태그</canvas>
가 꼭 필요! -> 캔버스를 지원하지 않는 브라우저에는 canvas 태그 안에 img 태그 등을 임의로 넣어줄 수 있다.
캔버스 태그가 랜더링 영역을 지정해준다면, context는 컨텐츠의 출력 및 렌더링을 담당한다고 한다. getContext()라는 메소드를 사용하여 선언할 수 있으며, 인자로 '2d', '3d'를 지정해줄 수 있다. (webGL의 경우가 "3d")
const canvas = document.querySelector("#draw");
// 캔버스의 크기 설정하기
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// 2d 렌더링 컨텍스트 설정하기
const ctx = canvas.getContext("2d");
// 선의 모양 설정하기
ctx.strokeStyle = "#BADA55"; /* 선의 색, 그라디언트, 패턴 등을 결정 */
ctx.lineJoin = "round"; /* 두 선이 만났을 때 접점을 둥글게 처리 */
ctx.lineCap = "round"; /* 선 끝을 둥글게 */
ctx.lineWidth = 100; /* 선의 두께 */
let isDrawing = false; /* isDrawing state */
let lastX = 0; /* 시작점의 x좌표 설정 */
let lastY = 0; /* 시작점의 y좌표 설정 */
function draw(e) {
if (!isDrawing) return;
ctx.beginPath(); /* 경로를 그리기 시작 */
ctx.moveTo(lastX, lastY); /* 경로를 그리지 않고 해당 좌표로 이동 : 시작점*/
ctx.lineTo(e.offsetX, e.offsetY); /* 경로를 그리며 이동 : 끝점 */
ctx.stroke(); /* 지정한 경로에 실제로 선을 남김 */
lastX = e.offsetX; /* 그리기가 끝난 시점에 다음 시작점의 x좌표 설정 */
lastY = e.offsetY; /* 그리기가 끝난 시점에 다음 시작점의 y좌표 설정 */
}
canvas.addEventListener("mousemove", draw);
canvas.addEventListener("mousedown", (e) => {
isDrawing = true; /* isDrawing state 변경 */
lastX = e.offsetX; /* drawing 시작점의 x좌표 설정 */
lastY = e.offsetY; /* drawing 시작점의 y좌표 설정 */
});
canvas.addEventListener("mouseup", () => (isDrawing = false));
canvas.addEventListener("mouseout", () => (isDrawing = false));
hsl은 hue(색상), saturation(채도), lightness(명도)를 모두 바꿀 수 있는 메소드이다.
hue는 0부터 360까지의 스펙트럼(빨강 ~ 보라)을 가지고, saturation와 lightness는 0에서 100%까지의 스펙트럼을 가진다. saturation의 기본값은 100%, lightness는 50%인 듯?
let hue = 0;
let direction = true; /* 선 두께를 변경하기 위한 flag 역할 */
function draw(e) {
/* ...위 코드에 이어서 계속... */
hue++; /* 드로잉이 진행되는 동안 hue를 지속적으로 변경한다. */
if (hue >= 360) hue = 0; /* hue는 360까지이므로 다시 0으로 리셋 */
/* 선 두께를 0 ~ 100까지 조절하기 위한 flag */
if (ctx.lineWidth >= 100 || ctx.lineWidth <= 1) {
direction = !direction;
}
direction ? ctx.lineWidth++ : ctx.lineWidth--;
}
참고자료
background-image 속성에 가장 마지막 인자로 이미지 url을 넣으면 배경사진이 가장 마지막에 위치하게 된다.
그 위로 linear-gradient 효과를 주는데, 같은 %를 준다면 그 경계가 그라디언트가 아니라 면으로 나누어지는 효과를 활용하면 된다.
<div class="book"></div>
.book {
background-image:
linear-gradient(
105deg, /* 각도 조절! */
rgba($color-white, 0.9) 0%, /* 0 ~ 50%을 하얀색으로 */
rgba($color-white, 0.9) 50%, /* 50%라는 숫자가 겹치므로 경계는 면이 된다 */
transparent 50% /* 나머지를 투명색으로 */
),
url("../img/nat-10.jpg"); /* 배경이미지는 가장 마지막으로 */
}
순수 html form 태그에서도 validation check가 가능하다는 걸 오늘 알았다.
<input type="text" class="form__input" required />
이렇게 required 속성을 주면 된다!
.form__input:focus:invalid {
border-bottom: 3px solid $color-secondary-dark;
}
그리고 css에서 :focus:invalid를 설정하면 validation에 따른 스타일 설정이 가능하다.
<div class="one"></div>
<div class="two"></div>
<div class="three"></div>
/* 인접한 형제기 때문에 가능 */
.one + .two {
display: block;
}
/* 인접한 형제가 아니기 때문에 불가능 */
.one + .three {
display: block;
}
<div class="one"></div>
<div class="two"></div>
<div class="three"></div>
/* one two three 모두 선택 */
.one ~ .three {
display: block;
}
참고자료
라디오 버튼은 브라우저 자체 디자인이기 때문에 커스텀이 불가능해서 "display: none"으로 숨기고 임의의 span 태그를 디자인하는 꼼수를 배웠다!
<div class="form__radio-group">
<input type="radio" name="tour" id="small" class="form__radio-input"/>
<label for="small" class="form__radio-label">
<!--👇 요 친구가 가짜 라디오 버튼. label 안에 넣었기 때문에 input과 함께 묶인다 -->
<span class="form__radio-button"></span>
Small tour group
</label>
</div>
.form {
/* 진짜 라디오버튼은 숨긴다 */
&__radio-input {
display: none;
}
&__radio-label {
position: relative;
}
/* 임의의 라디오버튼 디자인 (테두리) */
&__radio-button {
height: 3rem;
width: 3rem;
border: 5px solid $color-primary;
border-radius: 50%;
display: inline-block;
position: absolute;
left: 0;
top: -0.4rem;
/* 임의의 라디오버튼 디자인 (select 시 나타나는 동그라미) */
&::after {
content: "";
display: block;
height: 1.3rem;
width: 1.3rem;
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: $color-primary;
opacity: 0;
transition: opacity 0.2s;
}
}
/* Sibling을 통해 input이 check 속성이 되었을 때 그 속성을 넘겨받는다 */
&__radio-input:checked ~ &__radio-label &__radio-button::after {
opacity: 1;
}
}
오늘은 집중이 잘 안 돼서 코드보다는 웹 포트폴리오 구상에 집중했다. 처음에는 이력서 양식을 계승한 포트폴리오를 만드려고 헀는데, 그럼 그냥 이력서를 pdf로 보는게 낫지 웹사이트로 보는 게 무슨 의미가 있지? 이런 생각이 들어서 색다른 시도를 해보기로 헀다. 인터렉티브까지는 되지 않더라도 최대한 playground처럼 꾸며보기로 했다. 나 자신을 표현하는 공간 그 자체로. 단순한 이력서가 아니라.
일단 구상하면서 도메인도 구매해놔야겠다.