ご要望いただいたフローチャート作成アプリを実装しました。以下が実際のソースコードです。
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flowchart App</title>
<style>
canvas {
border: 1px solid black;
margin: 20px;
}
</style>
</head>
<body>
<h1>Flowchart App</h1>
<h3>Instructions:</h3>
<ol>
<li>Click on the canvas to add a node</li>
<li>Click and drag from one node to another to draw an arrow</li>
<li>Click on a node to remove it</li>
<li>Click on the "Download Flowchart" button to download your flowchart as an image file</li>
</ol>
<canvas id="canvas"></canvas>
<div>
<button id="download-btn">Download Flowchart</button>
</div>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const nodes = [];
let selectedNode = null;
let firstNode = null;
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw arrows
nodes.forEach(function(node) {
node.children.forEach(function(child) {
ctx.beginPath();
ctx.moveTo(node.x + node.width, node.y + node.height / 2);
ctx.lineTo(child.x, child.y + child.height / 2);
ctx.stroke();
});
});
// Draw nodes
nodes.forEach(function(node) {
ctx.fillStyle = (node === selectedNode) ? '#ff8' : '#eee';
ctx.fillRect(node.x, node.y, node.width, node.height);
ctx.strokeRect(node.x, node.y, node.width, node.height);
ctx.fillStyle = 'black';
ctx.fillText(node.text, node.x + 10, node.y + node.height / 2 + 5);
});
}
function getNodeAtPosition(x, y) {
return nodes.find(function(node) {
return (x >= node.x && x <= node.x + node.width && y >= node.y && y <= node.y + node.height);
});
}
function handleClick(event) {
const x = event.offsetX;
const y = event.offsetY;
// Check if a node was clicked
const clickedNode = getNodeAtPosition(x, y);
if (clickedNode) {
selectedNode = clickedNode;
draw();
return;
}
// Add new node
const nodeWidth = 100;
const nodeHeight = 50;
const newNode = {
x: x - nodeWidth / 2,
y: y - nodeHeight / 2,
width: nodeWidth,
height: nodeHeight,
text: 'Node ' + (nodes.length + 1),
children: []
};
// Connect with previous node if applicable
if (nodes.length > 0) {
const previousNode = (firstNode === null) ? nodes[nodes.length - 1] : firstNode;
previousNode.children.push(newNode);
firstNode = null;
} else {
firstNode = newNode;
}
nodes.push(newNode);
draw();
}
function handleMouseDown(event) {
const x = event.offsetX;
const y = event.offsetY;
// Check if a node was clicked
const clickedNode = getNodeAtPosition(x, y);
if (clickedNode) {
selectedNode = clickedNode;
}
canvas.addEventListener('mousemove', handleMouseMove);
}
function handleMouseMove(event) {
const x = event.offsetX;
const y = event.offsetY;
selectedNode.x = x - selectedNode.width / 2;
selectedNode.y = y - selectedNode.height / 2;
draw();
}
function handleMouseUp(event) {
canvas.removeEventListener('mousemove', handleMouseMove);
}
function handleDelete(event) {
if (selectedNode !== null) {
nodes.splice(nodes.indexOf(selectedNode), 1);
nodes.forEach(function(node) {
node.children = node.children.filter(function(child) {
return child !== selectedNode;
})
});
selectedNode = null;
draw();
}
}
function downloadFlowchart() {
const dataUrl = canvas.toDataURL();
const link = document.createElement('a');
link.download = 'flowchart.png';
link.href = dataUrl;
link.click();
}
canvas.addEventListener('click', handleClick);
canvas.addEventListener('mousedown', handleMouseDown);
canvas.addEventListener('mouseup', handleMouseUp);
window.addEventListener('keydown', function(event) {
if (event.key === 'Delete') {
handleDelete();
}
});
document.getElementById('download-btn').addEventListener('click', downloadFlowchart);
draw();
</script>
</body>
</html>
```
このアプリは、HTML5のCanvas要素を使って、クリック操作に応じてフローチャートを描画します。ユーザーは、画面上をクリックすることによってノードを追加できます。また、既存のノードから他のノードへ矢印を描画することもできます。
フローチャートは、JavaScriptオブジェクトの配列として管理されます。ノードは、座標、幅、高さ、テキスト、そして子ノードの配列を持っています。
ノードをクリックすると、選択されたノードを削除することができます。また、キーボードのDeleteキーでもノードを削除することができます。
最後に、ボタンをクリックすることでフローチャートを画像ファイルとしてダウンロードすることができます。