国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

記錄--買不起勞力士,一氣之下熬夜寫一個

這篇具有很好參考價值的文章主要介紹了記錄--買不起勞力士,一氣之下熬夜寫一個。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

這里給大家分享我在網(wǎng)上總結(jié)出來的一些知識,希望對大家有所幫助

記錄--買不起勞力士,一氣之下熬夜寫一個

最近喜歡研究起了手表,對勞力士這款“百事圈”實在是心水的不行??!

心癢難耐無奈錢包不支持,作為一個前端程序員,買不起的東西該怎么辦?

當(dāng)然是自己做一個?。?/p>

說干就干,熬夜自己做了個“百事圈”出來!源碼在最后!

先看成品

記錄--買不起勞力士,一氣之下熬夜寫一個

?還是有那么六七成相像了吧!主要還是在顏色選擇和細(xì)節(jié)處理上要花些功夫,無奈通過單純的平面很難展現(xiàn)出“材質(zhì)感”。

記錄--買不起勞力士,一氣之下熬夜寫一個

雖然質(zhì)感比不上人家吧,但咱們這個走時精準(zhǔn)度肯定比那鋼砣子強不是??。

除了實現(xiàn)了手表的“走時”這個基礎(chǔ)功能外,還把日歷窗、GMT雙時區(qū)功能、外圈旋轉(zhuǎn)功能也一并實現(xiàn)啦!圖片里不好展示,大家可以看完文章,自行領(lǐng)取源碼來玩玩!

實現(xiàn)思路

本想想用盡量多的CSS來實現(xiàn),但CSS實現(xiàn)這種較為復(fù)雜的動態(tài)功能還是有些頭疼,所以還是把思路放到了用canvas來實現(xiàn)。

小小構(gòu)思后手表被分為三個模塊:

  • 表盤

記錄--買不起勞力士,一氣之下熬夜寫一個

  • 表圈

記錄--買不起勞力士,一氣之下熬夜寫一個

  • 表針

記錄--買不起勞力士,一氣之下熬夜寫一個

先在html結(jié)構(gòu)中建立三個canvas標(biāo)簽:

<div class="watch-box">
  <!-- 表針 -->
  <canvas id="watchPointer" width="1800" height="1800"></canvas>
  <!-- 表盤 -->
  <canvas id="dial" width="1800" height="1800"></canvas>
  <!-- 表圈 -->
  <canvas id="bezel" width="1800" height="1800"></canvas>
</div>
并在JS中響應(yīng)地對三個canvas進(jìn)行初始化。 每個canvas畫布繪制的第一步,我們首先用getContext("2d")方法來獲取到canvas畫布的二維渲染上下文,并且為了能讓畫面清晰度更高,我們使用.scale()方法對canvas進(jìn)行四倍縮放,這樣我們可以得到一個清晰度更高的canvas畫布:
const watchBox = document.querySelector(".watch-box");
const watchPointer = document.querySelector("#watchPointer");
const dial = document.querySelector("#dial");
const bezel = document.querySelector("#bezel");
const ctx = watchPointer.getContext("2d");
const dialCtx = dial.getContext("2d");
const bezelCtx = bezel.getContext("2d");
const ratio = 4;
ctx.scale(ratio, ratio);
dialCtx.scale(ratio, ratio);
bezelCtx.scale(ratio, ratio);
鑒于我們的手表中包含了不少顏色,這些顏色都會在canvas繪制中使用到,所以我們先把顏色存儲在變量中方便后續(xù)使用:
// 初始化顏色變量
const gmtBezelRed = "#8a2811";
const blue = "#133760";
const black = "#10111e";
const white = "#fff";
const grayD = "#ddd";
const grayC = "#ccc";
const grayB = "#bbb";
const grayA = "#aaa";
const gray9 = "#999";
const gray8 = "#888";
const gmtPointerRed = "#aa0d0f";
const transparent = "grba(0,0,0,255)";	

好,準(zhǔn)備部分做完了,我們開始正題!構(gòu)建繪制方法drawGmtBezel,首先對最簡單的表圈部分進(jìn)行繪制:

// 繪制表圈
function drawGmtBezel() {
  // 設(shè)置中心點,此時225,225變成了坐標(biāo)的0,0
  bezelCtx.translate(225, 225);
  // 陰影的x偏移
  bezelCtx.shadowOffsetX = 50;
  // 陰影的y偏移
  bezelCtx.shadowOffsetY = 50;
  // 陰影顏色
  bezelCtx.shadowColor = "rgba(0, 0, 0, 0.5)";
  // 陰影的模糊半徑
  bezelCtx.shadowBlur = 100;

  /**
   * 繪制陶瓷表圈
   * @param {CanvasRenderingContext2D} bezelCtx
   * @param {number} begin
   * @param {number} end
   * @param {string} color
   * @returns
   **/
  const drawCeramicCircle = (bezelCtx, begin, end, color) => {
    bezelCtx.beginPath();
    bezelCtx.lineWidth = 26.5;
    bezelCtx.arc(0, 0, 113.25, begin, end);
    bezelCtx.strokeStyle = color;
    bezelCtx.stroke();
    bezelCtx.closePath();
  }
  // 畫上表圈(藍(lán))
  drawCeramicCircle(bezelCtx, Math.PI, 2 * Math.PI, blue)

  // 畫下表圈(紅)
  drawCeramicCircle(bezelCtx, 0, Math.PI, gmtBezelRed)
}

目前的代碼只是繪制出了雙色表圈:

記錄--買不起勞力士,一氣之下熬夜寫一個

我們首先使用bezelCtx.translate(225, 225)來設(shè)置畫布的原始點,由于我們要畫的是圓心在畫布中心點的表圈,所以我們把畫布原始點設(shè)置到225, 225這個畫布中心點的位置。

之所以是225這個數(shù)字,是因為我們在canvas標(biāo)簽中將canvas大小設(shè)置為1800x1800,又在canvas初始化時把scale設(shè)置為4倍縮放,所以畫布分辨率實際上就是1800/4,也就是450x450像素,中心點自然就是225, 225了。

隨后我們對表圈部分的陰影進(jìn)行設(shè)置,這里就不用我多介紹啦,和CSS的box-shadow邏輯是一樣的。

接下來就是繪制的部分了,我們再來看看代碼:

const drawCeramicCircle = (bezelCtx, color, begin, end) => {
  bezelCtx.beginPath();
  bezelCtx.lineWidth = 26.5;
  bezelCtx.arc(0, 0, 113.25, begin, end);
  bezelCtx.strokeStyle = color;
  bezelCtx.stroke();
  bezelCtx.closePath();
}

我們首先用beginPath方法來開始一個新路徑,可以理解為調(diào)用一只新“畫筆”,我們在canvas中的所有線條繪制都要靠這個“畫筆”來進(jìn)行。

思路其實很簡單,每個畫面都是由一筆一畫的基礎(chǔ)元素組成的,我們需要對這些基礎(chǔ)元素進(jìn)行拆解,每一筆不一樣的筆觸都需要換一只新筆,然后設(shè)置這只筆的各種屬性,最后再進(jìn)行繪畫。

我們隨后就使用lineWidth()strokeStyle()設(shè)置這只“畫筆”的粗細(xì)、顏色屬性,并且使用arc方法來繪制一個“弧形”,這個arc方法接收五個參數(shù):圓心的 x 軸坐標(biāo)、圓心的 y 軸坐標(biāo)、圓弧的半徑、圓弧的起始點、圓弧的終點。

我們在前面已經(jīng)把畫布的起始點設(shè)置為畫布中心了,所以前兩個圓心參數(shù)我們都傳入0,半徑就選用113.25這個數(shù)字(純?yōu)榱吮壤齾f(xié)調(diào)),起點和終點的設(shè)置就需要稍微計算一下了,所謂的“圓弧起始點”默認(rèn)是x軸上右側(cè)的半徑切點:

記錄--買不起勞力士,一氣之下熬夜寫一個

所以如果我們要先畫“下半圈”的話,起點也就是0,終點也就是在x軸的左側(cè)。這兩個參數(shù)的單位都是“弧度”,一個半圓對應(yīng)的弧度也就是PI,所以下半圓的起始點是0,終點是PI。

按照這樣調(diào)用方法drawCeramicCircle(bezelCtx, 0, Math.PI, gmtBezelRed),看看效果:

記錄--買不起勞力士,一氣之下熬夜寫一個

?沒問題,我們再用同樣的邏輯drawCeramicCircle(bezelCtx, Math.PI, 2 * Math.PI, blue)制作上半圈:

記錄--買不起勞力士,一氣之下熬夜寫一個

最后我們用stroke方法來進(jìn)行繪制,圖像就被繪制出來了!

這就實現(xiàn)啦,邏輯其實不過就是這樣:新建路徑(畫筆)—> 設(shè)置路徑屬性 —> 設(shè)置路徑信息 —> 繪制。

表盤的邏輯也是一致,只要你稍微掌握如何在canvas中繪制矩形、線條,實現(xiàn)起來其實沒有什么難度,我們直接快進(jìn)到表針部分:

function drawWatchPointer() {
  // 設(shè)置中心點,此時225, 225變成了坐標(biāo)的0,0
  ctx.translate(225, 225);
  // 獲取當(dāng)前時分秒
  let time = new Date();
  let day = time.getDate();
  let hour = time.getHours() % 12;
  let min = time.getMinutes();
  let second = time.getSeconds();
  let millsecond = time.getMilliseconds();

  // 時針
  ctx.rotate(((2 * Math.PI) / 12) * hour + ((2 * Math.PI) / 12) * (min / 60) - Math.PI / 2);
  ctx.beginPath();
  ctx.lineWidth = 3;
  ctx.fillStyle = white;
  ctx.fillRect(0, -4, 40, 8);
  ctx.strokeStyle = grayA;
  ctx.strokeRect(0, -3, 40, 6);
  ctx.closePath();
  // 奔馳針頭上三角
  ctx.beginPath();
  ctx.moveTo(48, -4.5);
  ctx.lineTo(57, 0);
  ctx.lineTo(48, 4.5);
  ctx.lineWidth = 2;
  ctx.strokeStyle = grayA;
  ctx.fillStyle = white;
  ctx.fill();
  ctx.stroke();
  ctx.closePath();
  // 繪制奔馳針
  ctx.beginPath();
  ctx.arc(40, 0, 10, 0, 2 * Math.PI);
  ctx.fillStyle = white;
  ctx.lineWidth = 2;
  ctx.strokeStyle = grayA;
  ctx.fill();
  ctx.stroke();
  ctx.closePath();
  ctx.beginPath();
  ctx.moveTo(30, 0);
  ctx.lineTo(39, 0);
  ctx.lineTo(46.5, 7);
  ctx.lineTo(39, 0);
  ctx.lineTo(46.5, -7);
  ctx.lineWidth = 2;
  ctx.strokeStyle = grayA;
  ctx.stroke();
  ctx.closePath();
}

其實可以看到,整體邏輯和畫表圈并沒有什么不同,只是有一些新的方法需要學(xué)習(xí)。我們還是順著邏輯走一遍:

  1. 設(shè)置畫布中心點為255, 255
  2. 通過new Date()獲取當(dāng)前時間
  3. 表針其實就是一個固定的矩形,只是需要改變矩形的旋轉(zhuǎn)就可以表示時間。所以通過((2 * Math.PI) / 12) * hour + ((2 * Math.PI) / 12) * (min / 60) - Math.PI / 2來計算出當(dāng)前時間對于時針來說需要旋轉(zhuǎn)的角度并傳參給rotate方法,使用rotate方法可以旋轉(zhuǎn)繪制的角度
  4. 新建路徑,并設(shè)置路徑屬性(粗細(xì)、顏色)
  5. 使用fillRect來繪制矩形,四個參數(shù)分別代表x起始點、y起始點、寬、高
  6. 結(jié)束表針本體的繪制,使用closePath來清除畫筆信息。接下來繪制表針的針頭(三角形)
  7. 使用moveTo方法來移動畫筆起始位置
  8. 使用lineTo方法來從畫筆起始位置繪制一條直線,參數(shù)為直線終點的x和y
  9. 連續(xù)繪制三條直線,形成三角形
  10. 使用fill來填充矩形內(nèi)部的顏色
  11. 結(jié)束表針本體的繪制,使用closePath來清除畫筆信息。接下來繪制表針的奔馳針部分(圓形)

可以看到,其實使用邏輯都是一樣的,不過就是上面說的這些,你可以自己嘗試一下把分針和秒針給實現(xiàn)出來,應(yīng)該就會對canvas有個基本的認(rèn)識啦。

時針的實現(xiàn)效果:

記錄--買不起勞力士,一氣之下熬夜寫一個

完整源碼

Canvas的基礎(chǔ)知識都是比較零碎但深度普遍不深的,我就不帶著大家把每個實現(xiàn)都過一遍了,直接把源碼拿出來,大家隨意取用!

可以試著在這個源碼基礎(chǔ)上,把自己喜歡的別的表也給做出來,做這玩意有種玩“我的世界”的快感,快來試試吧!

熬夜寫的代碼比較匆忙,還有很大的優(yōu)化空間,我就以此拋磚引玉啦:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Rolex GMT-MASTER</title>
    <style>
      @font-face {
        font-family: "Optima";
        src: url("fonts/Optima.ttc");
      }

      @font-face {
        src: url("./fonts/Palatino.ttc");
        font-family: "Trebuchet MS";
      }

      @font-face {
        font-family: "Nunito Sans";
        src: url("./fonts/NunitoSans-Regular.ttf");
      }

      body {
        margin: 0;
      }

      .watch-box {
        width: 100vw;
        height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
        background: radial-gradient(circle, #eee, #ccc, #aaa, #777);
      }

      h2 {
        position: absolute;
        top: 0;
        font-family: "Nunito Sans";
      }

      canvas {
        position: absolute;
        transform: scale(0.25);
      }

      #bezel {
        z-index: 0;
        font-weight: bold;
        font-stretch: 0px;
      }

      #dial {
        z-index: 1;
        letter-spacing: 0.5px;
      }

      #watchPointer {
        z-index: 2;
      }
    </style>
  </head>

  <body>
    <div class="watch-box">
      <!-- 表針 -->
      <canvas id="watchPointer" width="1800" height="1800"></canvas>
      <!-- 表盤 -->
      <canvas id="dial" width="1800" height="1800"></canvas>
      <!-- 表圈 -->
      <canvas id="bezel" width="1800" height="1800"></canvas>
    </div>

    <script>
      const watchBox = document.querySelector(".watch-box");
      const watchPointer = document.querySelector("#watchPointer");
      const dial = document.querySelector("#dial");
      const bezel = document.querySelector("#bezel");
      const ctx = watchPointer.getContext("2d");
      const dialCtx = dial.getContext("2d");
      const bezelCtx = bezel.getContext("2d");
      const ratio = 4;
      ctx.scale(ratio, ratio);
      dialCtx.scale(ratio, ratio);
      bezelCtx.scale(ratio, ratio);

      const logo = new Image();
      const rolexLogo = new Image();
      const imgResources = [logo, rolexLogo];
      rolexLogo.src = "./images/rolex.png";
      logo.src = "./images/logo.png";

      // 圖片資源加載后繪制表盤
      const renderDrawDial = (() => {
        let imageOnloadSuccessCount = 0;
        return () => {
          imageOnloadSuccessCount ++;
          if (imageOnloadSuccessCount >= imgResources.length) { // 圖片資源加載完畢
            drawDial();
            drawGmtBezel();
            setInterval(drawWatchPointer, 100);
          }
        }
      })()
      rolexLogo.onload = renderDrawDial;
      logo.onload = renderDrawDial;

      const gmtBezelRed = "#8a2811";
      const blue = "#133760";
      const black = "#10111e";
      const white = "#fff";
      const grayD = "#ddd";
      const grayC = "#ccc";
      const grayB = "#bbb";
      const grayA = "#aaa";
      const gray9 = "#999";
      const gray8 = "#888";
      const gmtPointerRed = "#aa0d0f";
      const transparent = "grba(0,0,0,255)";


      // 繪制表圈
      function drawGmtBezel() {
        bezelCtx.save();
        bezelCtx.clearRect(0, 0, 1800, 1800);
        // 設(shè)置中心點,此時225, 225變成了坐標(biāo)的0,0
        bezelCtx.translate(225, 225);
        bezelCtx.save();

        // 陰影的x偏移
        bezelCtx.shadowOffsetX = 50;
        // 陰影的y偏移
        bezelCtx.shadowOffsetY = 50;
        // 陰影顏色
        bezelCtx.shadowColor = "rgba(0, 0, 0, 0.5)";
        // 陰影的模糊半徑
        bezelCtx.shadowBlur = 100;

        /**
         * 繪制陶瓷表圈
         * @param {CanvasRenderingContext2D} bezelCtx
         * @param {number} begin
         * @param {number} end
         * @param {string} color
         * @returns
         **/
        const drawCeramicCircle = (bezelCtx, begin, end, color) => {
          bezelCtx.beginPath();
          bezelCtx.lineWidth = 26.5;
          bezelCtx.arc(0, 0, 113.25, begin, end);
          bezelCtx.strokeStyle = color;
          bezelCtx.stroke();
          bezelCtx.closePath();
        }
        // 畫上表圈(藍(lán))
        drawCeramicCircle(bezelCtx, Math.PI, 2 * Math.PI, blue)

        // 畫下表圈(紅)
        drawCeramicCircle(bezelCtx, 0,Math.PI, gmtBezelRed)

        // 最外層金屬旋轉(zhuǎn)外圈
        bezelCtx.beginPath();
        bezelCtx.lineWidth = 6;
        bezelCtx.arc(0, 0, 129.5, 0, 2 * Math.PI);
        bezelCtx.strokeStyle = grayD;
        bezelCtx.stroke();
        bezelCtx.closePath();

        bezelCtx.save();
        bezelCtx.rotate(-Math.PI / 2);
        for (let i = 1; i <= 60; i++) {
          bezelCtx.rotate((2 * Math.PI) / 60);
          // 繪制旋轉(zhuǎn)外圈上的凹槽
          bezelCtx.beginPath();
          bezelCtx.lineWidth = 0.6;
          bezelCtx.arc(132.5, 0, 4.2, Math.PI / 2, (3 / 2) * Math.PI);
          if ((i > 13 && i < 18) || (i > 28 && i < 33)) {
            bezelCtx.fillStyle = gray9;
          } else if (i >= 18 && i <= 28) {
            bezelCtx.fillStyle = gray8;
          } else {
            bezelCtx.fillStyle = grayA;
          }
          bezelCtx.strokeStyle = white;
          bezelCtx.fill();
          bezelCtx.stroke();
          bezelCtx.closePath();
          bezelCtx.lineWidth = 1;

          if (i === 60) {
            // 繪制十二點方向外圈
            bezelCtx.beginPath();
            bezelCtx.lineWidth = 1;
            bezelCtx.moveTo(106, 0);
            bezelCtx.lineTo(120, 16);
            bezelCtx.lineTo(120, -16);
            bezelCtx.lineTo(107, 0);
            bezelCtx.fillStyle = white;
            bezelCtx.strokeStyle = white;
            bezelCtx.fill();
            bezelCtx.stroke();
            bezelCtx.closePath();
          }
          if (i % 5 === 0 && i !== 60) {
            bezelCtx.save();
            bezelCtx.rotate(Math.PI / 2);
            bezelCtx.beginPath();
            bezelCtx.fillStyle = white;
            bezelCtx.font = "500 24px Saira";
            bezelCtx.textBaseline = "bottom";
            let width = bezelCtx.measureText((i * 4) / 10).width;
            if (width < 20) {
              bezelCtx.fillText((i * 4) / 10, -8, -99.5);
            } else {
              bezelCtx.fillText((i * 4) / 10, -12, -99.5);
            }
            bezelCtx.fill();
            bezelCtx.stroke();
            bezelCtx.closePath();
            bezelCtx.restore();
          }
          if (i % 5 === 3) {
            bezelCtx.beginPath();
            bezelCtx.fillStyle = white;
            bezelCtx.strokeStyle = white;
            bezelCtx.arc(109, -4, 2.7, 0, 2 * Math.PI);
            bezelCtx.fill();
            bezelCtx.stroke();
            bezelCtx.closePath();
          }
        }
        bezelCtx.restore();
        bezelCtx.restore();

        bezelCtx.rotate(0.5 * Math.PI);
      }

      // 繪制表盤
      function drawDial() {
        dialCtx.save();

        dialCtx.clearRect(0, 0, 1800, 1800);
        // 設(shè)置中心點,此時225, 225變成了坐標(biāo)的0,0
        dialCtx.translate(225, 225);
        // 畫表盤外圈
        dialCtx.beginPath();
        // 畫圓線使用arc(中心點X,中心點Y,半徑,起始角度,結(jié)束角度)
        dialCtx.arc(0, 0, 100, 0, 2 * Math.PI);
        dialCtx.strokeStyle = grayC;
        dialCtx.stroke();
        // 執(zhí)行畫線段的操作stroke
        dialCtx.closePath();

        // 畫表盤
        dialCtx.beginPath();
        // 畫圓線使用arc(中心點X,中心點Y,半徑,起始角度,結(jié)束角度)
        dialCtx.arc(0, 0, 53, 0, 2 * Math.PI);
        dialCtx.fillStyle = black;
        dialCtx.strokeStyle = black;
        dialCtx.lineWidth = 94;
        dialCtx.stroke();
        // 執(zhí)行畫線段的操作stroke
        dialCtx.closePath();

        dialCtx.drawImage(rolexLogo, -25, -56, 50, 27);

        dialCtx.fillStyle = white;
        dialCtx.font = "500 6px Nunito Sans";
        dialCtx.textBaseline = "bottom";
        dialCtx.fillText(
          "OYSTER PERPETUAL DATE",
          -dialCtx.measureText("OYSTER PERPETUAL DATE").width / 2,
          -21
        );

        dialCtx.font = "6px Nunito Sans";
        dialCtx.fillText("GMT-MASTER", -28, 34);

        dialCtx.font = "6px Marmelad";
        dialCtx.fillText("II", 25, 34.3, 4);

        dialCtx.font = "5px Trebuchet MS";
        dialCtx.fillText("SUPERLATIVE CHRONOMETER", -32.5, 40, 65);
        dialCtx.fillText("OFFICIALLY CERTIFIED", -24, 46, 48);

        // 繪制刻度
        dialCtx.save();

        dialCtx.lineWidth = 1;
        dialCtx.shadowOffsetX = 5;
        dialCtx.shadowOffsetY = 5;
        dialCtx.shadowColor = "rgba(0, 0, 0, 0.4)";
        dialCtx.shadowBlur = 10;

        dialCtx.rotate(-Math.PI / 2);
        for (let i = 1; i <= 60; i++) {
          dialCtx.rotate((2 * Math.PI) / 60);
          dialCtx.beginPath();

          dialCtx.lineWidth = 1;
          dialCtx.strokeStyle = grayD;
          if (i % 5 === 0) {
            dialCtx.strokeStyle = white;
            dialCtx.lineWidth = 1.3;
          }
          if (i === 28 || i === 29 || i === 31 || i === 32) {
            dialCtx.moveTo(94, 0);
            dialCtx.lineTo(96, 0);
          } else {
            dialCtx.moveTo(94, 0);
            dialCtx.lineTo(98.5, 0);
          }
          if (i !== 30) dialCtx.stroke();
          if (i === 29) {
            dialCtx.save();
            dialCtx.rotate(-Math.PI / 2 - 0.05);
            dialCtx.textBaseline = "middle";
            dialCtx.font = "4px Nunito Sans";
            dialCtx.fillStyle = white;
            dialCtx.fillText(
              "M A D E",
              -dialCtx.measureText("MADE").width / 2,
              98,
              13
            );
            dialCtx.restore();
          }
          if (i === 30) {
            dialCtx.save();
            dialCtx.rotate(-Math.PI / 2);
            ctx.mozImageSmoothingEnabled = false;
            ctx.webkitImageSmoothingEnabled = false;
            ctx.msImageSmoothingEnabled = false;
            ctx.imageSmoothingEnabled = false;
            dialCtx.drawImage(logo, -3.5, 93, 7, 6);
            dialCtx.restore();
          }
          if (i === 31) {
            dialCtx.save();
            dialCtx.rotate(-Math.PI / 2 + 0.05);
            dialCtx.textBaseline = "middle";
            dialCtx.font = "4px Nunito Sans";
            dialCtx.fillStyle = white;
            dialCtx.fillText(
              "S W I S S",
              -dialCtx.measureText("SWISS").width / 2,
              98,
              13.5
            );
            dialCtx.restore();
          }
          dialCtx.closePath();

          if (i === 60) {
            dialCtx.beginPath();
            dialCtx.moveTo(90, 12);
            dialCtx.lineTo(62, 0);
            dialCtx.lineTo(90, -12);
            dialCtx.lineTo(90, 12.5);
            dialCtx.lineWidth = 1.5;
            dialCtx.strokeStyle = gray9;
            dialCtx.fillStyle = white;
            dialCtx.fill();
            dialCtx.stroke();
            dialCtx.closePath();
          }
          // 繪制刻度
          if (i % 5 === 0 && i % 15 !== 0) {
            dialCtx.beginPath();
            dialCtx.arc(82, 0, 8.5, 0, 2 * Math.PI);
            dialCtx.lineWidth = 1.5;
            dialCtx.strokeStyle = gray9;
            dialCtx.fillStyle = white;
            dialCtx.fill();
            dialCtx.stroke();
            dialCtx.closePath();
          }
          // 繪制刻度
          if (i % 15 === 0 && i !== 60 && i !== 15) {
            dialCtx.beginPath();
            dialCtx.lineWidth = 1.5;
            dialCtx.strokeStyle = gray9;
            dialCtx.fillStyle = white;
            dialCtx.fillRect(60, -5, 30, 10);
            dialCtx.strokeRect(60, -5, 30, 10);
            dialCtx.fill();
            dialCtx.stroke();
            dialCtx.closePath();
          }
          // 繪制日歷窗
          if (i === 15) {
            dialCtx.beginPath();
            dialCtx.lineWidth = 2;
            dialCtx.strokeStyle = gray9;
            dialCtx.fillStyle = white;
            dialCtx.fillRect(57, -8, 25, 16);
            dialCtx.fill();
            dialCtx.stroke();
            dialCtx.closePath();
          }
        }
        dialCtx.restore();
        dialCtx.restore();
      }

      function drawWatchPointer() {
        ctx.save();
        ctx.clearRect(0, 0, 1800, 1800);
        // 設(shè)置中心點,此時225, 225變成了坐標(biāo)的0,0
        ctx.translate(225, 225);
        // 把狀態(tài)保存起來
        ctx.save();

        // 獲取當(dāng)前時分秒
        let time = new Date();
        let day = time.getDate();
        let hour = time.getHours() % 12;
        let min = time.getMinutes();
        let second = time.getSeconds();
        let millsecond = time.getMilliseconds();

        // 渲染日歷窗數(shù)字
        ctx.fillStyle = "#000";
        ctx.font = "bold 16px AppleGothic";
        let width = ctx.measureText(day).width;
        ctx.fillText(day, width < 15 ? 63.5 : 58, 6);
        ctx.fill();

        // 繪制圓軸
        ctx.beginPath();
        ctx.arc(0, 0, 7, 0, 2 * Math.PI);
        ctx.fillStyle = grayA;
        ctx.fill();
        ctx.closePath();
        // 時針
        ctx.rotate(((2 * Math.PI) / 12) * hour +((2 * Math.PI) / 12) * (min / 60) -Math.PI / 2);
        ctx.beginPath();
        ctx.lineWidth = 3;
        ctx.fillStyle = white;
        ctx.fillRect(0, -4, 40, 8);
        ctx.strokeStyle = grayA;
        ctx.strokeRect(0, -3, 40, 6);
        ctx.stroke();
        ctx.closePath();
        // 奔馳針頭上三角
        ctx.beginPath();
        ctx.moveTo(48, -4.5);
        ctx.lineTo(57, 0);
        ctx.lineTo(48, 4.5);
        ctx.lineWidth = 2;
        ctx.strokeStyle = grayA;
        ctx.fillStyle = white;
        ctx.fill();
        ctx.stroke();
        ctx.closePath();
        // 繪制奔馳針
        ctx.beginPath();
        ctx.arc(40, 0, 10, 0, 2 * Math.PI);
        ctx.fillStyle = white;
        ctx.lineWidth = 2;
        ctx.strokeStyle = grayA;
        ctx.fill();
        ctx.stroke();
        ctx.closePath();
        ctx.beginPath();
        ctx.moveTo(30, 0);
        ctx.lineTo(39, 0);
        ctx.lineTo(46.5, 7);
        ctx.lineTo(39, 0);
        ctx.lineTo(46.5, -7);
        ctx.lineWidth = 2;
        ctx.strokeStyle = grayA;
        ctx.stroke();
        ctx.closePath();

        // 恢復(fù)成上一次save的狀態(tài)
        ctx.restore();
        ctx.save();

        // GMT針
        ctx.rotate(((2 * Math.PI) / 24) * time.getHours() + ((2 * Math.PI) / 24) * (min / 60) - Math.PI / 2);
        ctx.beginPath();
        ctx.shadowOffsetX = 5;
        ctx.shadowOffsetY = 5;
        ctx.shadowColor = "rgba(0, 0, 0, 0.2)";
        ctx.shadowBlur = 15;
        ctx.lineWidth = 2;
        ctx.fillStyle = white;
        ctx.strokeStyle = gmtPointerRed;
        ctx.moveTo(0, 0);
        ctx.lineTo(80, 0);
        ctx.stroke();
        ctx.closePath();
        ctx.beginPath();
        ctx.strokeStyle = grayA;
        ctx.moveTo(79, -9);
        ctx.lineTo(95, 0);
        ctx.lineTo(80, 8);
        ctx.lineTo(80, -9);
        ctx.fill();
        ctx.stroke();
        ctx.closePath();
        // 繪制圓軸
        ctx.beginPath();
        ctx.arc(0, 0, 6, 0, 2 * Math.PI);
        ctx.fillStyle = grayD;
        ctx.fill();
        ctx.closePath();
        ctx.beginPath();
        ctx.arc(0, 0, 2.5, 0, 2 * Math.PI);
        ctx.fillStyle = grayA;
        ctx.fill();
        ctx.closePath();
        ctx.restore();
        ctx.save();

        // 分針
        ctx.rotate(((2 * Math.PI) / 60) * min +((2 * Math.PI) / 60) * (second / 60) - Math.PI / 2);
        ctx.beginPath();
        ctx.lineWidth = 2;
        ctx.fillStyle = white;
        ctx.fillRect(10, -4, 70, 8);
        ctx.strokeStyle = grayA;
        ctx.fillStyle = grayA;
        ctx.strokeRect(0, -4, 80, 8);
        ctx.moveTo(80.7, -5.1);
        ctx.lineTo(90, 0);
        ctx.lineTo(80.7, 5.1);
        ctx.fillRect(0, -4, 10, 8);
        ctx.fill();
        ctx.closePath();
        // 繪制圓軸
        ctx.beginPath();
        ctx.arc(0, 0, 6, 0, 2 * Math.PI);
        ctx.fillStyle = grayD;
        ctx.fill();
        ctx.closePath();
        ctx.beginPath();
        ctx.arc(0, 0, 2.5, 0, 2 * Math.PI);
        ctx.fillStyle = grayA;
        ctx.fill();
        ctx.closePath();
        ctx.restore();
        ctx.save();

        // 秒針
        ctx.rotate(((2 * Math.PI) / 60) * second +((2 * Math.PI) / 60) * (millsecond / 1000) - Math.PI / 2);
        ctx.beginPath();
        ctx.shadowOffsetX = 5;
        ctx.shadowOffsetY = 5;
        ctx.shadowColor = "rgba(0, 0, 0, 0.2)";
        ctx.shadowBlur = 15;
        ctx.moveTo(-30, 0);
        ctx.lineTo(90, 0);
        ctx.lineWidth = 2;
        ctx.strokeStyle = grayA;
        ctx.closePath();
        ctx.stroke();
        // 繪制秒針尾部
        ctx.beginPath();
        ctx.arc(-30, 0, 5, 0, 2 * Math.PI);
        ctx.fillStyle = white;
        ctx.fill();
        ctx.closePath();
        // 繪制秒針中間圓形
        ctx.shadowOffsetX = 5;
        ctx.shadowOffsetY = 5;
        ctx.shadowColor = "rgba(0, 0, 0, 0.2)";
        ctx.shadowBlur = 15;
        ctx.beginPath();
        ctx.arc(55, 0, 5.5, 0, 2 * Math.PI);
        ctx.fillStyle = white;
        ctx.lineWidth = 2;
        ctx.strokeStyle = grayA;
        ctx.fill();
        ctx.stroke();
        ctx.closePath();
        ctx.restore();
        ctx.save();

        ctx.restore();
        ctx.restore();
      }
    </script>
  </body>
</html>

本文轉(zhuǎn)載于:

https://juejin.cn/post/7304533060514971657

如果對您有所幫助,歡迎您點個關(guān)注,我會定時更新技術(shù)文檔,大家一起討論學(xué)習(xí),一起進(jìn)步。

?記錄--買不起勞力士,一氣之下熬夜寫一個文章來源地址http://www.zghlxwxcb.cn/news/detail-747015.html

到了這里,關(guān)于記錄--買不起勞力士,一氣之下熬夜寫一個的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • XmlDocument.SelectNodes 不起作用

    XmlDocument.SelectNodes 不起作用

    今天采用Xpath讀取Xml節(jié)點,怎么都讀不出。 錯誤代碼如下: 經(jīng)排查 dotnet 文檔,發(fā)現(xiàn)代碼編寫沒有問題。文檔描述如下: 文檔示例如下: 示例代碼: 示例XML: 自己程序采用Xml:

    2024年02月10日
    瀏覽(19)
  • Swagger傳參不起作用

    Swagger傳參不起作用

    本來是在swagger上面測試的,但是參數(shù)沒有傳進(jìn)來,debug發(fā)現(xiàn)傳的courseId為null 這個肯定就是傳參的問題 拿去postman測試 發(fā)現(xiàn)結(jié)果正常 ? 這時候就應(yīng)該考慮是swagger的問題了 這個時候發(fā)現(xiàn)swagger上面的ParameterType是body類型的 那就好解決了,自己的請求地址是代碼拼接類型的,也就

    2024年02月02日
    瀏覽(16)
  • wx.miniProgram.navigaTo不起作用

    最近寫了兩個個h5頁面嵌套在小程序中,其中有一個按鈕點擊通過window.location.href跳轉(zhuǎn)到第二個頁面,在第二個頁面中需要點擊跳轉(zhuǎn)按鈕跳轉(zhuǎn)到小程序中的某個頁面,但是點擊了沒反應(yīng) 現(xiàn)將問題記錄如下 解決方法 總結(jié): 如果直接用window.location.href這種方式 小程序內(nèi)嵌h5頁面去

    2024年02月11日
    瀏覽(26)
  • github中.gitignore不起作用啦

    提示:人不是靠講話來生活。每個人都應(yīng)該靠行動。而行動,是需要時間來證明的。 --《自在獨行》 (.gitignore中已經(jīng)表標(biāo)明忽略的文件目錄下的文件了,所有g(shù)it push 的時候還是出現(xiàn)在push的目錄中,或者使用git status 查看狀態(tài),看看想要被忽略的文件是否是顯示被跟蹤狀態(tài)) 重

    2024年02月06日
    瀏覽(22)
  • vscode安裝中文插件后不起作用

    安裝中文插件后,中文并沒有如期出現(xiàn)或者偶爾會自動變成英文 方法一: 點擊 Uninstall ,重新安裝,再重啟vscode 方法二: 在vscode中,按住 ctr+shift+p ,在出現(xiàn)的輸入框中,輸入 Configure Display Language ,在彈出的語言中,選中zh-cn,軟件彈出提示。點擊重啟(Restart)按鈕后,中文即可生

    2024年02月07日
    瀏覽(24)
  • 為什么很多人“看不起”Winform?

    經(jīng)常遇到還沒開始學(xué)習(xí)C#的學(xué)員問我: Winform和WPF,我應(yīng)該先學(xué)什么? 在很多人眼里,WPF是一門高級技術(shù),而Winform是比較Low的。 今天跟大家聊聊,關(guān)于WPF和Winform。 首先我認(rèn)為Winform不算是過時的技術(shù),WPF也不算是新技術(shù),兩者并不是你死我活的競爭狀態(tài),還是不同階段的不同

    2024年02月06日
    瀏覽(16)
  • css中calc不生效(不起作用)

    css中calc屬性不起作用 1、格式錯誤 calc屬性作用不起作用是因為書寫格式錯誤,正確的格式需要在運算符的兩邊留有空格。 2、父元素需要設(shè)置高度或者寬度,不能用100%。 scss、less函數(shù)不生效 如果還解決不了,請留言 。 Up高頻在線

    2024年02月13日
    瀏覽(15)
  • 胡歌深夜發(fā)文:我對不起好多人

    胡歌深夜發(fā)文:我對不起好多人

    胡歌的微博又上了熱搜。 8月29日01:18分,胡歌微博發(fā)文稱:“我盡量保持冷靜,我對不起好多人,我希望對得起這短暫的一生”,并配了一張自己胡子拉碴的圖,右眼的傷疤清晰可見。 不少網(wǎng)友留言稱“哥你又喝多了嗎”,還有不少粉絲表示:“你沒有對不起誰,盡力就好,

    2024年02月11日
    瀏覽(15)
  • git的.gitignore文件更新后不起作用

    首先,讓我們回顧一下 .gitignore 文件的作用。 .gitignore 文件用于指定哪些文件或目錄應(yīng)該被Git忽略,即這些文件和目錄不會被添加到版本控制中。它使用簡單的模式匹配規(guī)則來定義要忽略的文件或目錄。 下面是一些可能導(dǎo)致 .gitignore 文件不起作用的原因: 如果您在 .gitignor

    2024年02月13日
    瀏覽(28)
  • 不是 ES 用不起,而是 ClickHouse 更具“性價比”?

    不是 ES 用不起,而是 ClickHouse 更具“性價比”?

    云原生架構(gòu)是一種基于云計算、容器化和微服務(wù)的架構(gòu)模式。業(yè)內(nèi)預(yù)測,到2025年,預(yù)計超過95%的工作負(fù)載將遷移到云端,云原生架構(gòu)成為業(yè)務(wù)的必需品。 經(jīng)過十三年的發(fā)展,某快遞公司目前C端累計注冊用戶超2.5億、P端(專業(yè)用戶)累計注冊快遞員及網(wǎng)點經(jīng)營者超130萬、B端

    2024年01月25日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包