Turnjs fabricjs canvas


Recently, I did a book turning effect project to summarize the implementation process and some problems encountered, so that I can quickly solve the problems in the future. I hope it can also help the students who also encounter such problems. If there is a better method, I hope you can share it with me
Git address

plug-in unit:

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

Problems are more difficult to solve, more one-sided, if you have other questions can leave a message or exchangeBing


When you download the file from the official website of turn, it will provide five case codes. According to the requirements, I usedocsFirst, let’s look at a simple example code:

  • HTML
<div id="flipbook"></div>
  • JS
  width: width,
  height: height,
  pages: length,
  autoCenter: true,
  When: {// handle events
    missing: function(e, pages) { // e:(event), pages:( type:arr , number of pages to add)
      var book = $(this)
      pages.forEach(function(item, i) {
        addPage(item, i, data)

Put your content in theflipbookNext, throughturn(object)To initialize your data. Of course, you can also useDOMAdd data, and then initialize the data. The difference may be throughmissingEvent monitoring can know the change of data in time, and through theDOMIt can’t (just guess without verification)


Here, every page is made up of pictures, words and line segments, so it is usedcanvas.

First questionThis is the problem of background tiling. It seems that background tiling is not supported in the fabric document, or maybe I didn’t find it, so I used this method to add background to the canvas directly

  'background-image':'url(' + url + ')',
  'background-size': 'size'

Second questionIt is the problem of drawing Bezier curve. In drawing Bezier curve, we usePathMethod, first look at the code:

var path = new fabric.Path('C43,128,28,143,17,153C14,156,12,158,12,158z', {
  Opacity:. 5, // line transparency
  Stroke: '# e4433c' // color
  Strokelinecap: 'round', // thread style
  Strokewidth: 3, // line width
  Fill: false, // fill transparent
  Strokelinejoin: 'round' // intersection style
Canvas. Add (path) // add to canvas

You can add curves in this way
new Path('M0,0L100,100C50,50,60,60,70,70z', {})
Letters can also be lowercase, commas can be replaced by spaces or dashes, and other characters should also be supported (I haven’t tried)MThe representative moves the point there and thenLDraw a line,CRepresents the beginning of drawing Bezier curve, which is cubic Bezier curve (and quadratic, I don’t know under Bing). The cubic Bezier curve needs four points to control, and the first point is in the code(100,100), followed by the first control point(50,50)Second control point(60,60)The last point(70,70)End pointzClose it up. What do you want to doCAdd 8 numbers after it? Don’t try, I’ve tried, but it’s useless. In the process of drawing, you will find that the curves drawn are always end-to-end. If you don’t meet the requirements, you can’t add them at the end of the drawingzAt the same timefillSet tofalse.

Third questionIt’s a matter of hierarchy. You want the text on the picture, and you want the small logo on the top, but it’s often not the effect you want to draw. This is because most of the pictures and logos are pictures, and the request is asynchronous. You draw the pictures that are taken asynchronously to set themzindexIt can’t achieve the expected effect

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() {
    promise.then(function(img) {
      Img = new fabric.Image(img, {
        ... // set some properties
      obj = adjustment(canvas, Img, -50)

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)
  setTimeout(arguments.callee, 50)
}, 50)

The overall idea is as follows:

  1. usePromiseLoad the picture andpromisePush to arraypromiseArrCan be used to determine whether the pictures are downloaded and do comparative judgment
  2. Suppose there are 20 images on the first page, one for eachPromiseRight herestepCounterRecord the corresponding attributes in, compare and judge
  3. Put the picture on the right sidezIndexAnd some necessary information in an array(layerArr), adjust after picture downloadzIndex.

lastusesetTimeoutCheck whether the image drawn on the current page is consistent with thepromise.lengthIf it is the same or not, the same will prove that all the pictures are being loaded, and thenPromise.all()Make sure that after the image is loaded, you can adjust the color of the imagezIndexYes, I refer to itstackoverflow0, stackoverflow1, consideringPromiseWe need to introduce theES6-Promise

Book turning area
With touchjs simulation, not to say, very simple

It used to bejiathisShare, can’t use after HTTPS, maybe it’s not supported

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}';

So I directly called the interface and wrote a