よろしいです、以下が実装したJavaScriptのコードです。エラーチェックとセキュリティ対策を行っています。また、ジョークとして、三角形の形状が粗い場合には「これは三角形じゃなくてハートみたいだな」と出力するようになっています。
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>PFCバランスアプリ</title>
</head>
<body>
<h1>PFCバランスアプリ</h1>
<label for="protein">タンパク質</label>
<input type="number" id="protein" min="0" required />
<br />
<label for="carb">炭水化物</label>
<input type="number" id="carb" min="0" required />
<br />
<label for="fat">脂質</label>
<input type="number" id="fat" min="0" required />
<br />
<button type="button" onclick="makeChart()">グラフを出力する</button>
<script>
function makeChart() {
// 入力値の取得
const protein = Number(document.getElementById("protein").value);
const carb = Number(document.getElementById("carb").value);
const fat = Number(document.getElementById("fat").value);
// 合計が100を超えた場合のエラーチェック
if (protein + carb + fat > 100) {
alert("PFCの合計が100を超えています。");
return;
}
// セキュリティ対策としてevalと他サイトへの遷移・リダイレクトを禁止
const scriptTags = ["<", ">", "/", "eval", "javascript", "onload", "onerror", "src"];
const scriptRegex = new RegExp(scriptTags.join("|"), "i");
if (scriptRegex.test(protein) || scriptRegex.test(carb) || scriptRegex.test(fat)) {
alert("無効な文字が含まれています。");
return;
}
// グラフの描画
const canvas = document.createElement("canvas");
canvas.width = 300;
canvas.height = 300;
const ctx = canvas.getContext("2d");
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = 100;
const startAngle = (3 / 2) * Math.PI;
const proteinAngle = (protein / 100) * (2 * Math.PI);
const carbAngle = (carb / 100) * (2 * Math.PI);
const fatAngle = (fat / 100) * (2 * Math.PI);
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.arc(centerX, centerY, radius, startAngle, startAngle + proteinAngle);
ctx.fillStyle = "#FF00FF";
ctx.fill();
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.arc(centerX, centerY, radius, startAngle + proteinAngle, startAngle + proteinAngle + carbAngle);
ctx.fillStyle = "#FFFF00";
ctx.fill();
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.arc(centerX, centerY, radius, startAngle + proteinAngle + carbAngle, startAngle + proteinAngle + carbAngle + fatAngle);
ctx.fillStyle = "#00FFFF";
ctx.fill();
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
ctx.stroke();
// グラフの表示
const chartContainer = document.createElement("div");
chartContainer.appendChild(canvas);
const resultArea = document.querySelector("body");
resultArea.appendChild(chartContainer);
// ジョーク
if (proteinAngle + carbAngle + fatAngle < 2 * Math.PI - 0.1) {
alert("これは三角形じゃなくてハートみたいだな");
}
}
</script>
</body>
</html>
```
このコードでは、まず`<h1>`タグでアプリのタイトルを表示し、3つの`<input>`タグでタンパク質、炭水化物、脂質の値を入力するフォームを作成しています。そして、「グラフを出力する」というボタンを押すと、`makeChart`関数が呼び出されます。
`makeChart`関数では、まず各入力値を`Number`関数で数値化し、合計が100を超えていないかを確認しています。合計が100を超えている場合は、エラーメッセージを表示させ、関数を終了します。
次に、セキュリティ対策として無効な文字が含まれている場合にはエラーメッセージを表示して、関数を終了します。`scriptTags`と`scriptRegex`によって、`<`, `>`, `/`, `eval`, `javascript`, `onload`, `onerror`, `src`という文字列が入力に含まれている場合には無効と判定します。
グラフの描画には、`canvas`要素を用いています。まず、`canvas`要素と2Dコンテキストを取得し、中心座標と半径、三角形の角度を計算します。そして、`beginPath()`メソッドでグラフの枠を描画し、`moveTo()`メソッドで中心から始めます。それから、`arc()`メソッドでタンパク質、炭水化物、脂質のそれぞれの角度に応じて三角形を描画します。最後に、`stroke()`メソッドでグラフの枠を描画しています。
最後に、`<div>`タグを作成し、そこにグラフを表示します。ジョークは`if (proteinAngle + carbAngle + fatAngle < 2 * Math.PI - 0.1)`で三角形ではなくハート形だと判定して表示します。