整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          干貨:程序員必備畫圖技能

          干貨:程序員必備畫圖技能

          程序員不是專門寫代碼的嗎,只要把代碼寫得足夠優雅就行了呀,為什么還要畫圖?畫好圖呢?

          沒錯!一圖勝千言,對復雜問題進行分析分解,再通過圖形化的表達方式,來描述業務或者技術上的邏輯,可以說事半功倍!今天作者就帶大家認識一些常見的圖、圖的畫法以及常用的畫圖工具。

          思維導圖

          英文名稱是The Mind Map,也叫做心智導圖,腦圖,心智地圖,腦力激蕩圖,靈感觸發圖,概念地圖,樹狀圖,樹枝圖或思維地圖。它是表達發散性思維的有效圖形思維工具,它簡單卻又很有效,是一種實用性的思維工具。可用于會議記錄、思路整理、測試用例、商業計劃等。

          流程圖

          以特定的圖形符號加上說明,表示算法的圖,稱為流程圖或框圖流程圖是一個系統的信息流、觀點流或部件流的圖形代表,也是軟件設計開發過程中比較常用的圖形。流程圖的圖形符號如下圖所示:

          時序圖

          時序圖(Sequence Diagram),又名序列圖、循序圖,是一種UML交互圖。它通過描述對象之間發送消息的時間順序顯示多個對象之間的動態協作,也是軟件設計開發過程中比較常用的圖形時序圖中包括的建模元素主要有:角色、對象、生命線、控制焦點、消息等等。

          數據庫ER圖

          E-R圖也稱實體-聯系圖(Entity Relationship Diagram),提供了表示實體類型、屬性和聯系的方法,用來描述現實世界的概念模型,它是描述現實世界關系概念模型的有效方法。

          數據庫模型

          1. 概念模型:找到你開發設計的系統,業務層面核心的實體和關系,如上述E-R圖。
          2. 邏輯模型:整理完善系統所有實體、實體間的關系,給實體添加字段屬性。
          3. 物理模型:通過case工具(例如:powerdesigner)由邏輯模型自動生成物理模型(可生成不同數據庫類型的DDL語句、數據字典)。

          參考文檔 https://blog.51cto.com/u_15067238/2573674

          架構圖

          業務架構:使用一套方法論/邏輯對產品(項目)所涉及到的業務進行邊界劃分,所以熟悉業務是關鍵,如下圖所示某業務中臺架構圖:

          應用架構:它是對整個系統實現的總體上的架構,需要指出系統的層次、系統開發的原則、系統各個層次的應用服務。如下圖所示,就將系統分為數據層、服務層、通訊層、展現層,并細分寫明每個層次的應用服務。

          技術架構:技術架構是應接應用架構的技術需求,并根據識別的技術需求,進行技術選型,把各個關鍵技術和技術之間的關系描述清楚。技術架構解決的問題包括:純技術層面的分層、開發框架的選擇、開發語言的選擇、涉及非功能性需求的技術選擇等。

          部署圖(deployment diagram,配置圖)是用來顯示系統中軟件和硬件的物理架構。部署圖中可以了解到軟件和硬件之間的物理關系以及處理節點的組件分布情況。使用部署圖可以顯示運行時系統的結構,同時還傳達構成應用程序的硬件和軟件元素的配置和部署方式。

          網絡拓撲圖:是指用傳輸媒體互連各種設備的物理布局,就是用什么方式把網絡中的計算機等設備連接起來。拓撲圖給出網絡服務器、工作站的網絡配置和相互間的連接,它的結構主要有星型結構、環型結構、總線結構、分布式結構、樹型結構、網狀結構、蜂窩狀結構等。

          制圖的關鍵

          不是在于熟悉和熟練使用幾種圖形元素,而更在于,真正理解“模型”的意思和意義,通過合理的過程定義和圖形使用,對復雜問題進行分析、解構后的結構化、邏輯化、專業化的表達和描述,反映出業務邏輯的處理過程和實現上的邏輯劃分,是對復雜問題合理簡化的結果。


          畫圖軟件推薦

          Xmind:一款非常實用的商業思維導圖軟件,應用全球最先進的Eclipse RCP 軟件架構,全力打造易用、高效的可視化思維軟件,強調軟件的可擴展、跨平臺、穩定性和性能,致力于使用先進的軟件技術幫助用戶真正意義上提高生產率。https://www.xmind.cn/

          ②Process On:是一個在線協作繪圖平臺,為用戶提供強大、易用的作圖工具。優點是在線支持協作,模板比較豐富,缺點是必須登錄才可以使用。免費版僅支持 9 個文件。https://www.processon.com/

          Draw.io:一款免費的跨平臺繪圖工具。可以創建流程圖、組織架構圖、UML、ER圖、泳道圖、網絡拓樸圖、思維導圖等等。內置豐富的模板和控件庫供挑選使用,還可以導入組件。支持Google Dirve,One Drive, Dropbox和本地存儲,支持將流程圖導出為多種格式,比如 pdf/svg/html 等,提供 Chrome 插件。https://app.diagrams.net/

          ④Microsoft Visio:它提供各行業和角色的豐富用例、強大的合作伙伴工具和服務并與 Microsoft 365 和 Microsoft Teams 無縫集成,了解它如何幫助你拓展業務。為客戶提供輕松創建專業圖表并快速做出決策所需的工具。

          OmniGraffle:Mac os系統上一款功能強大的繪圖軟件,可提供繪制圖表,如:樹狀結構表,流程表,頁面編排等等,您還可以用OmniGraffle來規劃電影或者戲劇劇本的情節走向,繪制公司的組織圖,并顯示一個專案所需要的步驟。


          大家還有什么好的畫圖軟件,歡迎評論區里留言推薦!

          鋒網按:本文為雷鋒字幕組編譯的技術博客,原標題 Matplotlib Plotting Guide, 作者為 Prince Grover。

          翻譯 | 李振 于志鵬 整理 | 凡江

          大多數人不會花大量時間去學 matplotlib 庫,仍然可以實現繪圖需求,因為已經有人在 stackoverflow、github 等開源平臺上提供了絕大多數畫圖問題的解決方案。我們通常會使用 google 來完成繪圖需求。至少我是這樣。

          那學 matplotlib 庫有什么用?答案是:可以節約搜索時間。掌握 matplotlib 的速查表并了解其基本接口,根據個性需求從眾多資源中編輯我們的繪圖,從長期來看會節約很多的時間。

          大部分內容取自以下 2 個鏈接,建議也去閱讀一下。

          https://realpython.com/python-matplotlib-guide/#why-can-matplotlib-be-confusing

          https://s3.amazonaws.com/assets.datacamp.com/blog_assets/Python_Matplotlib_Cheat_Sheet.pdf

          matplotlib 是一個基于 Python 的 2D 繪圖庫,其可以在跨平臺的在各種硬拷貝格式和交互式環境中繪制出高圖形。

          • 一個有趣的現象。為什么引用庫總采用 import matplotlib.pyplot as plt 的方式呢?

            因為使用例如 pylab import * 或者 %pylab 是一個非常不好的方式,matplotlib 官方不建議這樣使用,具體原因如下:

          由于歷史原因,from pylab import * 仍然存在,但是強烈建議不要這樣使用。這樣做會遮蔽 Python 的內置函數進而占用命名空間,導致難以追蹤的 bugs。想要實現零輸入獲得 IPython 集成,推薦使用 %matplotlib 命令。來源:https://matplotlib.org/users/shell.html#using-matplotlib-in-a-python-shell

          使用 matplotlib 繪制不同類型的圖像是很容易的,有很多文檔和教程。最重要的是,了解最佳的繪圖方式。如何使用 axes,subplots 等。這篇文章主要針對這些問題。

          1.內聯繪圖和 % matplotlib

          %matplotlib 命令可以在當前的 Notebook 中啟用繪圖。這個命令提供一個可選參數,指定使用哪個 matplotlib 后端。絕大多數情況下,Notebook 中都是使用 inline 后臺,它可以在 Notebook 中嵌入繪圖。另一個選項是 qt 后臺,它在側窗口打中打開 Matplotlib 交互 UI 。

          Matlibplot 提供了多種繪圖 UI ,可進行如下分類 :

          • 彈出窗口和交互界面: %matplotlib qt 和 %matplot tk

          • 非交互式內聯繪圖: %matplotlib inline

          • 交互式內聯繪圖: %matplotlib notebook-->別用這個,它會讓開關變得困難。

          2.理解 matplotlib 對象結構

          pyplot 是一個 matplotlib 面向對象的函數接口。

          plt.gca

          它返回當前 plot 關聯的軸

          如果不使用 plt.close,則會顯示出空的圖形。因為在開始時使用了 inline 命令。

          axis_id 仍然是相同的,但是當我們移動到另一個 Notebook 塊時,plt.gca 會發生變化。

          Setter 和 Getter

          Getter 和 Setter 方法用于捕獲當前或任意 axies 以及對其進行修改。我們可能需要修改標題、顏色、圖列、字體等。有兩種方法:

          1. 使用 fig.axes[i] 指定要抓取的 axes,使用 setter 的 getter 對 axies 對象進行調用。在上面的例子中,只有一個 axes,所以我們調用 axes[0]。

          2. 我們可以直接使用 plt.bla 調用當前 axis(其中,bla 可以是 title(),legend(),xlabel()等)。這是 matlibplot 面向對象的一種函數。這個函數讓修改當前的 axes 變得容易。比 1 的方法更常用。

          當我們使用 axes[i] 時,我們可以調用任何之前的代碼塊中的任何 axes 對象,但是調用 plt.bla,會在每個代碼塊中創建新的 axes 對象,并只調用當前對象。因此,上面例子中,只在 plt.title 被調用時,才創建新 plt 對象。

          重要觀察:我們通常在當前 axis 對象上調用 plt.bla,這種語法使得每個代碼塊中的 axis 對象都是新創建的。但是通過調用 fig.axes[0],我們也可以從任何代碼塊中處理之前的 axes 對象。

          這是 stateless(object oriented) 方法,并可以自定義,當圖像變得復雜時,這樣做很方便。

          所以,我建議是使用 fig,ax = plt.subplots(_) 先解壓 axes 和 figure,并給它們分配給一個新的變量。然后,可以對這些變量使用 Getter 和 Setter 方法進行繪圖中的更改。此外,這使得我們能夠在多個 axes 上做工作,而不是只在一個當前 axes 上。pyplot 使用 1 次創建子圖,然后使用 OO 方法。

          結論:從現在開始,我使用 plt.subpots 來完成不同的繪圖。(如果有人認為這個觀點是錯誤的,請糾正我)

          3.matplotlib 圖像剖析

          來自: https://matplotlib.org/faq/usage_faq.html

          4.繪圖的基本例子

          如何作圖的基本例子,涵蓋面向對象繪圖的各個方面。請仔細閱讀。

          總結上面的例子:

          • 我們創建 1 行和 2 列的圖形。即,1 行和 2 列中的 2 個 axes 對象。

          • 我們分別自定義 ax1 和 ax2。可以看到,我們可以將 Y-ticks 移動到右邊的第二圖形中。

          5.二維網格的繪制

          subplot2grid

          需要做什么?

          觀察下面的繪圖格式。

          思路是把上面的圖形考慮成為 2x4 網格。然后將多個網格分配給單個圖以容納所需的圖形。

          重點:

          • 我們可以使用 subplot2grid 定制我們的繪圖布局。

          • 我們可以用 plt.figure 創建無 axes 對象的圖形,然后手動添加 axes 對象。

          • 我們可以使用 fig.suptitle 來設置整個圖形的總標題。

          6.顏色,顏色條,RGB 數組和顏色圖譜

          我們已經介紹了 ax.plot,ax.scatter,ax.bar 和 ax.hist 等基本圖形操作,另一個更常用的函數是 ax.imshow,它用來顯示彩色圖或圖像/RGB 數組。

          7.線條樣式和線條寬度

          改變線條寬度、顏色或風格。

          8.基本的數據分布

          EDA 過程中的必要操作。

          9.二維數組的等高線圖和顏色網格圖

          熱像圖(顏色網格圖)和等高線圖在很多情況下都有助于可視化 2D 數據。

          10.圖像的調整、修改邊緣坐標和標度

          最后調整細節,讓繪圖變得更好看。

          11.標度的限制和自動調整

          需要注意的事情:

          • 填充(padding)自動設置 X 軸或 Y 軸網格標度

          • 我們可以使用 xlim,ylim 設置 x,y 的刻度限制

          12.技巧

          13.軸線

          14.結束

          博客原址: https://www.kaggle.com/grroverpr/matplotlib-plotting-guide/notebook

          雷鋒網雷鋒網

          家好,我是Echa。

          創作不易,喜歡的老鐵們加個關注,點個贊,后面會持續更新干貨,速速收藏,謝謝!

          在現在的時代發展中,從以前的手寫簽名,逐漸衍生出了電子簽名。電子簽名和紙質手寫簽名一樣具有法律效應。電子簽名目前主要還是在需要個人確認的產品環節和司法類相關的產品上較多。

          舉個常用的例子,大家都用過釘釘,釘釘上面就有電子簽名,相信大家這肯定是知道的。

          那作為前端的我們如何實現電子簽名呢?其實在html5中已經出現了一個重要級別的輔助標簽,是啥呢?那就是canvas。下面我給大家分享分享幾個關于前端如何實現電子簽名經典案例以及實現方法。

          什么是canvas

          Canvas(畫布)是在HTML5中新增的標簽用于在網頁實時生成圖像,并且可以操作圖像內容,基本上它是一個可以用JavaScript操作的位圖(bitmap)。Canvas 對象表示一個 HTML 畫布元素 -。它沒有自己的行為,但是定義了一個 API 支持腳本化客戶端繪圖操作。

          大白話就是canvas是一個可以在上面通過javaScript畫圖的標簽,通過其提供的context(上下文)及Api進行繪制,在這個過程中canvas充當畫布的角色。

          實現電子簽名

          知道幾何的朋友都很清楚,線由點繪成,面由線繪成。

          多點成線,多線成面。

          所以我們實際只需要拿到當前觸摸的坐標點,進行成線處理就可以了。

          全文大綱

          • vue-sign-canvas 一個基于canvas開發,封裝于Vue組件的通用手寫簽名板
          • Signature Pad 是一個用于繪制平滑簽名的JavaScript庫。
          • 純JavaScript實現電子簽名,同時支持Web端和移動端。

          vue-sign-canvas

          在線預覽:https://langyuxiansheng.github.io/vue-sign-canvas/

          Github:https://github.com/langyuxiansheng/vue-sign-canvas

          vue-sign-canvas 一個基于canvas開發,封裝于Vue組件的通用手寫簽名板(電子簽名板),支持pc端和移動端,屬性支持自定義配置

          組件模板使用

          <template>
              <div id="app">
                  <h2 class="title">Vue Sign Canvas 電子簽名板</h2>
                  <sign-canvas class="sign-canvas" ref="SignCanvas" :options="options" v-model="value" />
                  <img v-if="value" class="view-image" :src="value" width="150" height="150" />
                  <div class="config">
                      <ul class="ul-config">
                          <li class="li-c">
                              <span class="item-label">書寫速度:</span>
                              <span class="item-content">
                                  <select name="isSign" v-model="options.isSign">
                                      <option :value="true">簽名</option>
                                      <option :value="false">寫字</option>
                                  </select>
                              </span>
                          </li>
                          <li class="li-c">
                              <span class="item-label">顯示邊框/網格:</span>
                              <span class="item-content">
                                  <select name="isSign" v-model="options.isShowBorder">
                                      <option :value="true">顯示</option>
                                      <option :value="false">不顯示</option>
                                  </select>
                              </span>
                          </li>
                          <li class="li-c">
                              <span class="item-label">兼容高倍屏高清繪制:</span>
                              <span class="item-content">
                                  <select name="isSign" v-model="options.isDpr">
                                      <option :value="true">啟用</option>
                                      <option :value="false">關閉</option>
                                  </select>
                              </span>
                          </li>
                          <li class="li-c">
                              <span class="item-label">邊框寬度:</span>
                              <span class="item-content">
                                  <input v-model="options.borderWidth" type="number" />
                              </span>
                          </li>
                          <li class="li-c">
                              <span class="item-label">下筆寬度:</span>
                              <span class="item-content">
                                  <input v-model="options.writeWidth" type="number" />
                              </span>
                          </li>
                          <li class="li-c">
                              <span class="item-label">圖片類型:</span>
                              <span class="item-content">
                                  <input v-model="options.imgType" type="text" />
                              </span>
                          </li>
                          <li class="li-c">
                              <span class="item-label">線條的邊緣類型:</span>
                              <span class="item-content">
                                  <select name="lineCap" v-model="options.lineCap">
                                      <option value="butt">平直的邊緣</option>
                                      <option value="round">圓形線帽</option>
                                      <option value="square">正方形線帽</option>
                                  </select>
                              </span>
                          </li>
                          <li class="li-c">
                              <span class="item-label">線條交匯時邊角的類型:</span>
                              <span class="item-content">
                                  <select name="lineCap" v-model="options.lineJoin">
                                      <option value="bevel">創建斜角</option>
                                      <option value="round">創建圓角</option>
                                      <option value="miter">創建尖角</option>
                                  </select>
                              </span>
                          </li>
                          <li class="li-c">
                              <span class="item-label">畫筆顏色:</span>
                              <span class="item-content">
                                  <input type="color" v-model="options.writeColor" />
                              </span>
                          </li>
                          <li class="li-c">
                              <span class="item-label">背景色:</span>
                              <span class="item-content">
                                  <input type="color" v-model="options.bgColor" />
                              </span>
                          </li>
                      </ul>
                  </div>
                  <div class="sign-btns">
                      <span id="clear" @click="canvasClear()">清空</span>
                      <span id="save" @click="saveAsImg()">保存</span>
                      <span id="save" @click="downloadSignImg()">下載</span>
                  </div>
              </div>
          </template>
          <script>
              import SignCanvas from "../packages";
              export default {
                  components: { SignCanvas },
                  data() {
                      return {
                          value: null,
                          options: {
                              isDpr: false, //是否使用dpr兼容高倍屏 [Boolean] 可選
                              lastWriteSpeed: 1, //書寫速度 [Number] 可選
                              lastWriteWidth: 2, //下筆的寬度 [Number] 可選
                              lineCap: "round", //線條的邊緣類型 [butt]平直的邊緣 [round]圓形線帽 [square]	正方形線帽
                              lineJoin: "bevel", //線條交匯時邊角的類型  [bevel]創建斜角 [round]創建圓角 [miter]創建尖角。
                              canvasWidth: 350, //canvas寬高 [Number] 可選
                              canvasHeight: 370, //高度  [Number] 可選
                              isShowBorder: true, //是否顯示邊框 [可選]
                              bgColor: "#fcc", //背景色 [String] 可選
                              borderWidth: 1, // 網格線寬度  [Number] 可選
                              borderColor: "#ff787f", //網格顏色  [String] 可選
                              writeWidth: 5, //基礎軌跡寬度  [Number] 可選
                              maxWriteWidth: 30, // 寫字模式最大線寬  [Number] 可選
                              minWriteWidth: 5, // 寫字模式最小線寬  [Number] 可選
                              writeColor: "#101010", // 軌跡顏色  [String] 可選
                              isSign: true, //簽名模式 [Boolean] 默認為非簽名模式,有線框, 當設置為true的時候沒有任何線框
                              imgType: "png", //下載的圖片格式  [String] 可選為 jpeg  canvas本是透明背景的
                          },
                      };
                  },
                  methods: {
                      /**
                       * 清除畫板
                       */
                      canvasClear() {
                          this.$refs.SignCanvas.canvasClear();
                      },
          
                      /**
                       * 保存圖片
                       */
                      saveAsImg() {
                          const img=this.$refs.SignCanvas.saveAsImg();
                          alert(`image 的base64:${img}`);
                      },
          
                      /**
                       * 下載圖片
                       */
                      downloadSignImg() {
                          this.$refs.SignCanvas.downloadSignImg();
                      },
                  },
              };
          </script>
          <style lang="less">
              * {
                  margin: 0;
                  padding: 0;
              }
              .title {
                  padding: 20px;
                  text-align: center;
              }
              .sign-canvas {
                  display: block;
                  margin: 20px auto;
              }
              .view-image {
                  display: block;
                  margin: 20px auto;
              }
              .config {
                  width: 350px;
                  margin: 20px auto;
                  .ul-config {
                      .li-c {
                          display: flex;
                          align-items: center;
                          padding: 4px 10px;
                          .item-label {
                              font-size: 14px;
                          }
                          .item-content {
                              margin-left: 10px;
                          }
                      }
                  }
              }
              .sign-btns {
                  display: flex;
                  justify-content: space-between;
                  #clear,
                  #clear1,
                  #save {
                      display: inline-block;
                      padding: 5px 10px;
                      width: 76px;
                      height: 40px;
                      line-height: 40px;
                      border: 1px solid #eee;
                      background: #e1e1e1;
                      border-radius: 10px;
                      text-align: center;
                      margin: 20px auto;
                      cursor: pointer;
                  }
              }
          </style>

          橫屏全屏模式下簽名要怎么顯示?

          <div class="user-sign">
              <template v-if="sign">
                  <img class="sign-image" :src="sign" alt="" srcset="" />
              </template>
          </div>
          
          <script>
              //局部注冊
              import SignCanvas from "sign-canvas";
              import util from "@util";
              import { saveSignature } from "@/http";
              export default {
                  name: "UserSign",
                  components: { SignCanvas },
                  data() {
                      return {
                          sign: null,
                      };
                  },
              };
          </script>
          <style lang="scss" scoped>
              .user-sign {
                  background: #e7e7e7;
                  height: 9.375rem;
                  position: relative;
          
                  .sign-image {
                      margin: 0 auto;
                      z-index: 9;
                      height: 100%;
                      transform: rotate(-90deg) scale(1.5);
                      display: block;
                  }
              }
          </style>

          如下圖:




          Signature Pad

          在線預覽:http://szimek.github.io/signature_pad/

          Github:https://github.com/szimek/signature_pad

          Signature Pad是一個用于繪制平滑簽名的JavaScript庫。它基于HTML5畫布,使用基于Square發布的Smoother Signatures的可變寬度Bézier曲線插值。它適用于所有現代桌面和移動瀏覽器,不依賴任何外部庫。

          核心代碼:

          const canvas=document.querySelector("canvas");
          
          const signaturePad=new SignaturePad(canvas);
          
          // Returns signature image as data URL (see https://mdn.io/todataurl for the list of possible parameters)
          signaturePad.toDataURL(); // save image as PNG
          signaturePad.toDataURL("image/jpeg"); // save image as JPEG
          signaturePad.toDataURL("image/jpeg", 0.5); // save image as JPEG with 0.5 image quality
          signaturePad.toDataURL("image/svg+xml"); // save image as SVG data url
          
          // Return svg string without converting to base64
          signaturePad.toSVG(); // "<svg...</svg>"
          signaturePad.toSVG({includeBackgroundColor: true}); // add background color to svg output
          
          // Draws signature image from data URL (mostly uses https://mdn.io/drawImage under-the-hood)
          // NOTE: This method does not populate internal data structure that represents drawn signature. Thus, after using #fromDataURL, #toData won't work properly.
          signaturePad.fromDataURL("data:image/png;base64,iVBORw0K...");
          
          // Draws signature image from data URL and alters it with the given options
          signaturePad.fromDataURL("data:image/png;base64,iVBORw0K...", { ratio: 1, width: 400, height: 200, xOffset: 100, yOffset: 50 });
          
          // Returns signature image as an array of point groups
          const data=signaturePad.toData();
          
          // Draws signature image from an array of point groups
          signaturePad.fromData(data);
          
          // Draws signature image from an array of point groups, without clearing your existing image (clear defaults to true if not provided)
          signaturePad.fromData(data, { clear: false });
          
          // Clears the canvas
          signaturePad.clear();
          
          // Returns true if canvas is empty, otherwise returns false
          signaturePad.isEmpty();
          
          // Unbinds all event handlers
          signaturePad.off();
          
          // Rebinds all event handlers
          signaturePad.on();

          如下圖:


          純JavaScript實現電子簽名

          完整版:

          <!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>Document</title>
              <style>
                  * {
                      margin: 0;
                      padding: 0;
                  }
              </style>
          </head>
          <body>
              <canvas></canvas>
              <div>
                  <button onclick="cancel()">取消</button>
                  <button onclick="save()">保存</button>
              </div>
          </body>
          <script>
              // 配置內容
              const config={
                  width: 400, // 寬度
                  height: 200, // 高度
                  lineWidth: 5, // 線寬
                  strokeStyle: 'red', // 線條顏色
                  lineCap: 'round', // 設置線條兩端圓角
                  lineJoin: 'round', // 線條交匯處圓角
              }
          
              // 獲取canvas 實例
              const canvas=document.querySelector('canvas')
              // 設置寬高
              canvas.width=config.width
              canvas.height=config.height
              // 設置一個邊框
              canvas.style.border='1px solid #000'
              // 創建上下文
              const ctx=canvas.getContext('2d')
          
              // 設置填充背景色
              ctx.fillStyle='transparent'
              // 繪制填充矩形
              ctx.fillRect(
                  0, // x 軸起始繪制位置
                  0, // y 軸起始繪制位置
                  config.width, // 寬度
                  config.height // 高度
              );
          
              // 保存上次繪制的 坐標及偏移量
              const client={
                  offsetX: 0, // 偏移量
                  offsetY: 0,
                  endX: 0, // 坐標
                  endY: 0
              }
          
              // 判斷是否為移動端
              const mobileStatus=(/Mobile|Android|iPhone/i.test(navigator.userAgent))
          
              // 初始化
              const init=event=> {
                  // 獲取偏移量及坐標
                  const { offsetX, offsetY, pageX, pageY }=mobileStatus ? event.changedTouches[0] : event 
          
                  // 修改上次的偏移量及坐標
                  client.offsetX=offsetX
                  client.offsetY=offsetY
                  client.endX=pageX
                  client.endY=pageY
          
                  // 清除以上一次 beginPath 之后的所有路徑,進行繪制
                  ctx.beginPath()
                  // 根據配置文件設置相應配置
                  ctx.lineWidth=config.lineWidth
                  ctx.strokeStyle=config.strokeStyle
                  ctx.lineCap=config.lineCap
                  ctx.lineJoin=config.lineJoin
                  // 設置畫線起始點位
                  ctx.moveTo(client.endX, client.endY)
                  // 監聽 鼠標移動或手勢移動
                  window.addEventListener(mobileStatus ? "touchmove" : "mousemove", draw)
              }
              // 繪制
              const draw=event=> {
                  // 獲取當前坐標點位
                  const { pageX, pageY }=mobileStatus ? event.changedTouches[0] : event
                  // 修改最后一次繪制的坐標點
                  client.endX=pageX
                  client.endY=pageY
          
                  // 根據坐標點位移動添加線條
                  ctx.lineTo(pageX , pageY )
          
                  // 繪制
                  ctx.stroke()
              }
              // 結束繪制
              const cloaseDraw=()=> {
                  // 結束繪制
                  ctx.closePath()
                  // 移除鼠標移動或手勢移動監聽器
                  window.removeEventListener("mousemove", draw)
              }
              // 創建鼠標/手勢按下監聽器
              window.addEventListener(mobileStatus ? "touchstart" : "mousedown", init)
              // 創建鼠標/手勢 彈起/離開 監聽器
              window.addEventListener(mobileStatus ? "touchend" :"mouseup", cloaseDraw)
              
              // 取消-清空畫布
              const cancel=()=> {
                  // 清空當前畫布上的所有繪制內容
                  ctx.clearRect(0, 0, config.width, config.height)
              }
              // 保存-將畫布內容保存為圖片
              const save=()=> {
                  // 將canvas上的內容轉成blob流
                  canvas.toBlob(blob=> {
                      // 獲取當前時間并轉成字符串,用來當做文件名
                      const date=Date.now().toString()
                      // 創建一個 a 標簽
                      const a=document.createElement('a')
                      // 設置 a 標簽的下載文件名
                      a.download=`${date}.png`
                      // 設置 a 標簽的跳轉路徑為 文件流地址
                      a.href=URL.createObjectURL(blob)
                      // 手動觸發 a 標簽的點擊事件
                      a.click()
                      // 移除 a 標簽
                      a.remove()
                  })
              }
          </script>
          </html>

          各內核和瀏覽器支持情況

          Mozilla 程序從 Gecko 1.8 (Firefox 1.5 (en-US)) 開始支持 <canvas>。它首先是由 Apple 引入的,用于 OS X Dashboard 和 Safari。Internet Explorer 從 IE9 開始支持<canvas> ,更舊版本的 IE 中,頁面可以通過引入 Google 的 Explorer Canvas 項目中的腳本來獲得<canvas>支持。Google Chrome 和 Opera 9+ 也支持 <canvas>。

          小程序中提示

          在小程序中我們如果需呀實現的話,也是同樣的原理哦,只是我們需要將創建實例和上下文的Api進行修改,因為小程序中是沒有dom,既然沒有dom,哪來的操作dom這個操作呢。

          • 如果是uni-app則需要使用uni.createCanvasContext進行上下文創建
          • 如果是原生微信小程序則使用wx.createCanvasContext進行創建(2.9.0)之后的庫不支持

          主站蜘蛛池模板: 日韩人妻无码一区二区三区久久99| 亚洲第一区视频在线观看| 国产精品特级毛片一区二区三区| 三上悠亚精品一区二区久久| 亚洲综合一区国产精品| 久久精品国产一区二区三| 无码8090精品久久一区| 亚洲日本乱码一区二区在线二产线| 狠狠色婷婷久久一区二区三区 | 国产精品福利一区二区久久| 中文字幕在线播放一区| 无码人妻精品一区二区蜜桃AV| 五十路熟女人妻一区二区| 亚洲一区二区三区播放在线| 无码国产精品一区二区免费16| 国产在线不卡一区二区三区| 无码精品人妻一区二区三区影院 | 国产精品香蕉一区二区三区| 亚洲国产日韩一区高清在线| 国产在线精品一区二区中文 | 精品香蕉一区二区三区| 亚洲日本乱码一区二区在线二产线| 亚洲av一综合av一区| 日本成人一区二区三区| 久久一本一区二区三区| 人妻无码第一区二区三区| 人妻少妇久久中文字幕一区二区 | 无码视频免费一区二三区| 欧美一区内射最近更新| 日韩视频在线一区| 亚洲福利视频一区二区| 中文字幕一区二区区免| 久久久久成人精品一区二区| 亚洲福利电影一区二区?| 亚洲国产成人久久一区二区三区 | 人妻无码一区二区三区免费| 在线视频一区二区三区| 蜜桃AV抽搐高潮一区二区| 欲色aV无码一区二区人妻| 日本v片免费一区二区三区| 无码毛片一区二区三区中文字幕|