Panda Noir

JavaScript の限界を究めるブログでした。最近は幅広めに書いてます。

アナログ時計の影をCSSでいい感じに表現する

物理的に計算するのは光源の設定などがめんどうだったのでしませんでした。

まず実物

今回のアナログ時計には拙作のsvelte-componentを利用しました。

これの針に対して影をつけます。

addEventListener('DOMContentLoaded', () => {
  const clock = new AnalogClock({target: document.querySelector('analog-clock')});
  const shadow = deg => {
    const line1 = 30, line2 = 60, line3 = 60, line4 = 30;
    if (deg === 0 || deg === 180) return '0.2px 0.2px 0 #000, -0.2px -0.2px 0 #000';
    else {
      let shadow;
      if ((0 < deg && deg < line1) || (180 - line4 <= deg && deg < 180)) shadow = 0.2;
      else if ((line1 <= deg && deg < line2) || (180 - line3 <= deg && deg < 180 - line4)) shadow = 0.5;
      else if (line2 <= deg && deg < 180 - line3) shadow = 1;
      else if (180 + line3 < deg && deg <= 360 - line2) shadow = -1;
      else if ((180 + line4 < deg && deg <= 180 + line3) || (360 - line2 < deg && deg <= 360 - line1)) shadow = -0.5;
      else if ((180 < deg && deg <= 180 + line4) || (360 - line1 < deg)) shadow = -0.2;
      return `${shadow}px ${shadow}px 0 #000`;
    }
  };
  setInterval(() => {
    const $secHand = document.querySelector('analog-clock .second-hand');
    const $minHand = document.querySelector('analog-clock .minute-hand');
    const $hourHand = document.querySelector('analog-clock .hour-hand');

    $secHand.style.boxShadow = shadow(clock._state.secondDeg);
    $minHand.style.boxShadow = shadow(clock._state.minuteDeg);
    $hourHand.style.boxShadow = shadow(clock._state.hourDeg);
  }, 10);
});

こんな感じです。shadow関数がそれらしいbox-shadowの値を返してくれるので、それを設定します。

実物はこんな感じです。

ちょっとあらが目立つ気もしますが、とりあえずいいでしょう。ちなみに、今回使用しているanalog-clockコンポーネントは外部からCSSでカスタマイズ可能なのでオリジナルデザインのアナログ時計を簡単に作成できます。