canvas美化仪表盘

function shapeFn1(ctx, x, y, radius, diff, start, end, color, type) {

  ctx.beginPath()

  ctx.moveTo(x + radius * Math.cos((start * Math.PI) / 180), y + radius * Math.sin((start * Math.PI) / 180))

  for (let i = start; end >= i; i += 1) {

    ctx.lineTo(x + radius * Math.cos((i * Math.PI) / 180), y + radius * Math.sin((i * Math.PI) / 180))

  }

  if ('end' === type || 'all' === type) {

    const x1 = x + (radius - diff / 2) * Math.cos((end * Math.PI) / 180)

    const y1 = y + (radius - diff / 2) * Math.sin((end * Math.PI) / 180)

    for (let i = end; end + 180 >= i; i += 1) {

      ctx.lineTo(x1 + (diff / 2) * Math.cos((i * Math.PI) / 180), y1 + (diff / 2) * Math.sin((i * Math.PI) / 180))

    }

  } else {

    ctx.lineTo(x + (radius - diff) * Math.cos((end * Math.PI) / 180), y + (radius - diff) * Math.sin((end * Math.PI) / 180))

  }

  for (let i = end; start <= i; i -= 1) {

    ctx.lineTo(x + (radius - diff) * Math.cos((i * Math.PI) / 180), y + (radius - diff) * Math.sin((i * Math.PI) / 180))

  }

  if ('start' === type || 'all' === type) {

    const x1 = x + (radius - diff / 2) * Math.cos((start * Math.PI) / 180)

    const y1 = y + (radius - diff / 2) * Math.sin((start * Math.PI) / 180)

    for (let i = start; start - 180 <= i; i -= 1) {

      ctx.lineTo(x1 + (diff / 2) * Math.cos((i * Math.PI) / 180), y1 + (diff / 2) * Math.sin((i * Math.PI) / 180))

    }

  } else {

    ctx.lineTo(x + radius * Math.cos((start * Math.PI) / 180), y + radius * Math.sin((start * Math.PI) / 180))

  }

  ctx.fillStyle = color

  ctx.fill()

}

function shapeFn2(ctx, x, y, radius, value, rate, currentColor) {

  const x1 = x + (radius - 10 * rate) * Math.cos(((135 + value * 2.7) * Math.PI) / 180)

  const y1 = y + (radius - 10 * rate) * Math.sin(((135 + value * 2.7) * Math.PI) / 180)

  ctx.beginPath()

  ctx.arc(x1, y1, 10 * rate, 0, 360)

  ctx.fillStyle = currentColor

  ctx.strokeStyle = '#fff'

  ctx.lineWidth = 4 * rate

  ctx.fill()

  ctx.stroke()

}

function shapeFn3(ctx, x, y, radius, start, end, color) {

  ctx.beginPath()

  ctx.moveTo(x + radius * Math.cos((start * Math.PI) / 180), y + radius * Math.sin((start * Math.PI) / 180))

  for (let i = start; end >= i; i += 1) {

    ctx.lineTo(x + radius * Math.cos((i * Math.PI) / 180), y + radius * Math.sin((i * Math.PI) / 180))

  }

  ctx.strokeStyle = color

  ctx.lineWidth = 2

  ctx.stroke()

  let j = 0

  for (let i = start; end >= i; i += (end - start) / 50) {

    const line = 0 === j % 5 ? 20 : 10

    ctx.beginPath()

    ctx.moveTo(x + radius * Math.cos((i * Math.PI) / 180), y + radius * Math.sin((i * Math.PI) / 180))

    ctx.lineTo(x + (radius - line) * Math.cos((i * Math.PI) / 180), y + (radius - line) * Math.sin((i * Math.PI) / 180))

    ctx.strokeStyle = color

    ctx.lineWidth = 2

    ctx.stroke()

    j += 1

  }

}

function shapeText(ctx, x, y, value, radius, rate, currentColor) {

  ctx.fillStyle = currentColor

  ctx.textAlign = 'center'

  ctx.textBaseline = 'middle'

  ctx.font = `${32 * rate}px 微软雅黑`

  ctx.fillText(`${value} %`, x, y)

  ctx.fillStyle = '#fff'

  ctx.textAlign = 'center'

  ctx.textBaseline = 'middle'

  ctx.font = `${18 * rate}px 微软雅黑`

  ctx.fillText('内存使用率', x, y + radius * 0.6)

}

class DashBoard {

  constructor(container) {

    this.container = container

    this.width = this.container.offsetWidth

    this.height = this.container.offsetHeight

    this.canvas = document.createElement('canvas')

    this.canvas.setAttribute('width', this.width)

    this.canvas.setAttribute('height', this.height)

    this.container.appendChild(this.canvas)

  }

  setOption(value) {

    this.value = value

    if (!this.container || !this.canvas) return

    this.draw()

  }

  resize() {

    if (!this.container || !this.canvas) return

    this.width = this.container.offsetWidth

    this.height = this.container.offsetHeight

    this.canvas.setAttribute('width', this.width)

    this.canvas.setAttribute('height', this.height)

    this.draw()

  }

  draw() {

    const ctx = this.canvas.getContext('2d')

    const x = this.width / 2

    const y = this.height / 2

    ctx.clearRect(0, 0, this.width, this.height)

    const radius = x > y ? y : x

    const colors = [

      {

        value: 0.6,

        color: 'rgba(4, 255, 206, 0.2)',

        activeColor: '#04FFCE',

      },

      {

        value: 0.8,

        color: 'rgba(252, 189, 106, 0.2)',

        activeColor: '#FCBD6A',

      },

      {

        value: 1,

        color: 'rgba(227, 22, 86, 0.2)',

        activeColor: '#E31656',

      },

    ]

    let currentColor = null

    const rate = radius / 150

    let start = 135

    colors.forEach((item, index) => {

      let type = ''

      if (0 === index) {

        type = 'start'

      } else if (colors.length - 1 === index) {

        type = 'end'

      }

      shapeFn1(ctx, x, y, radius - 15 * rate, 20 * rate, start, 135 + item.value * 270, item.color, type)

      start = 135 + item.value * 270

      if (!currentColor && this.value / 100 < item.value) {

        currentColor = item.activeColor

      }

    })

    shapeFn1(ctx, x, y, radius - 15 * rate, 20 * rate, 135, 135 + this.value * 2.7, currentColor, 'all')

    shapeFn1(ctx, x, y, radius, 8 * rate, 135, 135 + this.value * 2.7, currentColor, 'all')

    shapeFn2(ctx, x, y, radius - 15 * rate, this.value, rate, currentColor)

    shapeFn3(ctx, x, y, radius - 40 * rate, 135, 405, '#999')

    shapeText(ctx, x, y, this.value, radius, rate, currentColor)

  }

}

const a = new DashBoard(document.querySelector('#tutorial'))

a.setOption(36)

setInterval(() => {

  a.setOption(Number((Math.random() * 100).toFixed(2)))

}, 1000)

window.onresize = function () {

  a.resize()

}


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354