数値を入力しただけだと地味なので、断面形状を描画できるようにしたい。
さっそくChatGPTに相談してみる。
reactのフロントエンドアプリを作っており、図形を描画したい旨をいろいろ聞いてみたら、下記のようなコードを提案された。
import React, { useState } from 'react'; const LineDrawer = () => { const [startX, setStartX] = useState(50); const [startY, setStartY] = useState(50); const [endX, setEndX] = useState(150); const [endY, setEndY] = useState(150); const [lines, setLines] = useState([]); const addLine = () => { const newLines = [ ...lines, { startX, startY, endX, endY, id: Date.now() }, ]; setLines(newLines); }; return ( <div> <div> <label htmlFor="startX">Start X:</label> <input type="number" id="startX" value={startX} onChange={(e) => setStartX(Number(e.target.value))} /> </div> <div> <label htmlFor="startY">Start Y:</label> <input type="number" id="startY" value={startY} onChange={(e) => setStartY(Number(e.target.value))} /> </div> <div> <label htmlFor="endX">End X:</label> <input type="number" id="endX" value={endX} onChange={(e) => setEndX(Number(e.target.value))} /> </div> <div> <label htmlFor="endY">End Y:</label> <input type="number" id="endY" value={endY} onChange={(e) => setEndY(Number(e.target.value))} /> </div> <button onClick={addLine}>Add Line</button> <div style={{ position: 'relative', width: '500px', height: '500px', border: '1px solid black' }}> {lines.map(line => ( <svg key={line.id}> <line x1={line.startX} y1={line.startY} x2={line.endX} y2={line.endY} style={{ stroke: 'black', strokeWidth: 2 }} /> </svg> ))} </div> </div> ); }; export default LineDrawer;
なるほど。最初はcanvasか何かを使うのかなと思ったけど、コンポーネントでsvgを作ってしまえばいいのか。
念のために聞いてみる。
reactで描画を行おうと思います。canvasを使うのとsvgを使うのどちらのほうが良いですか?
canvasとSVGのどちらを使うかは、具体的な描画の内容や目的によって異なります。
Canvasは、ピクセル単位で描画を行うため、複雑なグラフィックスやアニメーションを作成するのに適しています。例えば、ゲームや高度なグラフの描画に利用されます。一方で、Canvasは描画された要素を構造化していないため、アクセシビリティやSEOには不向きです。
SVGはベクター形式で描画を行うため、拡大縮小しても画質が劣化しません。また、SVG要素はHTML要素として直接記述できるため、テキストベースの編集やスタイリングが容易です。SVGはアニメーションやグラフィックスを描画する際にも利用されます。SEOやアクセシビリティにも配慮しやすいです。
どちらを選択するかは、以下のような点を考慮して決定できます:
- 描画内容の複雑さ: 複雑なグラフィックスやアニメーションを行う場合はCanvasが適しています。
- 拡大縮小の必要性: 描画物を拡大縮小したい場合はSVGが有利です。
- 構造化とスタイリング: HTML要素として構造化して扱いたい場合はSVGが使いやすいです。
- アクセシビリティとSEO: テキストベースの要素として扱いたい、またはSEOやアクセシビリティを重視する場合はSVGが適しています。
どちらを選んでも、ReactではCanvasやSVGを簡単に扱うことができますので、プロジェクトの要件に合わせて適切なものを選択してください。
そんな複雑な図形は書かないので、svgでいいかな。
ということで最初のコード例を参考に以下の様に構成してみた。
以上をもとに下記のようなコンポーネントを作って、作成してみたところ、無事に断面形状が表示された。
DrawSection.tsx
import React from "react"; import { SecFlatBar } from "@st-func/st-func-ts"; import { Unit } from "@st-func/st-func-ts"; export class LineData { x1: number; y1: number; x2: number; y2: number; constructor(x1: number, y1: number, x2: number, y2: number) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; } } export interface DrawLinesProps { width: number; height: number; lines: LineData[]; } export const DrawLines: React.FC<DrawLinesProps> = ({ width, height, lines, }) => { return ( <svg width={width} height={height}> {lines.map((line) => { return ( <line x1={line.x1} y1={line.y1} x2={line.x2} y2={line.y2} stroke="black" /> ); })} </svg> ); }; export function flatBarLines(secFlatBar: SecFlatBar): LineData[] { const lines: LineData[] = []; const t = Unit.output(secFlatBar.t, "mm"); const b = Unit.output(secFlatBar.b, "mm"); lines.push(new LineData(0, 0, t, 0)); lines.push(new LineData(t, 0, t, b)); lines.push(new LineData(t, b, 0, b)); lines.push(new LineData(0, b, 0, 0)); return lines; }
とりあえず作った感なので、次回はもう少しコードをブラッシュアップしていきたい。