整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          html自學(xué)教程(八)html5基礎(chǔ)(定位 圖形)

          html5 地理定位

          html5 Geolocation API用于獲得用戶的地理位置

          鑒于該特性可能侵犯用戶的隱私,除非用戶同意,否則用戶位置信息是不可用的

          注意:Geolocation(地理定位)對于擁有GPS的設(shè)備,地理定位更加精確

          Geolocation API的主要方法是gerCurrentPositon,它用來獲得用戶的位置

          下面是一個(gè)簡答的地理定位實(shí)例,可返回用戶位置的經(jīng)度和緯度:

          var x=document.getElementById("demo");

          function getLocation(){

          if(navigator.geolocation){

          navigator.geolocation.getCurrentLocation(showPositon);}

          else{

          x.innerHTML="該瀏覽器不支持獲取地理位置."}

          }

          function showPosition(position){

          x.innerHTML="緯度:"+position.coords.latitude+

          "<br>經(jīng)度:"+position.coords.longitude;}

          實(shí)例解析:

          ●檢測是否支持地理定位

          ●如果支持,則運(yùn)行g(shù)erCurrentPosition()方法.如果不支持,則向用戶顯示一段信息

          ●如果getCurrentPostion()運(yùn)行成功,則向參數(shù)showPosition中規(guī)定的函數(shù)返回一個(gè)coordinates對象

          ●showPosition()函數(shù)獲得并顯示經(jīng)度和緯度

          上面的例子是一個(gè)非常基礎(chǔ)的地理定位腳本,不含錯(cuò)誤處理

          你需要先熟悉JavaScript才能理解和使用API

          如果gerCurrentPosition()運(yùn)行成功,則getCurrentPosition()方法返回對象.始終返回latitude,longtitude以及accuracy屬性.如果可用,則會返回其他下面的屬性:

          ●coords.latitude:十進(jìn)制數(shù)的緯度

          ●coords.longtitude:十進(jìn)制的經(jīng)度

          ●coords.accuracy:位置精度

          ●coords.altitude:海拔,海平面以上以米計(jì)

          ●coords.altitudeAccuracy:位置的海拔精度

          ●coords.heading:方向,從正北開始以度計(jì)

          ●coords.speed:速度,以米/每秒計(jì)

          ●timestamp:響應(yīng)的日期/時(shí)間

          二 html5 拖放

          拖放(Drag和drop)是html5標(biāo)準(zhǔn)的組成部分

          拖放是一種常見的特性,即抓取對象以后拖到另一個(gè)位置

          在html5中,拖放是標(biāo)準(zhǔn)的一部分,任何元素都能夠拖放

          ★設(shè)置元素為可拖放

          首先,為了使元素可拖動(dòng),需要把draggable屬性設(shè)置為true:

          <img draggable="true">

          ★拖動(dòng)什么-ondragstart和setData()

          然后,規(guī)定當(dāng)元素拖動(dòng)時(shí),會發(fā)生什么

          dataTransfer.setData()方法,設(shè)置被拖數(shù)據(jù)的數(shù)據(jù)類型和值:

          function drag(ev){

          ev.dataTransfer.setData("Text",ev.target.id);}

          在這個(gè)例子中,數(shù)據(jù)類型是"Text",值是可拖動(dòng)元素的id("drag1")

          ★放到何處-ondragover

          ondragover時(shí)間規(guī)定在何處放置被拖動(dòng)的數(shù)據(jù)

          默認(rèn)地,無法將數(shù)據(jù)/元素放置到其他元素中,如果需要設(shè)置允許放置,我們必須阻止元素的默認(rèn)處理方式.

          這要通過調(diào)用ondragover時(shí)間的event.preventDefault()方法:

          event.preventDefault()

          ★進(jìn)行放置-ondrop

          當(dāng)放置被拖數(shù)據(jù)時(shí),會發(fā)生drop事件

          function drop(ev){

          ev.preventDefault();

          var data=ev.dataTransfer.getData("Text");

          ev.target.appendChild(document.getElementById(data));}

          三 html5 SVG

          什么是SVG?

          ●SVG指可伸縮矢量圖形(Scalable Vector Graphics)

          ●SVG用于定義用于網(wǎng)絡(luò)的基于矢量的圖形

          ●SVG使用XML格式定義圖形

          ●SVG圖像在放大或改變尺寸的情況下其圖形質(zhì)量不會損失

          ●SVG是萬維聯(lián)盟的標(biāo)準(zhǔn)

          在html5中,你能夠直接將SVG元素嵌入html頁面中

          要使用SVG繪制圖形,你首先需要?jiǎng)?chuàng)建一個(gè)<svg>標(biāo)簽

          <svg width="1000" height="1000"></svg>

          要?jiǎng)?chuàng)建一個(gè)圓形,需要添加一個(gè)<circle>標(biāo)簽

          下面是SVG代碼:

          <svg width="1000" height="1000">

          <circle cx="100" cy="50" r="40" fill="red" />

          </svg>

          ●cx和cy屬性定義圓點(diǎn)的x和y坐標(biāo).如果省略cx和cy,圓的中心會被設(shè)置為(0,0)

          ●r屬性定義圓的半徑

          運(yùn)行效果如下:

          礎(chǔ)部分

          坐標(biāo)系

          畫布坐標(biāo)、屏幕坐標(biāo)的概念

            • 屏幕坐標(biāo),絕對坐標(biāo),類似于css中的絕對定位
            • 畫布坐標(biāo),類似于css中的相對定位,還要考慮縮放

          幾何變換:平移、縮放、旋轉(zhuǎn)

            • 平移,位置移動(dòng),形狀、相對位置不變
            • 縮放,位置(相對屏幕坐標(biāo))和大小都發(fā)生變化
            • 旋轉(zhuǎn),位置旋轉(zhuǎn),形狀、相對位置不變

          Canvas 中的所有幾何變換針對的不是繪制的圖形,而是針對畫布本身,也就是說,當(dāng)移動(dòng)、縮放、旋轉(zhuǎn)畫布之后,新的坐標(biāo)系只對新的操作生效

          參考:

          • Canvas 幾何變換 - Canvas 基礎(chǔ)教程 - 簡單教程,簡單編程
            • Canvas 平移 translate() - Canvas 基礎(chǔ)教程 - 簡單教程,簡單編程
            • Canvas 縮放 scale() - Canvas 基礎(chǔ)教程 - 簡單教程,簡單編程
            • Canvas 旋轉(zhuǎn) rotate() - Canvas 基礎(chǔ)教程 - 簡單教程,簡單編程

          繪圖步驟

          基礎(chǔ)繪圖三步法

          1. 獲取canvas對象
          2. 獲取上下文環(huán)境對象context
          3. 開始繪制圖形。

          示例代碼

          const canvas = document.getElementById("canvas");
          const context = convas.getContext("2d");
          context.fillRect(100, 100, 50, 50);
          

          通用繪圖步驟

          1. 保存畫布(狀態(tài)),context.save();
          2. 畫布操作,context.transform(疊加) 或者 context.setTransform(不疊加)
          3. 設(shè)置樣式,繪制圖形
          4. 恢復(fù)畫布(狀態(tài)),context.restore();

          圖形變換基本操作

          1. 清空畫布,context.clearRect
          2. 保存狀態(tài),context.save
          3. 畫布操作,doTransform
          4. getShapeList and forEach
          5. 恢復(fù)狀態(tài),context.restore


          Canvas性能

          Canvas的繪制和html的繪制是不一樣的,html的繪制是增量的,當(dāng)變化時(shí),只會重新繪制變化的部分,沒有變化的部分是不會重新繪制的,但是canvas不一樣,每次都是全量繪制的,如果一個(gè)canvas里有很多圖形,當(dāng)改變一個(gè)圖形時(shí),需要重新繪制所有圖形才可以(當(dāng)然,可以用clearRect擦除部分區(qū)域,但一般很少這么用)。

          了解canvas的繪制規(guī)則之后,就很容易發(fā)現(xiàn)性能問題,如果canvas上繪制了大量的圖形(成千上萬個(gè)),每次重繪就需要很長的時(shí)間,如果重繪的頻率很高,那么就會有性能問題



          那么如何解決這個(gè)問題呢,目前有以下幾種方案

          1. 使用圖層
          2. 使用臨時(shí)圖層
          3. 使用webworker或wasm
          4. 使用webgl

          使用圖層

          圖層的概念來自于PS,每一個(gè)圖層都是一個(gè)canvas,既然在一個(gè)canvas上繪制太多圖形會有性能問題,那么就分幾個(gè)圖層,每次僅重新繪制其中一個(gè)圖層,每個(gè)圖層的圖形都不會很多,那么即使重繪的頻率很高,也不會有性能問題。圖層的概念圖如下:

          這里用背景顏色只是示意,實(shí)際上圖層都是透明

          代碼實(shí)現(xiàn)

          用一個(gè)父元素作為容器,把所有的元素設(shè)置成一樣的寬高并放在里面重疊。

          <div class="container">
              <canvas width="500" height="500"></canvas>
              <canvas width="500" height="500"></canvas>
              <canvas width="500" height="500"></canvas>
              <canvas width="500" height="500"></canvas>
              <canvas width="500" height="500"></canvas>
          </div>
          


          使用臨時(shí)圖層

          繪制是很耗性能的,如果每次都清空畫布然后重新畫一次,那么性能會消耗很大(即使分了幾個(gè)圖層),我們應(yīng)區(qū)分“變”與“不變”的部分,只對“變”的部分重新渲染,“不變”的部分不渲染,將經(jīng)常變化的部分抽離到臨時(shí)圖層,這樣僅需要渲染臨時(shí)圖層,臨時(shí)圖層有幾種實(shí)現(xiàn)思路,一種是使用操作圖層(俗稱高性能圖層),一種是使用隱藏圖層(不繪制到界面上的)


          高性能圖層

          一般高頻(實(shí)時(shí)響應(yīng)鼠標(biāo)、鍵盤等事件)的操作會放在高性能圖層,等操作完成之后,再將最終結(jié)果保存到其它圖層,比如繪制、拖拽、縮放一個(gè)(或一批)shape

          隱藏圖層

          有些圖層是不用給用戶看的,這些canvas僅存在于內(nèi)存中,不會插入html的dom中,用完就銷毀,比如常見的canvas to image。

          還有一種實(shí)現(xiàn)方式是離屏渲染(OffscreenCanvas),先在一個(gè)offCanvas操作,然后再將結(jié)果渲染到界面上(有點(diǎn)像虛擬dom操作),一般會結(jié)合webworker或webassembly


          const canvas = document.createElement("canvas");
          const context = canvas.getContext("2d");
          // 繪制圖片,或其它操作
          context.drawImage();
          // 轉(zhuǎn)成base64圖片
          convas.toDataUrl();
          

          使用webworker或wasm

          影響canvas性能的除了繪制頻率,還有一個(gè)重要的是像素點(diǎn)操作,一般圖像處理會涉及到大量的像素點(diǎn)操作,如果放在主線程計(jì)算,那么會卡住其它操作,造成頁面卡頓,特別影響用戶體驗(yàn),這些涉及大量計(jì)算的一般會單獨(dú)開個(gè)線程來操作,而在瀏覽器中有這個(gè)能力的就只有webworker了。


          有了webworker可能還不夠,因?yàn)槭冀K是在js上執(zhí)行,js執(zhí)行效率天生就比其它語言慢,所以一般的會使用webassembly,執(zhí)行效率比js快很多,而且還能用到更豐富的圖像處理庫

          使用webgl

          如果還有更高的性能要求,那么普通的2d canvas可能就無法滿足了,這個(gè)時(shí)候可以使用webgl,性能更高(當(dāng)然學(xué)習(xí)成本也更高),再結(jié)合wasm,就可以有無限想象力了,鼎鼎大名的figma就是用webgl + wasm(rust)實(shí)現(xiàn)的,另外google doc在線文檔也使用了webgl,飛書文檔將來也會替換成wegbl,基于瀏覽器的渲染始終有諸多限制,一般有能力的都會實(shí)現(xiàn)自己的渲染引擎。

          業(yè)務(wù)中圖片縮放的實(shí)現(xiàn)設(shè)計(jì)

          假設(shè)canvas大小為(867,350)

          圖片的大小為(768,576)

          將上面這張圖片放到canvas中,圖片貼邊處理,也即圖片太大就縮小,圖片太小就放大。那么我們?nèi)绾螌?shí)現(xiàn)這種效果呢?


          總結(jié)一下,總共分為幾步:

          1. 計(jì)算畫布大小和圖片大小
          2. 計(jì)算如果將圖片以原圖大小放入畫布中心,左上角的坐標(biāo)
          3. 將畫布坐標(biāo)移動(dòng)到圖片中心點(diǎn)
          4. 將畫布放大或縮小(scale=Math.min(畫布寬度/圖片寬度,畫布高度/圖片高度))
          5. 重新移動(dòng)畫布坐標(biāo)到左上角
          6. 繪制圖片(或圖形)

          canvas的執(zhí)行細(xì)節(jié)如下:

          有時(shí)候,我們想閱讀頁面中某段精彩的內(nèi)容,但由于頁面太長,用戶需要自己滾動(dòng)頁面,查找起來非常麻煩 ,很容易讓人失去繼續(xù)往下閱讀的興趣。這樣體驗(yàn)非常不好,所以我們可以想辦法 實(shí)現(xiàn)點(diǎn)擊某段文字或者圖片跳轉(zhuǎn)到頁面指定位置,方便用戶的閱讀。

          一、 純 html 實(shí)現(xiàn)

          1. 利用 id 為標(biāo)記的錨點(diǎn)

          這里作為錨點(diǎn)的標(biāo)簽可以是任意元素。

            <a href="#aa">跳轉(zhuǎn)到 id 為 aa 標(biāo)記的錨點(diǎn)</a>
            <p>-------------分隔線-------------</p>
            <div id="aa">a</div>
          

          2. 利用 a 標(biāo)簽的 name 屬性作為錨點(diǎn)

          這里作為錨點(diǎn)的標(biāo)簽只能是 a 標(biāo)簽。

            <a href="#bb" >跳轉(zhuǎn)到 name 為 bb 的 a 標(biāo)簽錨點(diǎn)</a>
            <p>-------------分隔線-------------</p>
            <a name="bb">name 為 bb 的 a 標(biāo)簽的錨點(diǎn)</a>
            <div id="abb">bbb</div>
          

          注意:當(dāng)以 ' a 標(biāo)簽 name 屬性作為錨點(diǎn) ' 和 ' 利用 id 為標(biāo)記的錨點(diǎn) ' 同時(shí)出現(xiàn)(即以 name 為錨點(diǎn)和以 id 為錨點(diǎn)名字相同時(shí)),會將后者作為錨點(diǎn)。

          二、 js 實(shí)現(xiàn)

          1. 利用 scrollTo()

          window.scrollTo 滾動(dòng)到文檔中的某個(gè)坐標(biāo)。可提供滑動(dòng)效果,想具體了解 scrollTo() 可以看看 MDN 中的介紹。

          話不多說,看下面代碼

          「html 部分」:

            <a id="linkc">平滑滾動(dòng)到 c</a>
            <p>-------------分隔線-------------</p>
            <div id="cc">c</div>
          

          「js 部分」:

            var linkc = document.querySelector('#linkc')
            var cc = document.querySelector('#cc')
          
            function to(toEl) {
              // toEl 為指定跳轉(zhuǎn)到該位置的DOM節(jié)點(diǎn)
              let bridge = toEl;
              let body = document.body;
              let height = 0;
              
              // 計(jì)算該 DOM 節(jié)點(diǎn)到 body 頂部距離
              do {
                height += bridge.offsetTop;
                bridge = bridge.offsetParent;
              } while (bridge !== body)
              
              // 滾動(dòng)到指定位置
              window.scrollTo({
                top: height,
                behavior: 'smooth'
              })
            }
          
            linkc.addEventListener('click', function () {
              to(cc)
            });
          

          2. 利用 scrollIntoView()

          Element.scrollIntoView() 方法讓當(dāng)前的元素滾動(dòng)到瀏覽器窗口的可視區(qū)域內(nèi)。想具體了解 scrollIntoView() 可以看看 MDN 中的介紹。

          下面也直接上代碼

          「html 部分」:

            <a onclick="goTo()">利用 scrollIntoView 跳轉(zhuǎn)到 d</a>
            <p>-------------分隔線-------------</p>
            <div id="dd">ddd</div>
          

          「js 部分」:

            var dd = document.querySelector('#dd')
          
            function goTo(){
              dd.scrollIntoView()
            }
          

          注意:此功能某些瀏覽器尚在開發(fā)中,請參考瀏覽器兼容性表格以得到在不同瀏覽器中適合使用的前綴。由于該功能對應(yīng)的標(biāo)準(zhǔn)文檔可能被重新修訂,所以在未來版本的瀏覽器中該功能的語法和行為可能隨之改變。

          下面為了方便看效果,把上面的代碼整理在一起。

          <!DOCTYPE html>
          <html lang="en">
          <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Document</title>
            <style>
              div {
                width: 600px;
                height: 300px;
                background-color: pink;
              }
            </style>
          </head>
          <body>
            <a href="#aa">跳轉(zhuǎn)到以 id 為 aa 標(biāo)記的錨點(diǎn) a</a>
            <p>-------------分隔線-------------</p>
            <a name="aa">hhh</a>
            <div id="aa">aa</div>
            <a href="#bb" >跳轉(zhuǎn)到 name 為 bb 的 a 標(biāo)簽錨點(diǎn)</a>
            <p>-------------分隔線-------------</p>
            <a name="bb">name 為 bb 的 a 標(biāo)簽的錨點(diǎn)</a>
            <p>-------------分隔線-------------</p>
            <div>bb</div>
            <a id="linkc">平滑滾動(dòng)到 c</a>
            <p>-------------分隔線-------------</p>
            <div id="cc">cc</div>
            <a onclick="goTo()">利用 scrollIntoView 跳轉(zhuǎn)到 d</a>
            <p>-------------分隔線-------------</p>
            <div id="dd">dd</div>
            <p>-------------分隔線-------------</p>
            <div></div>
          </body>
          <script>
            var cc = document.querySelector('#cc')
            var linkc = document.querySelector('#linkc')
          
            function to(toEl) {
              //ele為指定跳轉(zhuǎn)到該位置的DOM節(jié)點(diǎn)
              let bridge = toEl;
              let body = document.body;
              let height = 0;
              do {
                height += bridge.offsetTop;
                bridge = bridge.offsetParent;
              } while (bridge !== body)
          
              console.log(height)
              window.scrollTo({
                top: height,
                behavior: 'smooth'
              })
            }
          
            linkc.addEventListener('click', function () {
              to(cc)
            });
          
          </script>
          <script>
            var dd = document.querySelector('#dd')
          
            function goTo(){
              dd.scrollIntoView()
            }
          </script>
          </html>
          

          效果圖:


          主站蜘蛛池模板: 女同一区二区在线观看| 伊人精品视频一区二区三区| 另类ts人妖一区二区三区| 国产婷婷色一区二区三区深爱网| 国产一区二区三区免费观在线| 国产精品一区二区不卡| 国产成人无码aa精品一区| 久久se精品一区二区国产| 成人丝袜激情一区二区| 久久综合精品不卡一区二区| 精品视频一区在线观看| 亚洲国产一区在线观看| 亚洲无人区一区二区三区| 视频一区在线免费观看| 国产激情一区二区三区小说| 亚洲制服中文字幕第一区| 久久se精品一区精品二区国产| 正在播放国产一区| 欧美日韩一区二区成人午夜电影 | 亚洲熟女乱综合一区二区| 91国偷自产一区二区三区| 无码少妇一区二区性色AV| 黄桃AV无码免费一区二区三区 | 免费萌白酱国产一区二区三区| 在线免费视频一区| 无码人妻精品一区二区三区久久久| 亚洲综合一区二区国产精品| 日韩一本之道一区中文字幕| 国产精品小黄鸭一区二区三区| 日韩一区二区三区在线精品| 精品国产AV无码一区二区三区| 亚洲综合一区无码精品| 亚洲美女一区二区三区| 一区二区三区日韩| 日韩国产精品无码一区二区三区| 久久久久人妻精品一区蜜桃| 午夜福利一区二区三区高清视频 | 国产在线精品一区二区夜色| 亚洲国产综合无码一区二区二三区| 精品一区狼人国产在线| 无码国产精品一区二区高潮|