turnjs fabricjs canvas 翻書

最近作了一個翻書效果的項目, 來總結一下實現過程和遇到的一些問題, 供本身之後快速解決問題, 但願也能幫到一樣遇到此類問題的同窗, 若是有更好的方法,但願你能分享給我
git地址php

插件:

Turn.js, Fabric.js, Touch.js, jQuery.js, jQuery-ui.js, ES6-Promisecss


問題都是些本身覺的比較難解決的, 比較片面, 若有其餘疑問能夠留言交流或者Bingjquery

Turn.js

當你從Turn官網下載下來文件後它裏面會提供5種事例代碼, 根據需求我用的是docs, 先看一段簡單的事例代碼:git

  • HTML
<div id="flipbook"></div>
  • JS
$('#flipbook').turn({
  width: width,
  height: height,
  pages: length,
  autoCenter: true,
  when: { // 處理事件
    missing: function(e, pages) { // e:(event), pages:(type:arr,須要添加的頁數)
      var book = $(this)
      pages.forEach(function(item, i) {
        addPage(item, i, data)
      })
    }
  }
})

把你的內容放在flipbook下面, 而後經過turn(object)來初始化你的數據, 固然你也可使用DOM添加數據, 而後再初始化數據.區別多是經過missing事件監聽能夠及時知道數據變化, 而經過DOM則不能(只是猜測沒有驗證).es6

Fabric.js

這裏每一頁內容都是由圖片, 文字, 線段組成的, 因此用了canvas.github

第一個問題是背景平鋪問題, 由於在Fabric文檔中好像不支持背景平鋪, 也多是我沒有找到, 因此就用了這種方式, 直接給畫布加背景:json

$('#canvas').css({
  'background-image':'url(' + url + ')',
  'background-size': 'size'
})

第二個問題是繪製貝塞爾曲線問題, 在繪製貝塞爾曲線用的是Path方法, 先看段代碼:canvas

var path = new fabric.Path('C43,128,28,143,17,153C14,156,12,158,12,158z', {
  opacity: .5, // 線條透明度
  stroke: '#e4393c', // 顏色
  strokeLineCap: 'round', // 線頭樣式
  strokeWidth: 3, // 線寬
  fill: false, // 填充透明
  strokeLineJoin: 'round' // 交點樣式
})
canvas.add(path) // 添加到canvas上

你能夠經過這種方式來加曲線, 其實完整寫法是
new Path('M0,0L100,100C50,50,60,60,70,70z', {})
其中字母也能夠小寫, 逗號能夠用空格代替或者短橫線, 應該也支持其餘的(我沒試過)M表明將點移動那裏而後L畫出一條線, C表明開始畫貝塞爾曲線, 是三次貝賽爾曲線(還有二次的,不知道Bing下), 三次貝塞爾曲線須要4個點來控制, 第一個點就是代碼裏面的(100,100), 緊接着是第一個控制點(50,50), 第二個控制點(60,60), 最後一個點(70,70)結束點z封閉一下. 你想在C後面加8個數? 別試了, 我試過沒用. 在繪製過程當中你會發現繪製出來的曲線老是首尾相連,若是不合需求你在繪製的最後就不能加z, 同時把fill設置爲false.api

第三個問題是層級問題, 你想文字在圖片上面, 你想小的logo在最頂部可是每每繪製出來並非你想要的效果, 這是由於圖片和logo大部分都是圖片, 請求是異步的, 你把異步拿來的圖片畫上去設置zindex並不能達到預期的效果, 先看代碼:數組

var stepCounter = {}, layerArr = [], promiseArr = []

function adjustment(canvas, img, index) {
  var obj = new Object()
  obj.canvas = canvas
  obj.img = img
  obj.index = index
  return obj
}

function draw() {
    var promise = new Promise(function(res, rej) {
      var img = new Image()
      stepCounter[num] += 1
      img.src = url
      img.onload = function() {
        res(img)
      }
    })
    
    promise.then(function(img) {
      Img = new fabric.Image(img, {
        ... // 設置一些屬性
      })
      canvas.add(Img)
      obj = adjustment(canvas, Img, -50)
      layerArr.push(obj)
      promiseArr.push(promise)
    })
}

setTimeout(function() {
  if (stepCounter[i] == promiseArr.length) {
    Promise.all(promiseArr).then(function() {
      layerArr.sort(function(a, b) {
        return a.index - b.index
      })
      layerArr.forEach(function(item, i) {
        var c = item.canvas
        c.moveTo(item.img, i)
        c.renderAll()
      })
    })
    return
  }
  setTimeout(arguments.callee, 50)
}, 50)

總體思路是這樣的:

  1. Promise加載圖片, 同時將promisepush到數組promiseArr中, 能夠用來判斷圖片是否都下載完和作對比判斷.
  2. 假設第一頁有20個圖片, 每建立一個Promise就在stepCounter中對應的屬性記錄一下, 對比判斷.
  3. 把圖片的zIndex和一些必要信息放在一個數組中(layerArr), 圖片下載完調整zIndex.

最後setTimeout檢測當頁繪製的圖片與promise.length是否相同, 相同就證實全部圖片都在加載中, 再用Promise.all()肯定圖片加載完成後就能夠調整圖片的zIndex了, 我參考了stackoverflow0, stackoverflow1, 考慮到Promise的兼容性, 須要引入ES6-Promise

翻書區域
用了Touchjs模擬, 就很少說了, 很簡單.
分享

原來用的是jiathis分享, https後不能用了, 多是不支持.

var qzone = 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url={url}&title={title}&pics={pic}&summary={content}';
var sina = 'http://service.weibo.com/share/share.php?url={url}&title={title}&pic={pic}&searchPic=false';
var weixin = 'http://qr.liantu.com/api.php?text={url}';

因此直接調接口本身寫了個

相關文章
相關標籤/搜索