캔버스와javascript를 사용하여 상호작용 도형 그리기
39742 단어 webdevtutorialjavascript
그러나 이것은 d3에 관한 게시물이 아니라 Canvas를 이용하여 화면에 그림을 그리는 것에 관한 것이다.더 구체적으로 말하자면, 우리는 그림에서 일련의 연결된 노드를 그려서 이 노드를 드래그할 수 있기를 바란다.시작합시다!
그래픽 노드
우리가 해야 할 첫 번째 일은 화포를 설치하는 것이다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Map</title>
<link rel="stylesheet" href="index.css">
<script defer type="text/javascript" src="load.js"></script>
</head>
<body>
<canvas></canvas>
</body>
</html>
/** index.css */
:root {
--root-font-size: 12px;
--bg: #fafafa;
}
/** 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;
}
지금 우리의javascript.⬇️ 우선, 우리는 우리가 그리고자 하는 노드 그룹을 보존해야 한다.노드는 x, y, 반경, 채우기, 획으로 구성됩니다.우리가 이 속성을 그릴 때, 그것들은 화포api 방법에 대응합니다.const canvas = document.querySelector('canvas');
const context = canvas.getContext('2d');
var nodes = [];
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.onresize = resize;
resize();
지금 우리는 계속 drawNode
함수를 추가합니다.우리는 arc 함수를 사용하여 원의 점, 반경, 각도를 그릴 것이다.우리는 또한 fill, stroke의 렌더링 상하문도 처리한다.우리가 호로 원을 생성하기 때문에, 우리는 전체 형상을 하나의 Path에 봉인하기를 희망한다. 이것이 바로 우리가 beginPath 함수를 사용하는 이유이다.function drawNode(node) {
context.beginPath();
context.fillStyle = node.fillStyle;
context.arc(node.x, node.y, node.radius, 0, Math.PI * 2, true);
context.strokeStyle = node.strokeStyle;
context.stroke();
context.fill();
}
마우스 기능
상호작용을 원하기 때문에, 사용자가 언제 터치하거나 캔버스를 눌렀는지 추적하는 기능을 추가하고, 커서 위치에 노드를 그립니다.
function click(e) {
let node = {
x: e.x,
y: e.y,
radius: 10,
fillStyle: '#22cccc',
strokeStyle: '#009999'
};
nodes.push(node);
drawNode(node);
}
window.onclick = click;
너무 좋아요.현재 우리는 화면에 노드를 그렸지만, 그것을 이동할 방법이 없다.마우스다운 함수의 목표 위치를 이용해서 마우스무브로 물체를 이동할 수 있습니다.
var selection = undefined;
function within(x, y) {
return nodes.find(n => {
return x > (n.x - n.radius) &&
y > (n.y - n.radius) &&
x < (n.x + n.radius) &&
y < (n.y + n.radius);
});
}
function move(e) {
if (selection) {
selection.x = e.x;
selection.y = e.y;
drawNode(selection);
}
}
function down(e) {
let target = within(e.x, e.y);
if (target) {
selection = target;
}
}
function up(e) {
selection = undefined;
}
window.onmousemove = move;
window.onmousedown = down;
window.onmouseup = up;
빈틈 수리
드래그하면 노드가 반복적으로 렌더링됩니다.
읊다, 읊조리다이러한 상황이 발생했을 때 모든 노드를 다시 렌더링할 수 있도록 이 문제를 수정해야 합니다.이를 위해, 우리는draw 코드에 조금
clearRect
을 추가하기만 하면 된다. drawNode
이 아니라,draw라고 부른다.function click(e) {
let node = {
x: e.x,
y: e.y,
radius: 10,
fillStyle: '#22cccc',
strokeStyle: '#009999'
};
nodes.push(node);
draw();
}
function move(e) {
if (selection) {
selection.x = e.x;
selection.y = e.y;
draw();
}
}
function draw() {
context.clearRect(0, 0, window.innerWidth, window.innerHeight);
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i];
context.beginPath();
context.fillStyle = node.fillStyle;
context.arc(node.x, node.y, node.radius, 0, Math.PI * 2, true);
context.strokeStyle = node.strokeStyle;
context.fill();
context.stroke();
}
}
반복 노드를 생성하려면 클릭 및 드래그
이것은 매우 유용하지만, 문제는 우리가 너무 빨리 클릭하면 마우스가 아래로 이동할 때 노드가 나타날 수 있다는 것이다.반대로, 우리가 새 노드를 만들려고 할 때, 이동 이벤트에 의존해서 상태를 지웁니다.
우리는 창문을 버릴 것이다.를 클릭하고 코드를 클릭하는 대신
mousedown
, mouseup
, mousemove
이벤트에 의존하여 선택과 생성 상태를 처리합니다.mouseup
이벤트가 발생했을 때 아무것도 선택하지 않고 이동하지 않으면 새 노드를 만듭니다./** remove the onclick code and update move and up code */
function move(e) {
if (selection) {
selection.x = e.x;
selection.y = e.y;
selection.moving = true;
draw();
}
}
function up(e) {
if (!selection || !selection.moving) {
let node = {
x: e.x,
y: e.y,
radius: 10,
fillStyle: '#22cccc',
strokeStyle: '#009999',
selectedFill: '#88aaaa'
};
nodes.push(node);
draw();
}
if (selection) {
delete selection.moving;
delete selection.selected;
}
selection = undefined;
draw();
}
너무 좋아요.
draw
코드를 닫기selected
상태로 업데이트하면 다음과 같이 채우기를 변경할 수 있습니다.context.fillStyle = node.selected ? node.selectedFill : node.fillStyle;
연결 추가
다음에 우리가 해야 할 일은 이 그림의 일부 가장자리에 있다.우리는 선로를 한 노드에서 다른 노드로 연결할 수 있기를 바란다.이를 위해, 우리는 이제 간단한 선을 사용하고, 이 연결을 정의하는 변수 그룹을 사용할 것이다.
우리가 실현하고자 하는 행동은 다음과 같다.
mousemove, 만약 선택이 있고 마우스를 눌렀다면➡️ 업데이트 선택 x 및 y
마우스를 아래로 눌러 노드 대상을 찾으면 선택이 있으면 선택한 상태를 지우고 선택사항을 대상에 지정하고 선택한 상태를 설정하고 그립니다
마우스를 멈추고 선택하지 않으면 새 노드를 만들고 그리고, 그렇지 않으면 현재 선택이 선택되지 않은 경우 (마우스로 눌렀기 때문에) 선택을 지우고 나중에 그리기
또한 새 노드로 변경을 선택하면 모서리를 만들 수 있습니다
function move(e) {
if (selection && e.buttons) {
selection.x = e.x;
selection.y = e.y;
draw();
}
}
function down(e) {
let target = within(e.x, e.y);
if (selection && selection.selected) {
selection.selected = false;
}
if (target) {
selection = target;
selection.selected = true;
draw();
}
}
function up(e) {
if (!selection) {
let node = {
x: e.x,
y: e.y,
radius: 10,
fillStyle: '#22cccc',
strokeStyle: '#009999',
selectedFill: '#88aaaa',
selected: false
};
nodes.push(node);
draw();
}
if (selection && !selection.selected) {
selection = undefined;
}
draw();
}
이것은 이전의 결과와 거의 같지만, 현재 우리는 선택 상태를 제어할 수 있다.내가 하고 싶은 것은 우리가 모서리를 추가할 수 있다는 것이다. 그러면 현재 선택과 새로운 선택이 새로운 모서리와 선을 만들 수 있다.var edges = [];
function draw() {
context.clearRect(0, 0, window.innerWidth, window.innerHeight);
for (let i = 0; i < edges.length; i++) {
let fromNode = edges[i].from;
let toNode = edges[i].to;
context.beginPath();
context.strokeStyle = fromNode.strokeStyle;
context.moveTo(fromNode.x, fromNode.y);
context.lineTo(toNode.x, toNode.y);
context.stroke();
}
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i];
context.beginPath();
context.fillStyle = node.selected ? node.selectedFill : node.fillStyle;
context.arc(node.x, node.y, node.radius, 0, Math.PI * 2, true);
context.strokeStyle = node.strokeStyle;
context.fill();
context.stroke();
}
}
function down(e) {
let target = within(e.x, e.y);
if (selection && selection.selected) {
selection.selected = false;
}
if (target) {
if (selection && selection !== target) {
edges.push({ from: selection, to: target });
}
selection = target;
selection.selected = true;
draw();
}
}
그렇습니다!지금 우리는 노드 사이에 약간의 경계가 있다!이 글의 후속 글에서 나는 베셀 곡선과 이 곡선 사이에 깔끔하고 매끄러운 삽입값을 만드는 방법, 캔버스api가 여기서 제공하는 기능에 대해 토론할 것이다.
건배!🍻
만약 당신이 이 글을 좋아한다면, 저에게 관심과 마음을 주세요.그리고 그렇게 생각하신다면 저의 유사한 업데이트와 다른 업데이트를 보십시오!
이 canvas 강좌를 좋아하신다면 canvas api에 있는 다른 글을 보십시오.
다시 한 번 감사합니다!🏕
Reference
이 문제에 관하여(캔버스와javascript를 사용하여 상호작용 도형 그리기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/nyxtom/drawing-interactive-graphs-with-canvas-and-javascript-o1j텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)