見出し画像

受け取った引数からスケール関数をダイナミックに作成してみよう~ネストした多角形ポリゴンの作成を例に~

こんにちわ。nap5です。


今回は小ネタですが、受け取った引数からスケール関数をダイナミックに作成するやり方の一つを紹介したいと思います。


使用するライブラリは以下です。




以前にも扱ったネストした多角形ポリゴンの作成をユースケースとしてスケール関数の作成にチャレンジしたいと思います。


以下が、受け取った引数からスケール関数をダイナミックに作成するコード
になります。

入力ドメインは-1から1までを受け取り、出力レンジは受け取った引数をもとに定義しています。


こうすることで、ネスト数が1段上がるたびにサイズをダウンスケールさせたり、アップスケールさせたりすることが可能になります。

import * as d3 from "d3";

const createScaler = ({ width }) => {
  return d3
    .scaleLinear()
    .domain([-1, 1])
    .range([-width / 2, width / 2]);
};


このスケール関数をネストした多角形ポリゴンの作成に落とし込んだコードが以下になります。


import * as d3 from "d3";
import { samples } from "culori";
import { degreesToRadians } from "popmotion";
import BABYLON from "babylonjs";
const { Scalar } = BABYLON;

const generateRadList = ({ edgeCount, rotationAngleOffset }) => {
  rotationAngleOffset = Scalar.NormalizeRadians(
    degreesToRadians(rotationAngleOffset)
  );
  return d3.range(edgeCount).map((num) => {
    return (num / edgeCount) * (2 * Math.PI) + rotationAngleOffset;
  });
};

const createPolygon = ({ edgeCount, scaler, rotationAngleOffset }) => {
  const resultList = [];
  const radList = generateRadList({ edgeCount, rotationAngleOffset });
  let path = `M${scaler(Math.cos(radList[0]))},${scaler(Math.sin(radList[0]))}`;
  radList.slice(1).forEach((item) => {
    path = path + `L${scaler(Math.cos(item))},${scaler(Math.sin(item))}`;
  });
  path = path + `Z`;
  return path;
};

const createScaler = ({ width }) => {
  return d3
    .scaleLinear()
    .domain([-1, 1])
    .range([-width / 2, width / 2]);
};

const createNestPolygon = ({
  width,
  edgeCount,
  nestCount,
  rotationAngleOffset,
}) => {
  const widthInfoList = samples(nestCount + 1)
    .slice(1)
    .map((t) => {
      return { t, w: width * t };
    });
  let resultPath = ``;
  for (let index = 0; index < widthInfoList.length; index++) {
    const widthInfo = widthInfoList[index];
    resultPath =
      resultPath +
      createPolygon({
        edgeCount,
        scaler: createScaler({ width: widthInfo.w }),
        rotationAngleOffset,
      });
  }
  return resultPath;
};

const result = createNestPolygon({
  edgeCount: 3,
  nestCount: 3,
  width: 2,
  rotationAngleOffset: 60,
});

console.log(result);


このプログラムの実行結果は以下になります。

$ time node index.js
M0.16666666666666669,0.2886751345948128L-0.3333333333333333,5.551115123125783e-17L0.16666666666666646,-0.28867513459481303ZM0.33333333333333337,0.5773502691896256L-0.6666666666666666,1.1102230246251565e-16L0.3333333333333329,-0.5773502691896261ZM0.5,0.8660254037844386L-1,2.220446049250313e-16L0.49999999999999933,-0.866025403784439Z

real    0m1.266s
user    0m1.477s
sys     0m0.133s


出力されたsvgのパスコマンドをsvg-path-editorに張り付けてみます。

ファイルにも保存し、添付しましたので、ダウンロード後、ブラウザにドラッグアンドドロップすると見れると思います。


引数にエッジカウント3、ネスト3、サイズ2、回転オフセット60度を指定した場合




最近では、Twitterでモックアップ動画を公開しているので、こちらもよかったら、覗いてみてください。


最後に、Udemyでコースを公開しました。
良かったら覗いてみてください。


また、コースの内容紹介記事は以下になります。


簡単ですが、以上です。

この記事が気に入ったらサポートをしてみませんか?