Turn.jsを用いて雑誌や本のようなページを作成してみよう！

#Turn.jsとは

こんな風に雑誌や本のようにページをめくるエフェクトをつけられるプラグインです。

[公式サイトはこちら](http://www.turnjs.com/)

![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379424/c3730311-4cb0-ee63-5a3e-07365042bcc7.gif)




##必要なもの
jQuery ver 1.3以上
turn.js([公式サイト](http://www.turnjs.com/)からダウンロード)


##作成したもの（宣伝）

Turn.jsを使用して自己紹介ページを作成してみました。(一番最初のgifアニメのやつです)是非ご覧ください

https://masibw.github.io/portfolio/

また、このサイトのソースコードもこちらにあります。参考になれば幸いです。

https://github.com/masibw/portfolio

##基本

まずは1番シンプルなものを作成してみましょう

![simple.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379424/097880f2-ce71-706d-1915-5e2bde080df9.gif)


```html:example.html
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="example.css" />
<script src="https://code.jquery.com/jquery-3.4.1.min.js"
    integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" 
    crossorigin="anonymous"></script> <!--jQueryをCDNから取得-->
<script type="text/javascript" src="turn.js"></script>
</head>
<body>
<div id="flipbook">
    <div>page1</div>
    <div>page2</div>
    <div>page3</div>
    <div>page4</div>
    <div>page5</div>
    <div>page6</div>
</div>
</body>
<script type="text/javascript">
	$("#flipbook").turn({
	});
</script>
</html>
```

```css:example.css
div {
  color: white; /* 文字色を白色に */
}

.odd {
  background-color: blue;/* 奇数ページを青色に */
}
.even {
  background-color: green;/* 偶数ページを緑色に */
}

#flipbook {
  width: 400px; /* flipbook自体の横幅なので各ページは200px */
  height: 400px;
  margin: 10% 20%; /* 一番左端だとたまに見切れるので適当に移動 */
}
```


指定したdiv要素の中に含まれる第一階層のdiv要素をページとして認識してくれます。

oddやevenクラスを指定することで奇数ページや偶数ページ用の指定もできます。

サイズは上記のようにCSSでも設定できますし下記のようにJavaScriptで指定することもできます。(jsでの単位はpx)

```example.html
<script type="text/javascript">
	$("#flipbook").turn({
          width:400,
          height:400,
	});
</script>
```

##様々なクラス

###hard 
ページをめくるエフェクトがハードカバーのようになります

###fixed
ページをめくっても残ります

###own-size
指定したページに独自の大きさを設定できます


これらを組み合わせると表紙が大きく中身は一回り小さいものが作れるのでこんな感じになります。

![fixed.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379424/79edfbe0-2e70-4305-2e50-dae7fca1866e.gif)

```example.html
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="example.css" />
<script src="https://code.jquery.com/jquery-3.4.1.min.js"
    integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script type="text/javascript" src="turn.js"></script>
</head>
<body>
<div id="flipbook">
    <div class="hard own-size">page1</div>
    <div class="hard own-size">page2</div>
    <div>page3</div>
    <div>page4</div>
    <div class="hard own-size">page5</div>
    <div class="hard own-size">page6</div>
</div>
</body>
<script type="text/javascript">
	$("#flipbook").turn({
        when:{
            turning: function(e,page,view){
                const book = $(this),
                pages=book.turn("pages");
                 if (page >= 2) $("#flipbook .p2").addClass("fixed");
                else $("#flipbook .p2").removeClass("fixed");

                if (page < book.turn("pages"))
                    $("#flipbook .p5").addClass("fixed");
                else $("#flipbook .p5").removeClass("fixed");
               
            }
        }
    });
    
   
</script>
</html>
```

```example.css
div {
  color: white;
}

.odd {
  background-color: blue;
}
.even {
  background-color: green;
}

.p1,
.p2,
.p5,
.p6 {
  width: 250px;
  height: 500px;
  background-color: brown;
}

#flipbook {
  width: 400px;
  height: 400px;
  margin: 10% 20%;
}

```

各ページについては自動的にp（ページ数）クラスが付与されるためこちらを使用してcssやjsで操作します。



##インデックスタブをつける

特定のページに飛ぶインデックスタブを付けるにはタブ用のdiv要素を作成し**ignore="1"**を付与します。

<img width="522" alt="スクリーンショット 2019-07-23 21.12.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379424/8f3bc92d-de60-ca9d-4523-4ee1e14829dc.png">

```example.html
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="example.css" />
<script src="https://code.jquery.com/jquery-3.4.1.min.js"
    integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script type="text/javascript" src="turn.js"></script>
</head>
<body>
<div id="flipbook">
    <div ignore="1" class="tabs">
        <div class="left"></div>
    </div>
    <div class="hard own-size">page1</div>
    <div class="hard own-size">page2</div>
    <div>page3</div>
    <div>page4</div>
    <div class="hard own-size">page5</div>
    <div class="hard own-size">page6</div>
    <div ignore="1" class="tabs">
        <div class="right"></div>
    </div>
</div>
</body>
<script type="text/javascript">
    function updateTabs() { //タブ更新用
        var tabs = {
            2: "page2", //左にページ数右にタブに表示される文字を記載
            3: "page3",
            4: "page4",
            5: "page5"
        },
            left = [],
            right = [],
            book = $(" #flipbook"),
            actualPage = book.turn("page"),
            view = book.turn("view");

        for (var page in tabs) {
            var isHere = $.inArray(parseInt(page, 10), view) != -1;

            if (page > actualPage && !isHere)
                right.push('<a href="#page/' + page + '">' + tabs[page] + "</a>");
            else if (isHere) {
                if (page % 2 === 0)
                    left.push(
                        '<a href="#page/' + page + '" class="on">' + tabs[page] + "</a>"
                    );
                else
                    right.push(
                        '<a href="#page/' + page + '" class="on">' + tabs[page] + "</a>"
                    );
            } else left.push('<a href="#page/' + page + '">' + tabs[page] + "</a>");
        }

        $(" #flipbook .tabs .left").html(left.join(""));
        $(" #flipbook .tabs .right").html(right.join(""));
    }

	$("#flipbook").turn({
        when:{
            turning: function(e,page,view){ //ページがめくられ始めたとき
                const book = $(this),
                pages=book.turn("pages");
                 if (page >= 2) $("#flipbook .p2").addClass("fixed");
                else $("#flipbook .p2").removeClass("fixed");

                if (page < book.turn("pages"))
                    $("#flipbook .p5").addClass("fixed");
                else $("#flipbook .p5").removeClass("fixed");
               
            },
            turned: function(e,page,view){ //ページがめくられ終わったとき
                var book=$(this);
                if(page!=1&& page!=book.turn("pages")) //１ページ目と最後のページの場合はタブを消す
                $(" #flipbook .tabs").fadeIn(500);
                else $("#flipbook .tabs").hide();
                updateTabs(); //タブの更新を呼ぶ
            }
        }
    });
</script>
</html>
```

```example.css
div {
  color: white;
}

.odd {
  background-color: blue;
}
.even {
  background-color: green;
}

.p1,
.p2,
.p5,
.p6 {
  width: 250px;
  height: 500px;
  background-color: brown;
}

#flipbook {
  width: 400px;
  height: 400px;
  margin: 10% 20%;
}
/* タブについて*/
.tabs .left {
  -webkit-writing-mode: vertical-lr; /*縦書き 参考 https://qiita.com/RinoTsuka/items/3e3eaaba8cddb6ff08e9 */
  -ms-writing-mode: tb-lr;
  writing-mode: vertical-lr;
  display: block;
  z-index: 10000; /* 一番上に表示されるように（いらないかも？)*/
  position: relative;
  left: -40px;
  text-orientation: upright;
  width: 30px;
  text-align: left;
}

.tabs .right {
  -webkit-writing-mode: vertical-rl;
  -ms-writing-mode: tb-rl;
  writing-mode: vertical-rl;
  display: inline-block;
  z-index: 100000;
  position: relative;
  right: -40px;
  width: 30px;
  float: right;
  text-orientation: upright;
}

.tabs a {
  text-decoration: none;
  color: #333;
  margin: 5px;
  border: 1px solid;
  background-color: #98fb98;
  display: inline-block;
  padding: 5px;
}

/* 角丸にする*/
.tabs .left a {
  border-top-left-radius: 10px;
  border-bottom-left-radius: 10px;
}

.tabs .right a {
  border-top-right-radius: 10px;
  border-bottom-right-radius: 10px;
}

.tabs a:hover {
  /* マウスオーバー時透明度を0.8にしポインターカーソルにする*/
  cursor: pointer;
  opacity: 0.8;
}
```

公式のサンプルには横書きで本の上部につけるインデックスタブも用意されているので是非参考にしてください。



##スマホ用表示について

現在のように両開きはスマホなどでは非常に見にくいですので単ページ表示にしましょう

>display:'single'

このオプションを追加すればOKです

スマホではタブなどもせまくて必要ないと思いますので再度シンプルな状態に戻したいと思います。

![single.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379424/9eaa56b0-ab90-57b0-1d95-cf46df1d50e8.gif)



###注意： single表示ではhard,fixed,own-size,odd,even クラスを使用しているとうまく動作しなくなります。

ですので実際はwindowsizeを取得して

$('.hard').removeClass("hard").removeClass("fixed").removeClass("own-size");
などで条件分岐により削除する必要があります

CSSもodd,evenを使用しないものに変更する必要があります。

```example.html
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="example.css" />
<script src="https://code.jquery.com/jquery-3.4.1.min.js"
    integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script type="text/javascript" src="turn.js"></script>
</head>
<body>
<div id="flipbook">
    <div>page1</div>
    <div>page2</div>
    <div>page3</div>
    <div>page4</div>
    <div>page5</div>
    <div>page6</div>
</div>
</body>
<script type="text/javascript">
	$("#flipbook").turn({
        display:'single',
    });
</script>
</html>
```

```example.css
div {
  color: white;
}

.p1,
.p2,
.p3,
.p4,
.p5,
.p6 {
  width: 250px;
  height: 500px;
  background-color: brown;
}

#flipbook {
  width: 400px;
  height: 400px;
  margin: 10% 20%;
}

```



##おわりに

今回はTurn.jsを使用して詰まったところを中心に記載しました。中々日本語での解説記事もなく解決に時間がかかったので誰かの役に立てば幸いです。

最後になりましたがこれらのコードや解説は動くことを重点に置いており、効率や使用方法が適切であるとは言い切れませんのでご注意ください。また、アップデートなどにより執筆時とは違う可能性もあります。


何か内容に問題等ありましたら連絡ください

公式サイトにもドキュメント・サンプルが充実しているため是非ご覧ください。

##参考サイト及びライセンス表示

[CSS3で縦書きにする方法と挙動](https://qiita.com/RinoTsuka/items/3e3eaaba8cddb6ff08e9)

[Turn.js](http://www.turnjs.com/)

/**
 * turn.js 4th release
 * turnjs.com
 * turnjs.com/license.txt
 *
 * Copyright (C) 2012 Emmanuel Garcia
 * All rights reserved
 **/