一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基于鴻蒙原生ArkTS語法開發(fā)的圖表組件--柱狀圖

陳姚豐 ? 來源:jf_83680738 ? 作者:jf_83680738 ? 2025-03-16 16:01 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

大家好,我是陳楊。在上一篇文章中,我簡要介紹了折線圖的實現(xiàn)邏輯,并解釋了整體圖表的繪制規(guī)則。根據(jù)這些規(guī)則,我們還可以繪制更多種類的圖表組件。在本期中,我將講解如何實現(xiàn)柱狀圖,并引入了一個新的功能。鑒于柱狀圖跟折線圖可共用的基礎(chǔ)配置很多,我將不再重復(fù)介紹基礎(chǔ)知識,如果你對此感興趣,可以翻閱上一篇文章了解更多內(nèi)容。

在開始技術(shù)講解之前,我想插播一個消息。為了方便大家今后使用與圖表相關(guān)的組件,我已經(jīng)陸續(xù)封裝了相關(guān)系列的組件,使其可以開箱即用。未來,我還將采取開源策略,希望大家共同分享創(chuàng)造更多實用的工具。目前,相關(guān)組件的使用文檔地址為:[http://meichuang.org.cn/McBarChart]

進(jìn)入正題,老規(guī)矩先把實現(xiàn)結(jié)構(gòu)整理出來。結(jié)構(gòu)中有一些我上篇文章已經(jīng)講過,所以這里不再做過多的闡述。直講新內(nèi)容

  • 公共屬性
    • 畫布的寬高
    • 畫布內(nèi)部間距
    • ...
  • 繪畫坐標(biāo)
    • 繪畫x與y坐標(biāo)軸
    • ...
  • 繪畫柱狀區(qū)
  • Tooltip(
    • 基本屬性
    • 定位顯示

繪畫柱狀區(qū)

在上一篇文章中,已經(jīng)包含了定義公共屬性和繪制坐標(biāo)的代碼。如果您對此感興趣,可以去查看。本期的內(nèi)容主要涵蓋了柱狀圖區(qū)域的基本屬性、柱子的繪制以及特性功能的實現(xiàn)。

繪畫柱子

先繪畫出柱狀區(qū)的概覽圖:

image.png

通過概覽圖,我們可以得到以下步驟:首先計算出每個刻度的X坐標(biāo),然后將數(shù)值轉(zhuǎn)換為對應(yīng)的高度,并設(shè)置柱子的寬度,最后利用canvas的矩形繪制方法來繪制相應(yīng)的柱子。接下來我們將詳細(xì)介紹具體的算法

每個刻度的X坐標(biāo)算法 :首先將實際數(shù)據(jù)長度length除以畫布的寬度width,得到等分刻度。然后,將等分刻度乘以索引值即可得到每個刻度的X坐標(biāo)。

數(shù)據(jù)轉(zhuǎn)化高度算法 :首先將實際數(shù)據(jù)的最大值maxValue除以畫布的高度height,得到縮放倍數(shù)。然后,使用每個刻度的實際數(shù)值乘以縮放倍數(shù)即可得到對應(yīng)的高度值。

柱子寬度 :設(shè)置基礎(chǔ)值,可以動態(tài)傳參。

了解大概算法,我們將算法轉(zhuǎn)換成代碼。代碼如下:

.onReady(() = > {  
  ...  
  // 上面是繪制x軸跟y軸的代碼  
  // 繪畫折線  
  const ySacle = (this.context.height - cSpace *2) / maxValue // 計算出y軸與實際最大值的縮放倍數(shù)  
  //連線
  for(var i=0; i< this.options.data.length; i++){  
    const dotVal = String(this.options.data[i].value)  
    const barW = 10
    // 畫布的高度減去下邊內(nèi)部高度加x軸高度
    const barH = parseInt(dotVal * ySacle) 
    // 計算每個數(shù)值的x坐標(biāo)值,減去barW/2是為了柱子能夠居中顯示
    const x = xSplitSpacing * (i + 1) + cSpace + maxNameW - barW / 2 
    // 由于畫布的左邊是從左上角開始計算的,用畫布高度減去縮放后的高度得到柱子頂部的坐標(biāo)
    const y = this.context.height - cSpace - barH 
    ctx.beginPath()
    ctx.rect( x, y, barW, barH)
    ctx.fillStyle = "green"
    ctx.fill()
    ctx.closePath()
  }  
  ctx.stroke();  
})

繪畫特性功能(文本標(biāo)簽)

繪制文本標(biāo)簽其實也很簡單。由于我們已經(jīng)計算出每根柱子的起點坐標(biāo),所以只需要將計算得到的坐標(biāo)減去文本的寬度和高度,就可以得到文本標(biāo)簽的位置。以下是具體的代碼示例:

.onReady(() = > {  
  ...  
  // 上面是繪制x軸跟y軸的代碼  
  // 繪畫折線  
  const ySacle = (this.context.height - cSpace *2) / maxValue // 計算出y軸與實際最大值的縮放倍數(shù)  
  //連線
  for(let i = 0; i < this.options.data.length; i++){  
    const dotVal = String(this.options.data[i].value)  
    const barW = 10
    // 畫布的高度減去下邊內(nèi)部高度加x軸高度
    const barH = parseInt(dotVal * ySacle) 
    // 計算每個數(shù)值的x坐標(biāo)值,減去barW/2是為了柱子能夠居中顯示
    const x = xSplitSpacing * (i + 1) + cSpace + maxNameW - barW / 2 
    // 由于畫布的左邊是從左上角開始計算的,用畫布高度減去縮放后的高度得到柱子頂部的坐標(biāo)
    const y = this.context.height - cSpace - barH
    ... 繪畫柱子
    
    // 繪制文本標(biāo)簽  
    const textWidth = this.context.measureText(dotVal).width; // 獲取文字的長度  
    const textHeight = this.context.measureText(dotVal).height; // 獲取文字的長度  
    this.context.fillText(dotVal, x - textWidth / 2, y - textHeight / 2); // 文字
  }  
  ctx.stroke();  
})

整個繪制基礎(chǔ)柱狀圖的功能已經(jīng)完成了。大家可以嘗試使用,并根據(jù)自己的業(yè)務(wù)需求來實現(xiàn)相應(yīng)的功能。希望這些代碼能夠?qū)δ兴鶐椭?/p>

Tooltip(提示層)

在講解完整個柱狀圖的繪畫之后,接下來我們將探討如何實現(xiàn)提示層功能。提示層功能在使用圖表呈現(xiàn)數(shù)據(jù)時是必不可少的,它可以讓數(shù)據(jù)更加直觀地展示,同時增加圖表的交互性,避免過于單調(diào)。

如果使用傳統(tǒng)的 JavaScript 開發(fā)機(jī)制,實現(xiàn)提示層功能相對簡單:點擊圖表內(nèi)容,判斷坐標(biāo)獲取對應(yīng)索引數(shù)據(jù),動態(tài)創(chuàng)建

元素來展示數(shù)據(jù),計算畫布和提示層的寬高,并決定提示層的最佳位置。這是大致的實現(xiàn)思路。

然而,在 ArkTS 語言中,我們需要解決以下兩個問題:

  1. 無法動態(tài)創(chuàng)建
    元素。
  2. 無法實時獲取元素的寬高。
  3. 無法觸發(fā)組件之外的內(nèi)容隱藏提示層。

針對這些問題,我們可以按照以下步驟將思路轉(zhuǎn)化為代碼并解決相應(yīng)的問題。

綁定事件/創(chuàng)建動態(tài)組件

首先,對畫布進(jìn)行單擊事件的綁定,并獲取點擊位置的 xy 值。然后循環(huán)遍歷數(shù)據(jù),對比判斷 x 值是否大于對應(yīng)索引的刻度值,如果大于,則記錄對應(yīng)的索引數(shù)據(jù),否則繼續(xù)判斷。代碼示例如下:

Canvas(this.context)
  .width('100%')
  .height('100%')
  .onReady(() = > {
    // 繪畫內(nèi)容區(qū)
  })
  .gesture(
    TapGesture({ count: 1 })
      .onAction((e: GestureEvent) = > {
         const ctx = this.context
         // 獲取點擊的x、y值
         let pos = {
          x: e.localX,
          y: e.localY
        }
        // 獲取x軸的刻度等分
        let xSplitSpacing = parseInt(String((ctx.width - cSpace * 2 - maxNameW) / this.options.data.length))
        // 循環(huán)數(shù)據(jù)判斷
        const activeObj = {}
        const activeX = null
        for(let i = 0; i < this.options.data.length; i++){  
           const item = this.options.data[i]
           if(pos.x > i * xSplitSpacing) {
               activeObj = item
               activeX = i * xSplitSpacing 
           }
        }
        // 顯示提示層
        if(this.activeX !== null) {
           ....
        }
      })
  )

由于我們沒有辦法直接動態(tài)添加元素,那我們要先定義好一個組件來呈現(xiàn)我們的數(shù)據(jù),動態(tài)控制顯示跟隱藏。

@State tooltipInfo: InterfaceObj = {}
@State tooltipPos: InterfaceObj = {
    x: -100000,
    y: -100000
}

Column() {
  Canvas(this.context)
  .width('100%')
  .height('100%')
  .onReady(() = > {
    // 繪畫內(nèi)容區(qū)
  })
  .gesture(
    TapGesture({ count: 1 })
      .onAction((e: GestureEvent) = > {
        ...判斷邏輯
        // 顯示提示層
        if(this.activeX !== null) {
           this.tooltipInfo = activeObj
           this.tooltipPos.x = activeX
        }
      })
  )
 if(Object.keys(this.tooltipInfo).length) {
    Column () {
      Text(this.tooltipInfo.title)
      ForEach(this.tooltipInfo.data, (item, index) = > {
        Text(item.name + ':' + item.num)
      })
    }
 }
}

好的,利用ArkTS提供的渲染控制能力來動態(tài)顯示元素節(jié)點是一個不錯的解決方案。這樣我們就成功地解決了無法動態(tài)添加節(jié)點的問題,并順利完成了第一步。

定位適配顯示

接下來,我們需要實現(xiàn)適配顯示的定位功能,使提示層能夠定位在鼠標(biāo)點擊的位置,并且不超出屏幕范圍。在上面顯示提示層時,我記錄了點擊圖表時數(shù)據(jù)項對應(yīng)的 X 坐標(biāo),這樣就可以為提示層設(shè)置相對定位的 X 屬性。至于 Y 軸的定位,我選擇居中顯示,當(dāng)然你們也可以根據(jù)數(shù)據(jù)項的 Y 坐標(biāo)進(jìn)行定位。

在設(shè)置提示層的 X 坐標(biāo)時,當(dāng)點擊右邊最后幾個數(shù)據(jù)項或者提示層內(nèi)容較大時,可能會導(dǎo)致提示層超出畫布內(nèi)容,從而造成數(shù)據(jù)顯示不全。解決這個問題的方法也比較簡單:判斷獲取提示層自身的寬度加上 X 坐標(biāo)是否大于畫布寬度,如果大于,則證明超出了畫布的范圍。然后,將 X 坐標(biāo)減去畫布的寬度,就可以得到最終的 X 坐標(biāo)。

然而,問題也隨之而來。由于 ArkTS 沒有提供直接獲取某些元素寬度和高度的功能,一開始我以為無法繼續(xù)下去了。但是,在仔細(xì)閱讀官方文檔之后,終于發(fā)現(xiàn)了一點線索。這里我就不賣關(guān)子了,這個 API 就是"組件區(qū)域變化事件"。你可以在官方文檔中找到相關(guān)的信息:

組件區(qū)域變化事件,快速跳轉(zhuǎn)

image.png

這個事件主要用于監(jiān)聽某個元素位置或尺寸的變化,并在變化發(fā)生時回調(diào),提供最新的位置和尺寸信息。這正好符合我們的需求,因為我們的 X 坐標(biāo)是不斷變化的,這樣我們就可以獲取到元素的尺寸了。下面是完整的代碼示例:

@State tooltipInfo: InterfaceObj = {}
@State tooltipPos: InterfaceObj = {
    x: -100000,
    y: -100000
}

Column() {
  Canvas(this.context)
  .width('100%')
  .height('100%')
  .onReady(() = > {
    // 繪畫內(nèi)容區(qū)
  })
  .gesture(
    // 點擊畫布相關(guān)事項
  )
 if(Object.keys(this.tooltipInfo).length) {
    Column () {
      Text(this.tooltipInfo.title)
      ForEach(this.tooltipInfo.data, (item, index) = > {
        Text(item.name + ':' + item.num)
      })
    }
    .position({
      x: this.tooltipPos.x,
      y: this.tooltipPos.y
    })
    .onAreaChange((oldValue: Area, newValue: Area) = > {
        const { x } = this.tooltipInfo.pos
        const { width: W, height: H } = this.context
        const { width, height } = newValue
        if (x + 40 + width > W - 10) {
          this.tooltipPos.x = x - width + 20
        } else {
          this.tooltipPos.x = x + 40
        }
        this.tooltipPos.y = H / 2 - height / 2
    })
 }
}

結(jié)束

講到這里,我們已經(jīng)完成了柱狀圖組件以及提示層功能的開發(fā),并成功封裝成了組件,即將發(fā)布到相關(guān)的文檔上。希望大家在使用過程中能夠?qū)W到很多知識。如果你有任何需要交流的地方,請在下面留言評論,我會第一時間回復(fù)你。感謝大家的支持!

審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 鴻蒙
    +關(guān)注

    關(guān)注

    60

    文章

    2620

    瀏覽量

    44058
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    開源啦?。?!基于鴻蒙ArkTS封裝的圖表組件《McCharts》,大家快來一起共創(chuàng)

    的地方請大家高抬貴手,寬容一下,謝謝。 這次主要是給大家?guī)硪粋€重磅消息,就是我自己使用鴻蒙ArkTS語法開發(fā)圖表
    發(fā)表于 03-15 15:21

    lcd12864顯示柱狀圖

    單片機(jī)用stc89c52,將采集的電壓用柱狀圖顯示,會動的那種
    發(fā)表于 05-26 23:02

    《Visual C# 2008程序設(shè)計經(jīng)典案例設(shè)計與實現(xiàn)》---柱狀圖表分析

    《Visual C# 2008程序設(shè)計經(jīng)典案例設(shè)計與實現(xiàn)》---柱狀圖表分析[hide][/hide]
    發(fā)表于 05-13 19:21

    《Visual C# 2008程序設(shè)計經(jīng)典案例設(shè)計與實現(xiàn)》---柱狀圖表的升序和降序

    《Visual C# 2008程序設(shè)計經(jīng)典案例設(shè)計與實現(xiàn)》---柱狀圖表的升序和降序[hide][/hide]
    發(fā)表于 05-13 19:23

    《Visual C# 2008程序設(shè)計經(jīng)典案例設(shè)計與實現(xiàn)》---利用Windows組件打印數(shù)據(jù)庫數(shù)據(jù)柱狀圖表

    《Visual C# 2008程序設(shè)計經(jīng)典案例設(shè)計與實現(xiàn)》---利用Windows組件打印數(shù)據(jù)庫數(shù)據(jù)柱狀圖表
    發(fā)表于 05-22 21:03

    請問labview中使用net的chart控件如何實現(xiàn)柱狀圖?

    本帖最后由 一只耳朵怪 于 2018-6-19 09:44 編輯 最近有個項目需要畫柱狀圖,并在柱狀圖上添加橫坐標(biāo)文本,并在柱狀圖中添加數(shù)值標(biāo)記,百度搜索了一大圈,也在QQ群里請教了很多人,最終實現(xiàn)了上述功能,有需要的朋友
    發(fā)表于 06-15 13:58

    Labview調(diào)用OWC11制作柱狀圖

    Labview調(diào)用OWC11制作柱狀圖
    發(fā)表于 02-22 11:00

    Matplotlib繪制柱柱狀圖、直方圖、條形的使用語法

    Matplotlib - 柱狀圖、直方圖、條形 bar() & barh() 所有用法詳解
    發(fā)表于 04-18 08:17

    Labview 柱狀圖

    請教一下,labview怎么生成下圖這種柱狀圖,可以標(biāo)識上下限數(shù)值,標(biāo)識數(shù)量。
    發(fā)表于 09-21 15:38

    LabVIEW強(qiáng)大的生產(chǎn)產(chǎn)量---柱狀圖表---嵌入MES系統(tǒng)

    ` 本帖最后由 wcl86 于 2021-5-14 15:28 編輯 LabVIEW做一些柱狀圖可以鏈接至你們的小MES系統(tǒng)之類的,希望能幫助大家啦,文件可回復(fù)下載附件通用邏輯運(yùn)動通用視覺`
    發(fā)表于 08-06 17:25

    怎么將每小時得到的合格和不合格的結(jié)果用柱狀圖表示出來?

    怎么將每小時得到的合格和不合格的結(jié)果用柱狀圖表示出來,類似下面這樣的
    發(fā)表于 09-24 11:54

    怎樣用MATLAB去給柱狀圖加數(shù)據(jù)標(biāo)簽?zāi)?/a>

    怎樣用MATLAB去給柱狀圖加數(shù)據(jù)標(biāo)簽?zāi)??記錄一下matlab畫柱狀圖的過程
    發(fā)表于 11-19 07:13

    HarmonyOS/OpenHarmony應(yīng)用開發(fā)-ArkTS語言基本語法說明

    的封裝和復(fù)用UI描述。 @Extend/@Style:擴(kuò)展內(nèi)置組件和封裝屬性樣式,更靈活地組合內(nèi)置組件。 stateStyles:多態(tài)樣式,可以依據(jù)組件的內(nèi)部狀態(tài)的不同,設(shè)置不同樣式。*附件:HarmonyOSOpenHarmo
    發(fā)表于 06-01 10:25

    柱狀圖Histogram Plot

    柱狀圖 Histogram Plot資料免費下載。
    發(fā)表于 06-01 17:00 ?17次下載

    如何用seabron生成柱狀圖和散點圖

    生成柱狀圖 柱狀圖是我們經(jīng)常會見到的數(shù)據(jù)圖表,每個柱狀都表示一組數(shù)據(jù) import seaborn import matplotlib.pyplot as pltmonths = [
    的頭像 發(fā)表于 10-07 11:20 ?1563次閱讀
    如何用seabron生成<b class='flag-5'>柱狀圖</b>和散點圖