canvas畫圖

當前環(huán)境下,大家都非常需要分享到朋友圈這個功能猿挚,但是實現(xiàn)起來各有心酸(坑比較多)咐旧,所以才有了如下的 canvas 繪圖工具


npm地址: https://www.npmjs.com/package/vue-poster

具有如下特性:

  • 簡單易用 —— 一個 json 搞定繪制圖片
  • 功能全 —— 滿足 90% 的使用場景
  • 支持圓形圖片繪制(eg: 微信頭像圓形)[round: true]
  • 繪制文本(換行、超出內(nèi)容省略號绩蜻、中劃線铣墨、下劃線、文本加粗)
  • 繪制圖片
  • 繪制矩形
  • 保存圖片
  • 多圖繪制 (支持回調(diào))
  • 導出圖片格式 jpg/png
    ...
  • 代碼量小

API配置
/**
 * @description: 生成分享海報
 * @json {Array}
 * @return: String
 */

function canvasPosterInit (json, callback) {
  // 創(chuàng)建canvas對象
  var canvas = document.createElement('canvas')
  var ctx = canvas.getContext('2d')
  // 初始化canvas的寬高度
  canvas.width = json.width
  canvas.height = json.height
  canvasRect({ backgroundColor: '#fff', left: 0, top: 0, width: json.width, height: json.height }, ctx)
  canvasAll(json.views, 0, ctx, function () {
    canvasTranImg(canvas, json.quality, function (res) {
      callback(res)
    })
  })
}

/**
 * @description: 畫圖遞歸回調(diào)办绝,拋出最后一次回調(diào)
 * @param {type}
 * @return:
 */

function canvasAll (views, index, ctx, callback) {
  if (!views[index]) {
    callback()
    return false
  }
  switch (views[index].type) {
    case 'image':
      canvasImage(views[index], ctx, function () {
        canvasAll(views, ++index, ctx, callback)
      })
      break
    case 'text':
      canvasText(views[index], ctx, function () {
        canvasAll(views, ++index, ctx, callback)
      })
      break
    case 'rect':
      canvasRect(views[index], ctx, function () {
        canvasAll(views, ++index, ctx, callback)
      })
      break
  }
}

/**
 * @description: 畫方形 eg: 填充背景
 * @param {type}
 * @return:
 */

function canvasRect (item, ctx, callback) {
  ctx.fillStyle = item.backgroundColor || '#f0f'
  ctx.fillRect(item.left, item.top, item.width, item.height);
  (typeof callback === 'function') && callback()
}

/**

 * @description: 將圖片放在canvas對應位置
 * @item {Object}
 * @canvas {DOM}
 * @return: null
 */
function canvasImage (item, ctx, callback) {
  ctx.save()
  if (item.round) {
    var cx = item.left + item.width / 2
    var cy = item.top + item.width / 2
    ctx.arc(cx, cy, item.width / 2, 0, 2 * Math.PI)
    ctx.clip()
  }
  var img = new Image()
  img.src = item.src
  img.setAttribute('crossOrigin', 'Anonymous')
  img.onload = function () {
    ctx.drawImage(img, item.left, item.top, item.width, item.height)
    if (item.round) {
      ctx.restore()
    }
    (typeof callback === 'function') && callback()
  }
}

/**
 * @description: 將文字放在canvas對應位置
 * @item {Object}
 * @canvas {DOM}
 * @return: null
 */

function canvasText (item, ctx, callback) {
  ctx.fillStyle = item.color
  var fontStyle = (item.fontSize || 12) + 'px ' + (item.fontFamily || 'Microsoft YaHei')
  if (item.fontBold) {
    fontStyle = 'bold ' + fontStyle
  }
  ctx.font = fontStyle
  ctx.textAlign = 'left'
  ctx.textBaseline = 'top'
  var txtArr = returnCanvasTextArr(item, ctx)
  var maxLineNumber = item.maxLineNumber || 2
  if (txtArr.length > maxLineNumber) {
    var _len = txtArr[maxLineNumber - 1].length
    txtArr[maxLineNumber - 1] = txtArr[maxLineNumber - 1].slice(0, _len - 1) + '...'
  }

  txtArr.every((conTxt, index) => {
    if (index >= maxLineNumber) {
      return false
    }
    ctx.fillText(conTxt, item.left, item.top + index * item.lineHeight)
    return true
  });
  (typeof callback === 'function') && callback()
}

/**
 * @description: 返回字符串需要的行
 * @item {Object}
 * @return: Array
 */

function returnCanvasTextArr (item, ctx) {
  var arr = []
  var lastIndex = 0
  if (ctx.measureText(item.content).width <= item.width) {
    arr.push(item.content)
  } else {
    for (var index = 1; index < item.content.length; index++) {
      if (ctx.measureText(item.content.slice(lastIndex, index)).width - item.width >= 0) {
        arr.push(item.content.slice(lastIndex, index))
        lastIndex = index
      }
    }
    arr.push(item.content.slice(lastIndex, item.content.length))
  }

  return arr.filter(function (s) {
    return s && s.trim()
  })
}

/**

 * @description: 將canvas轉(zhuǎn)換為圖片
 * @canvas {DOM} canvas對象
 * @callback {function} 成功回調(diào)函數(shù)
 * @return: base64
 */

function canvasTranImg (canvas, json, callback) {
  json.format === 'png' ? callback(canvas.toDataURL('image/png')) : callback(canvas.toDataURL('image/jpeg', json.quality || 1.0))
}

調(diào)用形式

  canvasPosterInit({
    width: '607',
    height: '700',
    quality: 1,
    views: [{
      type: 'image',
      width: '607',
      height: '400',
      left: 0,
      top: 0,
      src: 'https://vipadmin.chuanghehui.com/upload/pic/20200214/65fd6ef7b753304aab33359006693da3.jpg'
    },
    {
      type: 'text',
      content: '【我的天啊我的天啊我我的天啊我的天啊我的天啊我的天啊我的天啊我的天啊我的天天天天天天】',
      width: 580,
      fontSize: 20,
      fontFamily: 'Arial',
      color: '#000',
      left: 0,
      top: 450,
      maxLineNumber: 1,
      lineHeight: 30
    }]
  }, function (img) {
    var image = new Image()
    image.src = img
    image.onload = function () {
      document.body.appendChild(image)
    }
  })
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末伊约,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子孕蝉,更是在濱河造成了極大的恐慌屡律,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件降淮,死亡現(xiàn)場離奇詭異超埋,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門霍殴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來媒惕,“玉大人,你說我怎么就攤上這事繁成∠朋希” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵巾腕,是天一觀的道長面睛。 經(jīng)常有香客問我,道長尊搬,這世上最難降的妖魔是什么叁鉴? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮佛寿,結(jié)果婚禮上幌墓,老公的妹妹穿的比我還像新娘。我一直安慰自己冀泻,他們只是感情好常侣,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著弹渔,像睡著了一般胳施。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上肢专,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天舞肆,我揣著相機與錄音,去河邊找鬼博杖。 笑死椿胯,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的剃根。 我是一名探鬼主播哩盲,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼跟继!你這毒婦竟也來了种冬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤舔糖,失蹤者是張志新(化名)和其女友劉穎娱两,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體金吗,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡十兢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年趣竣,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旱物。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡遥缕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宵呛,到底是詐尸還是另有隱情单匣,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布宝穗,位于F島的核電站户秤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏逮矛。R本人自食惡果不足惜鸡号,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望须鼎。 院中可真熱鬧鲸伴,春花似錦、人聲如沸晋控。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赡译。三九已至杉辙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捶朵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工狂男, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留综看,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓岖食,卻偏偏與公主長得像红碑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子泡垃,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355