20211009のNode.jsに関する記事は4件です。

React メモ

目次 コマンド JSX props 条件分岐と繰り返し処理 Stateとイベント処理 ルーティング 1. コマンド # create-react-appをインストール $ npm install -g create-react-app # 新規作成 $ npx create-react-app [プロジェクト名] # TSX(JSXのTypeScript版)で作りたい時 # --template typescriptをつける $ npx create-react-app --template typescript [プロジェクト名] # 開発サーバー起動 $ npm start # ビルドしてHTML/CSS/JSファイルを生成 $ npm run build 2. JSX classはclassName, forはhtmlForで書く {変数名} の形式で埋め込むことができる index.js(最初に呼び出されるファイル) //React関連のライブラリをインポート import React from 'react'; import ReactDOM from 'react-dom'; //アプリ固有のファイルをインポート import './index.css'; import App from './App'; //キャッシュのためのサービスをインポート import reportWebVitals from './reportWebVitals'; //Appコンポーネントを実行 //render(comp, target) //comp: 出力するコンポーネント //target: 出力先の要素 ReactDOM.render( <App />, document.getElementById('root') ); //サービスを有効化 registerServiceWorker(); コンポーネントファイル //Reactの基本ライブラリをインポート import React, { Component } from 'react'; //ロゴ画像/スタイルシートをインポート import logo from './log.svg'; import './App.css'; //Appコンポーネントを定義 class App extends Component { //描画内容を準備 render() { return ( //class → classNameにすること <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.js</code> and save to reload. </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </a> </header> </div> ); } } //Appクラスをエクスポート export default App; React.Fragment(ダミーの要素) //React.Fragmentは最終的な出力には含まれない ReactDOM.render( <React.Fragment> <p>あいうえお</p> <p>かきくけこ</p> </React.Fragment> , document.getElementById('root'); ); 属性の設定 //属性値前後のクォートは付けない //href="{url}"だとダメ const url = 'https://wings.msn.to/'; <a href={url}>Webサイト</a> //style属性の指定にはオブジェクトを利用する //オブジェクトリテラルではcamelCase記法に直す const style = { color: 'Red', backgroundColor: 'Yellow' }; <p style={style}>あいうえお</p> //属性をまとめて設定 //オブジェクトリテラルと「...」演算子を利用する const attrs = { src: 'http://test/image/aiueo.jpg', alt: 'あいうえお', title: 'テストあいうえお' }; <img {...attrs} /> コンポーネントを入れ子にする import React, { Component } from 'react'; //子コンポーネントをインポート import MyCover from './MyCover'; export default class MyBook extends Component { render() { return ( <div> {/* MyCoverコンポーネントを呼び出し */} <MyCover title={this.props.info.title} /> </div> ) } } 3. props propsとは? 単一のオブジェクトとしてこのコンポーネントに渡すオブジェクトのこと。 JSX内で使用する属性情報、子要素を渡すことができる。 //コンポーネント側 import React, { Component } from 'react'; export default class MyHello extends Component { //プロパティを元に出力を生成 render(){ return <div>こんにちは、{this.props.name}さん</div>; } } //index.js import MyHello from './MyHello'; ... ReactDOM.render( //MyHelloコンポーネントにプロパティを引き渡す //この場合は「name」を渡す <MyHello name="鈴木" />, document.getElementById('root'); ); 「...」演算子を使用することで、オブジェクトの内容を個々の属性にばらすことも可能。 const data = { name: '鈴木', age: 18, sex: '男' }; ReactDOM.render( <MyClass {...data} />, document.getElementById('root') ); 4. 条件分岐と繰り返し処理 条件分岐 「?:」演算子、「&&」演算子 「?:」演算子は、三項演算子のような使い方 「&&」演算子は、trueの時だけ出力される //「?:」演算子 { this.props.isNew ? <MyNew /> : null } //「&&」演算子 { this.props.isNew && <MyNew /> } 即時関数 //関数を使う //見栄えが悪くなるので、なるべく先に名前付きで関数を作って、それを利用するようにする {(() => { if(this.props.isNew){ return <MyNew /> } })()} 繰り返し処理 Array#mapメソッドを利用する const data = [ { name: '鈴木', age: 18, sex: '男', userid=1 }, { name: '佐藤', age: 20, sex: '女', userid=2 }, }; //index.js ReactDOM.render( //配列dataを使っての繰り返し処理 <div> {data.map((x) => <MyClass {...x} />)} </div> ) //keyプロパティを持たないことによる警告対処のため //以下のようにkey属性を持つことを推奨 //主キーを持たない場合はkey={index}とするのもOK //<MyClass {...x} key={x.userid} /> 5. Stateとイベント処理 Stateとは? コンポーネントの状態(state)を管理するオブジェクト。 stateの値を更新する場合は、setStateを使用する export default class MyState extends Component { constructor(props) { super(props); //Stateの初期値を設定 this.state = { current: new Date() } } //1000ミリ秒おきにStateを更新 //setStateを使用する setInterval(() => { this.setState({ current: new Date() }); }, 1000) render() { //currentの値をページに反映 <div>{this.state.current.toLocaleString()}</div> } } イベント処理 HTMLではonchange(全て小文字)だが、JSXではonChange(cameCase形式)で書く this.関数名.bindでイベント実行時の関数を指定(bindを付けないとエラーになる) //onchangeイベントを起こす <input id="txtName" type="text" onChange={this.show.bind(this)} /> //アロー関数で指定する場合 <input id="txtName" type="text" onChange={(e) => this.show(e)} //引数を渡す場合 show(end, e) { console.log(`${e.target.value}${end}`); } ... //元々のイベントオブジェクトは、引数リストの末尾に渡される //end => 'さん' //e => this //がそれぞれわたされる <input id="txtName" type="text" onChange={this.show.bind(this, 'さん')} /> ライフサイクルメソッド 後で書く 6. ルーティング ルーティング機能用のライブラリとしてReact Routerがある # React Routerをインストール $ npm install --save react-router-dom ルーティングのサンプル ルーティング設定は<Route>で定義する <Switch>で括っているのは、最初に合致した要素だけ出力する、という意味 exact属性は、完全一致で判定するという意味 ルーティング経由でのページ遷移は、<Link>で定義する import React, { Component } from 'react'; //ルーティング関連の機能をインポート import { BrowserRouter as Router, Link, Route, Switch } from 'react-router-dom'; //ルーティングで利用するコンポーネントをインポート import MyTop from './MyTop'; import MyHello from './MyHello'; import MyArticle from './MyArticle'; export default class App extends Component { render() { //Router(BrowserRouter)でルーティング機能を有効化 return( <Router> <div> {/* ルーティング経由のリンクリストを準備 */} <ul> <li><Link to="/">トップ</Link></li> <li><Link to="/hello">Hello</Link></li> <li><Link to="/article">公開記事</Link></li> </ul> <hr /> {/* ルーティング設定(条件にマッチしたコンポーネントを出力) */} <Switch> <Route exact path="/" component={MyTop} /> <Route path="/hello" component={MyHello}/> <Route path="/article" component={MyArticle}/> </Switch> </div> </Router> ) } } ルートパラメータ //リンク <Link to="/article/13">記事13</Link> //ルートパラメーターを含んだルート <Route path="/article/:id" component={MyArticle} /> //コンポーネント側でルートパラメータを受け取る //this.props.match.params.名前で受け取ることが可能 const id = this.props.match.params.id; 補足 <Route>にてpathを書かない場合、全てのURLにマッチする、という書き方ができる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

package.jsonとpackage-lock.jsonのバージョン指定や必要性について

はじめに 業務内でpackage.jsonやpackage-lock.jsonを使う機会があり、学んだことをまとめる。 Node.jsとnpm メインの話ではないので細かい説明は省略。 ・Node.js Node.jsは、「JavaScriptの実行環境」。Node.jsを使うことで、サーバー側でJavaScriptを使うことが出来るようになる。 ・npm npmは、Node Package Manuagerの略でNode.jsのパッケージ管理ツール。 詳しい説明はこちらを→Node.jsとはなにか?なぜみんな使っているのか? npmはNode.jsをインストールする際に一緒にインストールされる。 package.jsonとpackage-lock.jsonについて Semantic Version Semantic Versionとは、バージョン番号を付けるにあたり決めたルールのこと。 細かい仕様については、下記サイトでまとまっている。 セマンティック バージョニング 2.0.0 Node.jsでは、このSemantic Versioning(semver)に従ってバージョン表記をしている。 semverでは、以下のようにX.Y.Zのように3つの数字で表される。 X:major version 後方互換性のない変更 Y:minor version 後方互換性のある変更 Z:patch version 後方互換性のあるバグ修正など メジャーバージョンが上がると、マイナーバージョンとパッチバージョンの値は0となる。 マイナーバージョンが上がると、パッチバージョンの値は0となる。 メジャーバージョンは後方互換性がない変更であるため、その点注意する必要がある。 例) "devDependencies": { "bootstrap": "^4.0.0" } この例の場合は、bootstrapパッケージでメジャーバージョンが4、マイナーバージョンと、パッチバージョンが0という風に対応している。 ただ、注意する点として先頭についている^(キャレット)がある場合は、あるルールにのっとってその範囲内のバージョンへのアップデートを許容する。 ^(キャレット) 上記の例でもあったようにバージョン指定する際に、"bootstrap": "^4.0.0"のように記載してあることがある。この先頭についているものが^(キャレット)である。 キャレットについて、npm Docsに以下のような説明があります。 Caret Ranges ^1.2.3 ^0.2.5 ^0.0.4 Allows changes that do not modify the left-most non-zero digit in the [major, minor, patch] tuple. 引用元:semver 翻訳すると、 [major, minor, patch]タプルの左端のゼロ以外の数字を変更しない変更を許可します 。 どういうことか実際にいくつかの例をもとに説明する。 ^1.2.3の場合 一番左端のゼロ以外の数字はメジャーバージョンを示す1。そのため、メジャーバージョンを変更しないようなアップデートを許容する。 ここでのバージョンアップ許容範囲は、 1.2.3 <= N < 2.0.0となる。 0.2.3の場合 一番左端のゼロ以外の数字はマイナーバージョンを示す2。そのためメジャーバージョンとマイナーバージョンを変更しないようなアップデートを許容する。 ここでのバージョンアップ許容範囲は、0.2.3 <= N < 0.3.0となる。 0.0.3の場合 一番左端のゼロ以外の数字はパッチバージョンを示す3。そのため、ここでのバージョンアップ許容範囲は、0.0.3 <= N < 0.0.4となる。 ~(チルダ) キャレットの他にもバージョン範囲指定がいくつかありその中に~(チルダ)がある。 npm Docsに以下のような説明があります。 Tilde Ranges ~1.2.3 ~1.2 ~1 Allows patch-level changes if a minor version is specified on the comparator. Allows minor-level changes if not. 翻訳すると、 コンパレータでマイナーバージョンが指定されている場合、パッチレベルの変更を許可します。そうでない場合は、マイナーレベルの変更を許可します。 どういうことか実際にいくつかの例をもとに説明する。 ~1.2.3の場合 この場合は、マイナーバージョン部分の2が指定されているため、パッチレベルのアップデートを許容する。バージョンアップ許容範囲は、1.2.3 <= N < 1.3.0となる。 ~1.2の場合 この場合は、マイナーバージョン部分の2が指定されているため、パッチレベルのアップデートを許容する。バージョンアップ許容範囲は、1.2.3 <= N < 1.3.0となる。 ~1の場合 この場合は、マイナーバージョンが指定されていないため、マイナーバージョンのアップデートを許容する。バージョンアップ許容範囲は、1.0.0 <= N < 2.0.0となる。 参考 package.jsonのパッケージバージョンに記載される ^ (キャレット) とは?どうしてつくのか? セマンティック バージョニング 2.0.0 Semantic Versioning おさらい semver(npm Docs) package-lock.jsonの必要性 今回学習初期段階のイメージとしては、package.jsonに記述してあるバージョンを入れて、入れたバージョン情報などがpackage-lock.jsonに自動的に記述されるだけという感じだった(不十分)。 しかし、先ほどのSemantic Versionでも触れたようにpackage.jsonでは入れるバージョンをある程度の範囲で指定することができる。そのため、実際にパッケージをインストールするタイミングによってはパッケージのバージョンが異なってしまうという問題がある。 チーム内で同じ環境を構築したい場合、バージョンが異なってしまうと困る。 このインストールするバージョンを固定するために必要なのが、package-lock.jsonである。 npm installを実行する際、package-lock.jsonがない場合はpackage.jsonに従ってパッケージがインストールされますが、package-lock.jsonがある場合は基本的にはpackage-lock.jsonのバージョンで固定してインストールすることが出来る。 これを自分は知らなかったため、最初インストールしたバージョンが他の環境と異なってしまうという問題に遭遇した。 これらのことから、どちらのファイルも非常に重要であるためもしGit管理する場合はどちらもコミットする必要がある。 また、npm installの具体的な挙動として以下のようになっているとのこと。 npm v6.9.0 時点ではnpm installの具体的な挙動は次のようになっている。 ・package-lock.jsonが存在しないとき package.jsonに基づいて dependency がインストールされ、実際にインストールされたバージョンがpackage-lock.jsonに書かれる。 ・package-lock.jsonが存在するとき package-lock.jsonに基づいてインストールされるが、package.json指定されたバージョンとの矛盾があれば、package.jsonが優先され、実際にインストールされたバージョンがpackage-lock.jsonに書かれる。 引用元:【初心者向け】NPMとpackage.jsonを概念的に理解する package.jsonとpackage-lock.jsonの指定バージョンに矛盾があった場合は、package.jsonが優先されるとのことなのでこの点注意したい。 参考 package.jsonとpackage-lock.jsonの運用方法について まとめ 今回は、package.jsonとpackage-lock.jsonのバージョン指定や必要性について簡単にまとめた。 まだまだ、理解が不十分であるため引き続き理解を深めていきたいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

node.jsでchart.jsを使う

expressを使ったWebAPIでグラフの画像を生成したかったので、Javascsriptで有名なchart.jsをNode.jsで動かすnpmモジュール「chartjs-node-canvas」を使いこなします。 以下の点を意識しています。 ・Node.jsでchart.jsを動かす場合も日本語がちゃんと表示されるようにする ・chart.jsの凡例やデータの指定方法がグラフの種類によってまちまちなのを統一する ・背景に色を塗ったり、前景全体に文字列を重ね合わせられるようにする 上記をクラス化して、使いやすい形にしていきます。 ソースコードもろもろは、GitHubに上げておきました。 poruruba/MakeChart_test ※node-fetchは、v2系を使った方がよいかも。 > npm install node-fetch@2.6.5 <参考URL> ・https://www.chartjs.org/docs/latest/ ・https://github.com/SeanSobey/ChartjsNodeCanvas/blob/master/API.new.md ・https://github.com/SeanSobey/ChartjsNodeCanvas ・https://github.com/shrhdk/text-to-svg chartjs-node-canvasのインストール 基本的には以下で説明の通りに実施します。 SeanSobey/ChartjsNodeCanvas > npm install chartjs-node-canvas chart.js@2.9.4 chart.jsは、v2系の情報が世の中に多いので、2系の最新バージョンにしています。 あとは、説明の通りに進めればよいのですが、このままでは日本が表示されません。 タイトルや凡例、ラベルなどで使われます。そこで、日本語フォントを登録します。 IPAフォントを使わせていただきました。 IPAexゴシック:ipaexg00401.zipをダウンロードし、適当な場所に解凍します。 解凍する出てく308Bipaexg.ttfというファイルを使います。 api\controllers\makechart-api\genchart.js const FONT_PATH = '【フォントを配置したフォルダ】' + '/ipaexg.ttf'; const FONT_NAME = "IPAEXG"; const FONT_COLOR = "#333333aa"; const { ChartJSNodeCanvas } = require('chartjs-node-canvas'); const chartJSNodeCanvas = new ChartJSNodeCanvas({ width: width, height: height, chartCallback: (ChartJS) => { ChartJS.defaults.global.defaultFontFamily = FONT_NAME; ChartJS.defaults.global.defaultFontColor = FONT_COLOR; } }); chartJSNodeCanvas.registerFont(FONT_PATH, { family: FONT_NAME }); widthとheightには、生成したいグラフ画像のサイズを指定します。 FONT_COLORは、文字の色および透過率を指定しています。お好みで変更してください。 グラフのテンプレートを作る あまり深いことを気にせずに作れるように、6種類ほどのグラフをテンプレート化しておきます。 そうすることで、たくさんあるchart.jsのオプション群を毎回思い出す必要がなくなるのと、最初に述べた通り、凡例とデータの並びに統一性を持たせたいためです。 以下6種類のテンプレートを作ります。 名称 種類 doughnut タコメータのようなもの gauge 横棒ゲージのようなもの line 折れ線グラフ pie 円グラフ stackbar 積み上げ棒グラフ bar 棒グラフ 以降は、テンプレート化後のパラメータ指定方法を示しますが、chart.jsの指定への変換内容は、今回作成したクラスのソースファイルをご参照ください。 タコメータのようなもの 必須 名前1 名前2 内容 備考 〇 value 値 legend 凡例 指定がない場合表示されない title タイトル 指定がない場合表示されない 〇 range max 最大値 100%となる値 例 { "value": 10, "legend": "凡例1", "title": "チャートタイトル", "range": { "max": 50 } } 横棒ゲージのようなもの 必須 名前1 名前2 内容 備考 〇 value 値 legend 凡例 指定がない場合表示されない title タイトル 指定がない場合表示されない 〇 range min 最小値 0%となる値 〇 max 最大値 100%となる値 例 { "value": 10, "legend": "凡例1", "title": "チャートタイトル", "range": { “min”: 0, "max": 50 } } 折れ線グラフ 必須 名前1 名前2 内容 備考 〇 datum 値の2次元配列 〇 labels ラベルの配列 legends 凡例の配列 指定がない場合表示されない title タイトル 指定がない場合表示されない range min 最小値 Y軸の最小値 max 最大値 Y軸の最大値 例 { "datum": [ [880, 740, 900, 520, 930], [380, 440, 500, 220, 630] ], "labels": ["1月", "2月", "3月", "4月", "5月"], "legends": ["プリンター販売台数", "パソコン販売台数"], "range": { "min": 0, "max": 1000 }, "title": "チャートタイトル" } 円グラフ 必須 名前1 名前2 内容 備考 〇 datum 値の配列 legends 凡例の配列 指定がない場合表示されない title タイトル 指定がない場合表示されない 例 { "datum": [880, 740, 100], "legends": ["OK", "NG", "UNKNOWN"], "title": "チャートタイトル" } 積み上げ棒グラフ 必須 名前1 名前2 内容 備考 〇 datum 値の2次元配列 〇 labels ラベルの配列 〇 legends 凡例の配列 title タイトル 指定がない場合表示されない 例 { "datum": [[1, 4], [5, 0], [3, 2], [4, 1]], "labels": ["pc1", "pc2", "pc3", "pc4"], "legends": ["OK", "NG"], "title": "チャートタイトル" } 棒グラフ 必須 名前1 名前2 内容 備考 〇 datum 値の配列 〇 labels ラベルの配列 title タイトル 指定がない場合表示されない range min 最小値 Y軸の最小値 max 最大値 Y軸の最大値 例 { "datum": [1, 2, 3, 5, 2], "labels": ["1月", "2月", "3月", "4月", "5月"], "title": "チャートタイトル", "range": { "min": 0 } } グラフ画像を生成する widthとheightに画像サイズを指定します。 typeは、先ほどの6種類の名称(doughnut, gauge, line, pie, stackbar, bar)です。 paramsはグラフの種類ごとに指定する値です。 mimetypeは画像のフォーマットを指定します。例えば、”image/png”。 api\controllers\makechart-api\genchart.js async makeChart(width, height, type, params, mimetype){ const chartJSNodeCanvas = new ChartJSNodeCanvas({ width: width, height: height, chartCallback: (ChartJS) => { ChartJS.defaults.global.defaultFontFamily = FONT_NAME; ChartJS.defaults.global.defaultFontColor = FONT_COLOR; } }); chartJSNodeCanvas.registerFont(FONT_PATH, { family: FONT_NAME }); var configuration; switch(type){ case 'doughnut': { configuration = make_chart_doughnut(params.value, params.legend, params.title, params.range); break; } case 'gauge': { configuration = make_chart_gauge(params.value, params.legend, params.title, params.range); break; } case 'line': { configuration = make_chart_line(params.datum, params.labels, params.legends, params.title, params.range); break; } case 'pie': { configuration = make_chart_pie(params.datum, params.legends, params.title); break; } case 'stackbar': { configuration = make_chart_stackbar(params.datum, params.labels, params.legends, params.title, params.range); break; } case 'bar': { configuration = make_chart_bar(params.datum, params.labels, params.title, params.range); break; } default:{ throw 'unknown type'; } } return chartJSNodeCanvas.renderToBuffer(configuration, mimetype); } 背景に色を塗ったり、前景全体に文字列を重ね合わせられるようにする 前景全体に文字列を重ね合わせます。 文字列の画像生成には、npmモジュールの「text-to-svg」を使わせていただきました。背景色の生成や画像の合成には、npmモジュールの「sharp」をつかわせていただきました。 > npm install text-to-svg > npm install sharp 文字列画像の生成 chartjs-node-canvasの時と同様に、日本語も表示できるように、日本語フォントを設定します。 api\controllers\makechart-api\genchart.js const TextToSVG = require("text-to-svg"); const FONT_PATH = '【フォントを配置したフォルダ】' + '/ipaexg.ttf'; const textToSVG = TextToSVG.loadSync(FONT_PATH); あとは、文字列を引数にしてgetSVGを呼び出せばよいのですが、画像サイズいっぱいに表示したいため、フォントサイズを動的に決定するようにしています。 api\controllers\makechart-api\genchart.js const CAPTION_FONT_SIZE = 72; const CAPTION_PADDING = 20; makeCaption(width, height, caption){ var fontSize = Math.min(CAPTION_FONT_SIZE, width / caption.length); var svgOptions = { x: 0, y: 0, anchor: "left top", attributes: { fill: FONT_COLOR } }; do { svgOptions.fontSize = fontSize; var metrics = textToSVG.getMetrics(caption, svgOptions); if (metrics.width <= width * (100 - CAPTION_PADDING) / 100 && metrics.height <= height * (100 - CAPTION_PADDING) / 100) break; fontSize -= 2; if( fontSize <= 0 ) throw 'unknown error'; } while (true); return textToSVG.getSVG(caption, svgOptions); } 最後に、グラフ画像に対して、背景色と前景文字列をマージします。sharpの機能を活用します。 背景色の画像は、SVGを使って生成しています。 場合によっては、背景色だけつけたい場合、前景文字列だけつけたい場合、いずれも不要な場合があると思いますので、切り替えられるようにしています。 api\controllers\makechart-api\genchart.js async generateChart(width, height, type, chart_params, caption, bgcolor){ var chart_image = await this.makeChart(width, height, type, chart_params, "image/png"); var caption_image; if( caption ) caption_image = Buffer.from(this.makeCaption(width, height, caption)); var image_buffer; if( bgcolor ){ var background_svg = `<svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg"> <path d="M0 0 L ${width} 0 L ${width} ${height} L 0 ${height}" style="fill:${bgcolor}; stroke-width:0" /> </svg>`; var comps = []; comps.push({ input: chart_image }); if( caption_image ) comps.push({ input: caption_image, gravity: "center" }); image_buffer = await sharp(Buffer.from(background_svg)) .composite(comps) .png() .toBuffer(); }else if( caption_image ){ image_buffer = await sharp(chart_image) .composite([{ input: caption_image, gravity: 'center' }]) .png() .toBuffer(); }else{ image_buffer = chart_image; } return image_buffer; } クラスの使い方 結局は、クラス化で、こんな感じで使えるようにしました。 api\controllers\makechart-api\index.js var image_buffer = await genchart.generateChart(body.width, body.height, body.type, body.chart_params, body.caption, body.bgcolor); WebAPI使用例 HTTP GETまたはHTTP Post(Json)で、グラフ画像(image/png)が返ってくるWebAPIを作成してみました。 以下の3種類を用意しました。GETの呼び出して呼び出せるようにしています。 Endpoint名:/makechart-inspect netdataのグラフ画像 Ping応答チェッカー マシンのメモリ使用状況 また、POST(Json)呼び出して、データやタイトルやらすべて呼び出し側で指定して画像取得することもできるようにしています。 Endpoint名:/makechart-generate まとめるとこんな感じです。 api\controllers\makechart-api\index.js 'use strict'; const HELPER_BASE = process.env.HELPER_BASE || '../../helpers/'; const BinResponse = require(HELPER_BASE + 'binresponse'); const { URLSearchParams } = require('url'); const fetch = require('node-fetch'); const genchart = require('./genchart'); const ping = require('ping'); const osu = require('node-os-utils'); const PING_TIMEOUT = 3; const netdata_base_url = "【netdataのURL】"; exports.handler = async (event, context, callback) => { if( event.path == '/makechart-inspect' ){ console.log(event.queryStringParameters); if (event.queryStringParameters.type == 'netdata' ){ const width = Number(event.queryStringParameters.width); const height = Number(event.queryStringParameters.height); const chart = event.queryStringParameters.chart || 'system.cpu'; var qs = { chart: chart, points: 20, format: 'json', after: -600, group: 'max', options: 'jsonwrap' }; var json = await do_get(netdata_base_url + '/api/v1/data', qs); console.log(json); var labels = []; for( var i = 0 ; i < json.points ; i++ ){ // labels.push(String((qs.after / qs.points) * (json.points - i - 1)) + 's'); var t = new Date(json.result.data[json.points - i - 1][0] * 1000); labels.push(zero2d(t.getHours()) + ':' + zero2d(t.getMinutes()) + ':' + zero2d(t.getSeconds())); } var datum = []; for (var j = 1; j < json.result.labels.length ; j++ ){ var array = []; for (var i = 0; i < json.points; i++) { array.push(json.result.data[json.points - i - 1][j]); } datum.push(array); } var legends = []; for (var i = 1; i < json.result.labels.length ; i++ ) legends.push(json.result.labels[i]); var image_buffer = await genchart.generateChart(width, height, "line", { datum: datum, labels: labels, legends: legends, title: 'netdata: ' + chart, range: (event.queryStringParameters.max) ? { max: Number(event.queryStringParameters.max) } : undefined }); return new BinResponse("image/png", image_buffer); }else if( event.queryStringParameters.type == 'ping' ){ const width = Number(event.queryStringParameters.width); const height = Number(event.queryStringParameters.height); const hosts = event.queryStringParameters.hosts.split(','); const trycount = event.queryStringParameters.trycount ? Number(event.queryStringParameters.trycount) : 3; const promises = hosts.map( async item => { var result = { success: 0, error: 0 }; for (var i = 0; i < trycount ; i++ ){ try{ var res = await ping.promise.probe(item, { timeout: PING_TIMEOUT, }); if( res.alive ) result.success++; else result.error++; }catch(error){ console.log(error); result.error++; } } return result; }); var result = await Promise.all(promises); var datum = result.map(item =>{ return [ item.success, item.error ]; }); var image_buffer = await genchart.generateChart(width, height, "stackbar", { datum: datum, labels: hosts, legends: ["OK", "NG"], title: 'Pingライフチェック', }); return new BinResponse("image/png", image_buffer); }else if (event.queryStringParameters.type == 'memory' ){ const width = Number(event.queryStringParameters.width); const height = Number(event.queryStringParameters.height); var info = await osu.mem.used(); var used = info.usedMemMb / info.totalMemMb * 100; var image_buffer = await genchart.generateChart(width, height, "gauge", { value: used, title: '使用メモリ(%)', range: { min: 0, max: 100 } }, used.toFixed(1) + '%'); return new BinResponse("image/png", image_buffer); } } else if (event.path == '/makechart-generate') { console.log(event.body); var body = JSON.parse(event.body); var image_buffer = await genchart.generateChart(body.width, body.height, body.type, body.chart_params, body.caption, body.bgcolor); return new BinResponse("image/png", image_buffer); } }; function zero2d(val) { return ('00' + String(val)).slice(-2); } function do_get(url, qs) { var params = new URLSearchParams(qs); return fetch(url + `?` + params.toString(), { method: 'GET', }) .then((response) => { if (!response.ok) throw 'status is not 200'; return response.json(); }); } 終わりに これで、GET呼び出しで、グラフ画像が取得できるようになったので、LCD付のESP32で、稼働監視を可視化できそうです。 以上
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Next.jsでMaterialUIが使えない時の対策

Next.jsでMaterialUIが使えない時の対策です。 現象 MaterialUI公式の、ボタンを表示するソースコードをコピペしてもエラーが出る。 環境 ・Next.js ・Mac OS Big Sur ver11.6 ・Docker Desktop4.1.0 ・npm install @mui/material コマンドでインストール済み エラー内容: エラー内容:Module not found: Can't resolve '@emotion/react' @emotion/reactをインストールをしても、 今度は@emotion/styledのエラーが出ます。 エラー内容:Module not found: Can't resolve '@emotion/styled' ソースコード(テスト用) import Head from 'next/head' import Image from 'next/image' import styles from '../styles/Home.module.css' // add MaterialUI import * as React from 'react'; import ReactDOM from 'react-dom'; import Button from '@mui/material/Button'; export default function Home() { return ( <Button variant="contained">Hello World</Button> ) } 対策 @emotion/reactと@emotion/styledをインストールし、Dockerをbuild後、再起動します。 インストールコマンド yarn add @emotion/react @emotion/styled 参考 npm公式 https://www.npmjs.com/package/@emotion/styled Material UI公式 https://mui.com/getting-started/usage/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む