캔버스와javascript를 사용하여 태그 텍스트 그리기 및 편집

지난주에 나는 줄곧 가지고 놀았다 canvas api.나는 가시화된 것들을 함께 놓고 나의 이전 내용을 훑어보았다. (거기서 나는 유장과 소음 알고리즘을 상세하게 소개했다. 봐라, 나는 그것을 정말 좋아한다.)
내 게임에서 나는 도형 도구에 대한 생각을 정리하고 사용자가 도형 도구에서 필요로 하는 가장 기본적인 것 중 하나는 텍스트를 입력하는 능력이다.이렇게 할 수 있는 방법은 캔버스 드로잉 표면에 HTML을 덮어쓰거나 d3.js 를 사용하는 것을 포함한다.반대로 나는 기존의 캔버스api를 사용하는 간단한 스크립트만 쓰기로 했다.모든 일과 마찬가지로 이 일의 의미는 표면적인 것에 그치지 않는다. 그러나 당신이 단지 일을 시작하고 싶을 뿐이라면, 시작합시다.

프로젝트 설정


먼저 예제 코드를 설정하려면 HTML과 약간의 CSS가 필요합니다.이것은 결코 많지 않지만, 분명히 이것은 출발점이다.
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Map</title>
    <link rel="stylesheet" href="index.css">
    <script type="text/javascript" src="load.js"></script>
</head>
<body>
    <canvas></canvas>
</body>
</html>
단독 css 파일에서 기본적인 리셋 변수와 루트 스타일을 설정했습니다.이것은 결코 완전히 필요한 것은 아니지만, 나는 처음부터 이런 물건들이 있는 것을 좋아한다.
/** index.css */
:root {
    --root-font-size: 12px;
    --bg: #fafafa;
    --text-color: #333333;
}

/** Reset */
html, body, nav, ul, h1, h2, h3, h4, a, canvas {
    margin: 0px;
    padding: 0px;
    color: var(--text-color);
}
html, body {
    font-family: Roboto, -apple-system, BlinkMacSystemFont, 'Segoe UI', Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
    font-size: var(--root-font-size);
    background: var(--bg);
    height: 100%;
    width: 100%;
    overflow: hidden;
}
*, body, button, input, select, textarea, canvas {
    text-rendering: optimizeLegibility;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    outline: 0;
}
최신 CSS에 관해서 내가 매우 좋아하는 점은 네가 어떤 구축 도구도 필요로 하지 않는다는 것이다.네트워크 애플리케이션을 활용하려면 root variables 만 사용하십시오.보통 이런 작은 항목에서 나는 단지 몇 가지 변수만 만들었을 뿐, 나는 아주 잘했다.
실제로 이 변수를 사용하여 CSS에서 도령 논리를 완성하는 방법을 소개하는 좋은 글이 있다.봐라, 작가는 실제로 완전한 지뢰 제거 게임을 사용했다.

캔버스 API


The canvas element creates a fixed-size drawing surface that exposes one or more rendering contexts, which are used to create and manipulate the content shown. In this tutorial, we focus on the 2D rendering context. Other contexts may provide different types of rendering; for example, WebGL uses a 3D context based on OpenGL ES.


다음 내용으로 파일 만들기load.js
/** load.js */
var canvas, context;
var text = [''];

function setup() {
    canvas = document.querySelector('canvas');
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    context = canvas.getContext('2d');
    context.font = '18px Roboto';
}

function draw() {
    /* draw code */
}

window.onresize = function () {
    if (canvas) {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
    }
}

window.onkeypress = function (e) {
}

window.onkeydown = function (e) {
}

window.onload = function () {
    setup();
}
이곳에서 몇 가지 일이 발생했다.우선, 우리는 창이 onload를 통해 불러올 때까지 기다렸다. 이것은 모든 자원이 불러올 때까지 기다렸다는 것을 의미한다.
설정을 호출한 후, 우리는 캔버스를 잡아서 창 높이/너비로 설정합니다.우리는 onresize event를 통해 창의 크기를 조정할 때도 너비/높이를 설정해야 한다.

버튼/아래쪽


이것은 편집기이기 때문에, 우리는 키를 눌렀을 때 내용을 작성하기를 원할 수도 있다.onkeypress와 onkeydown 코드를 다음과 같이 업데이트합니다.
window.onkeypress = function (e) {
    if (e.key === 'Enter') {
        text.push('');
    } else {
        text[text.length - 1] += e.key;
    }
    draw();
}

window.onkeydown = function (e) {
    if (e.key === 'Backspace' && text.length && text[0].length) {
        let txt = text[text.length - 1];
        txt = txt.slice(0, txt.length - 1);
        text[text.length - 1] = txt;
        if (!txt.length && text.length > 1) {
            text = text.slice(0, text.length - 1);
        }
    }
    draw();
}
이러한 기능은 우리의 텍스트 상태를 효과적으로 관리할 것이다.그것은 결코 전면적이지 않지만, 현재 우리는 텍스트 그룹을 바꾸기 위해 입력을 하고 리턴/체크아웃을 누르는 등 기본적인 일을 할 수 있다.

그림을 그리다


코드를 그리기 시작합시다.우리가 캔버스에 있을 때, 다른 그림을 바꾸기 전에 화면을 지우는 것이 가장 좋다.시각화와 생성 예술에서 당신은 기존의 창조를 이용하여 깔끔한 효과를 낼 수 있다.그러나 모든 버튼에 텍스트를 그려서 업데이트하기 때문에 화면을 지우고 내용을 새로 고치려고 합니다.
function draw() {
    context.clearRect(0, 0, window.innerWidth, window.innerHeight);

    let offset = 0;
    let totalHeight = 0;
    let height = (18 * 1.5); // font * line height

    let items = text.map(txt => {
        let width = context.measureText(txt).width;
        let item = {
            txt,
            width,
            offset
        };
        offset = offset + height;
        totalHeight += height;
        return item;
    });

    let cY = (window.innerHeight / 2) - (totalHeight / 2);
    items.forEach(item => {
        let x = window.innerWidth / 2 - item.width / 2;
        let y = item.offset + cY;
        context.fillText(item.txt, x, y);
    });
}

위의 코드에서 우리는 canvasapimeasureText를 사용한다.만약 우리가 텍스트를 더욱 정확하게 측정하고 싶다면, getBoundingBoxClientRect 을 사용하여 텍스트를 다른dom 요소로 마운트할 수 있습니다.나는 지금 캔버스 방법을 선택했다. 왜냐하면 우리는 최종적으로 아래의 렌더링 상하문을 이용하여 추가 측정을 할 것이다.
어떠한 상황에서도 우리는 가장 작은 텍스트 입력을 가지고 있으며, 여러 줄과 체크아웃을 지원한다.계속합시다!

가격 인하


이것은 가격 인하 편집기이기 때문이다.규범으로서 가격 인하는 상당히 작지만, 우리는 한 문장에서 모든 내용을 토론하지 않을 것이다.나는 당신에게 이것에 대해 상세하게 소개하라고 할 것이지만, 지금 우리는 규범화된 제목 부분만 실현할 것입니다.
이를 위해, 우리는 텍스트 줄을 해석하고, 필요에 따라 상하문에 대한 호출을 교환해야 한다.
다음 코드를 추가하여 텍스트 줄을 분석합니다
function parse(txt) {
    let lineHeight = 1.5;
    let headingSize = 32;
    let baseSize = 16;
    if (txt.trim().startsWith('#')) {
        let level = txt.match(/\s*\#/g).length;
        let size = headingSize - (level * 4);
        return {
            font: `bold ${size}px roboto`,
            height: size * lineHeight,
            txt
        };
    } else {
        return {
            font: `${baseSize}px roboto`,
            height: baseSize * lineHeight,
            txt
        };
    }
}
그리고 그림 코드에서 그것을 업데이트해서 우리의 해석 함수를 호출합니다.
function draw() {
    context.clearRect(0, 0, window.innerWidth, window.innerHeight);

    let offset = 0;
    let totalHeight = 0;

    let items = text.map(txt => {
        let item = parse(txt);
        item.offset = offset;
        offset = offset + item.height;
        totalHeight += item.height;
        return item;
    });

    let centerY = (window.innerHeight / 2) - (totalHeight / 2);
    items.forEach(item => {
        context.font = item.font;
        let width = context.measureText(item.txt).width;
        let x = window.innerWidth / 2 - width / 2;
        let y = item.offset + centerY;
        context.fillText(item.txt, x, y);
    });
}
measure Text 코드를 실제로 그리기 전에 코드로 옮겼습니다.이것은 우리가 context.font = item.font 를 사용하여 이전 줄의 렌더링 상하문을 변경했기 때문이다.우리는 현재 렌더링 상하문에 따라 정확한 측정을 진행하기를 희망합니다.

결론


여기 있습니다!이것은 매우 기본적이고 가장 작은 것이지만, 이것은 아주 좋은 시작이다.나는 당신에게 더 많은 코드를 써서 규범의 나머지 부분을 완성하도록 남겨 두겠습니다.
예전과 같이, 만약 당신이 이 문장을 좋아한다면, 저에게 좋아하고 따르는 것을 주세요.미래의 글에 대한 어떤 피드백이나 생각을 환영합니다.꼭 비슷한 업데이트 하나 주세요. 따라오세요!
건배!🍺
이 시리즈의 다음 부분을 보는 것을 잊지 마라!

좋은 웹페이지 즐겨찾기