double page mode, sinon.spy instead of spy, pass opts directly to drawImage

This commit is contained in:
Bala Clark 2015-07-19 14:12:08 +02:00
parent 8ab949583f
commit ee877d0f1b
11 changed files with 145 additions and 97 deletions

View file

@ -80,10 +80,20 @@ class ComicBook extends EventEmitter {
drawPage (pageIndex) {
if (typeof pageIndex !== 'number') pageIndex = this.currentPageIndex
let page = this.pages.get(pageIndex)
let args = [ this.pages.get(pageIndex) ]
if (this.options.doublePage) {
args.push(this.pages.get(pageIndex + 1))
if (this.options.rtl) {
args.reverse()
}
}
args.push(this.options)
try {
this.canvas.drawImage(page)
this.canvas.drawImage.apply(this.canvas, args)
this.currentPageIndex = pageIndex
} catch (e) {
if (e.message !== 'Invalid image') throw e

View file

@ -1,5 +1,5 @@
let ComicBook = window.ComicBook = require('./comic-book')
let comic = window.comic = new ComicBook([
let srcs = [
'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_00.jpg',
'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_01.jpg',
'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_02.jpg',
@ -11,7 +11,8 @@ let comic = window.comic = new ComicBook([
'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_08.jpg',
'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_09.jpg',
'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_10.jpg'
])
]
let comic = window.comic = new ComicBook(srcs, { doublePage: true })
comic.preload()
comic.render()

View file

@ -9,24 +9,23 @@ class Canvas extends EventEmitter {
constructor (options) {
super()
this.options = Object.assign({
// fitWidth, fitWindow, manua
zoomMode: 'fitWidth',
// manga mode
rtl: false,
// should two pages be rendered at a time?
doublePage: false
}, options)
this.canvas = document.createElement('canvas')
this.context = this.canvas.getContext('2d')
}
drawImage (page, page2) {
drawImage (page, page2, opts = {}) {
this.emit('draw:start')
if (!(page instanceof window.Image) || (this.options.doublePage && !(page2 instanceof window.Image))) {
if (!(page2 instanceof window.Image)) {
opts = page2
}
let options = Object.assign({
doublePage: false,
zoomMode: 'fitWidth'
}, opts)
if (!(page instanceof window.Image) || (options.doublePage && !(page2 instanceof window.Image))) {
throw new Error('Invalid image')
}
@ -35,7 +34,7 @@ class Canvas extends EventEmitter {
let offsetH = 0
let width = page.width
let height = page.height
let doublePageMode = this.options.doublePage
let doublePageMode = options.doublePage
let canvasWidth
let canvasHeight
let pageWidth
@ -66,7 +65,7 @@ class Canvas extends EventEmitter {
}
// update the page this.scale if a non manual mode has been chosen
switch (this.options.zoomMode) {
switch (options.zoomMode) {
case 'manual':
document.body.style.overflowX = 'auto'
@ -101,8 +100,8 @@ class Canvas extends EventEmitter {
canvasWidth = page.width * zoomScale
canvasHeight = page.height * zoomScale
pageWidth = (this.options.zoomMode === 'manual') ? page.width * this.scale : canvasWidth
pageHeight = (this.options.zoomMode === 'manual') ? page.height * this.scale : canvasHeight
pageWidth = (options.zoomMode === 'manual') ? page.width * this.scale : canvasWidth
pageHeight = (options.zoomMode === 'manual') ? page.height * this.scale : canvasHeight
canvasHeight = pageHeight
@ -111,12 +110,12 @@ class Canvas extends EventEmitter {
this.canvas.height = (canvasHeight < window.innerHeight) ? window.innerHeight : canvasHeight
// always keep pages centered
if (this.options.zoomMode === 'manual' || this.options.zoomMode === 'fitWindow') {
if (options.zoomMode === 'manual' || options.zoomMode === 'fitWindow') {
// work out a horizontal position
if (canvasWidth < windowWidth()) {
offsetW = (windowWidth() - pageWidth) / 2
if (this.options.doublePage) { offsetW = offsetW - pageWidth / 2 }
if (options.doublePage) { offsetW = offsetW - pageWidth / 2 }
}
// work out a vertical position
@ -125,17 +124,9 @@ class Canvas extends EventEmitter {
}
}
// in manga double page mode reverse the page(s)
if (this.options.rtl && this.options.doublePage && typeof page2 === 'object') {
let tmpPage = page
let tmpPage2 = page2
page = tmpPage2
page2 = tmpPage
}
// draw the page(s)
this.context.drawImage(page, offsetW, offsetH, pageWidth, pageHeight)
if (this.options.doublePage && typeof page2 === 'object') {
if (options.doublePage && typeof page2 === 'object') {
this.context.drawImage(page2, pageWidth + offsetW, offsetH, pageWidth, pageHeight)
}

62
dist/comicbook.js vendored
View file

@ -108,10 +108,20 @@ var ComicBook = (function (_EventEmitter) {
key: 'drawPage',
value: function drawPage(pageIndex) {
if (typeof pageIndex !== 'number') pageIndex = this.currentPageIndex;
var page = this.pages.get(pageIndex);
var args = [this.pages.get(pageIndex)];
if (this.options.doublePage) {
args.push(this.pages.get(pageIndex + 1));
if (this.options.rtl) {
args.reverse();
}
}
args.push(this.options);
try {
this.canvas.drawImage(page);
this.canvas.drawImage.apply(this.canvas, args);
this.currentPageIndex = pageIndex;
} catch (e) {
if (e.message !== 'Invalid image') throw e;
@ -146,7 +156,8 @@ module.exports = ComicBook;
'use strict';
var ComicBook = window.ComicBook = require('./comic-book');
var comic = window.comic = new ComicBook(['https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_00.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_01.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_02.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_03.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_04.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_05.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_06.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_07.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_08.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_09.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_10.jpg']);
var srcs = ['https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_00.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_01.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_02.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_03.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_04.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_05.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_06.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_07.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_08.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_09.jpg', 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_10.jpg'];
var comic = window.comic = new ComicBook(srcs, { doublePage: true });
comic.preload();
comic.render();
@ -182,16 +193,6 @@ var Canvas = (function (_EventEmitter) {
_classCallCheck(this, Canvas);
_get(Object.getPrototypeOf(Canvas.prototype), 'constructor', this).call(this);
this.options = _Object$assign({
// fitWidth, fitWindow, manua
zoomMode: 'fitWidth',
// manga mode
rtl: false,
// should two pages be rendered at a time?
doublePage: false
}, options);
this.canvas = document.createElement('canvas');
this.context = this.canvas.getContext('2d');
}
@ -199,9 +200,20 @@ var Canvas = (function (_EventEmitter) {
_createClass(Canvas, [{
key: 'drawImage',
value: function drawImage(page, page2) {
var opts = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
this.emit('draw:start');
if (!(page instanceof window.Image) || this.options.doublePage && !(page2 instanceof window.Image)) {
if (!(page2 instanceof window.Image)) {
opts = page2;
}
var options = _Object$assign({
doublePage: false,
zoomMode: 'fitWidth'
}, opts);
if (!(page instanceof window.Image) || options.doublePage && !(page2 instanceof window.Image)) {
throw new Error('Invalid image');
}
@ -210,7 +222,7 @@ var Canvas = (function (_EventEmitter) {
var offsetH = 0;
var width = page.width;
var height = page.height;
var doublePageMode = this.options.doublePage;
var doublePageMode = options.doublePage;
var canvasWidth = undefined;
var canvasHeight = undefined;
var pageWidth = undefined;
@ -238,7 +250,7 @@ var Canvas = (function (_EventEmitter) {
}
// update the page this.scale if a non manual mode has been chosen
switch (this.options.zoomMode) {
switch (options.zoomMode) {
case 'manual':
document.body.style.overflowX = 'auto';
@ -271,8 +283,8 @@ var Canvas = (function (_EventEmitter) {
canvasWidth = page.width * zoomScale;
canvasHeight = page.height * zoomScale;
pageWidth = this.options.zoomMode === 'manual' ? page.width * this.scale : canvasWidth;
pageHeight = this.options.zoomMode === 'manual' ? page.height * this.scale : canvasHeight;
pageWidth = options.zoomMode === 'manual' ? page.width * this.scale : canvasWidth;
pageHeight = options.zoomMode === 'manual' ? page.height * this.scale : canvasHeight;
canvasHeight = pageHeight;
@ -281,12 +293,12 @@ var Canvas = (function (_EventEmitter) {
this.canvas.height = canvasHeight < window.innerHeight ? window.innerHeight : canvasHeight;
// always keep pages centered
if (this.options.zoomMode === 'manual' || this.options.zoomMode === 'fitWindow') {
if (options.zoomMode === 'manual' || options.zoomMode === 'fitWindow') {
// work out a horizontal position
if (canvasWidth < windowWidth()) {
offsetW = (windowWidth() - pageWidth) / 2;
if (this.options.doublePage) {
if (options.doublePage) {
offsetW = offsetW - pageWidth / 2;
}
}
@ -297,17 +309,9 @@ var Canvas = (function (_EventEmitter) {
}
}
// in manga double page mode reverse the page(s)
if (this.options.rtl && this.options.doublePage && typeof page2 === 'object') {
var tmpPage = page;
var tmpPage2 = page2;
page = tmpPage2;
page2 = tmpPage;
}
// draw the page(s)
this.context.drawImage(page, offsetW, offsetH, pageWidth, pageHeight);
if (this.options.doublePage && typeof page2 === 'object') {
if (options.doublePage && typeof page2 === 'object') {
this.context.drawImage(page2, pageWidth + offsetW, offsetH, pageWidth, pageHeight);
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

15
npm-shrinkwrap.json generated
View file

@ -1019,6 +1019,11 @@
}
}
},
"formatio": {
"version": "1.1.1",
"from": "formatio@1.1.1",
"resolved": "http://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz"
},
"fs-extra": {
"version": "0.18.4",
"from": "fs-extra@>=0.18.0 <0.19.0",
@ -1514,6 +1519,11 @@
"from": "lodash.restparam@>=3.0.0 <4.0.0",
"resolved": "http://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz"
},
"lolex": {
"version": "1.1.0",
"from": "lolex@1.1.0",
"resolved": "http://registry.npmjs.org/lolex/-/lolex-1.1.0.tgz"
},
"lru-cache": {
"version": "2.6.5",
"from": "lru-cache@>=2.0.0 <3.0.0",
@ -2162,6 +2172,11 @@
"from": "rx@>=2.4.3 <3.0.0",
"resolved": "http://registry.npmjs.org/rx/-/rx-2.5.3.tgz"
},
"samsam": {
"version": "1.1.2",
"from": "samsam@1.1.2",
"resolved": "http://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz"
},
"saucelabs": {
"version": "0.1.1",
"from": "saucelabs@>=0.1.1 <0.2.0",

View file

@ -55,6 +55,7 @@
"imagediff": "^1.0.8",
"mochify": "^2.10.0",
"phantomjs": "^1.9.17",
"sinon": "^1.15.4",
"spy": "^0.1.3",
"standard": "^4.5.3",
"uglify-js": "^2.4.23",

View file

@ -1,5 +1,5 @@
let assert = require('assert')
let spy = require('spy')
let sinon = require('sinon')
let ComicBook = require('../app/comic-book')
let srcs = [
'data:image/gif;base64,R0lGODlhAQABAPAAAKqqqv///yH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==',
@ -71,16 +71,16 @@ describe('ComicBook', () => {
it('should update the progress bar', done => {
let comic = new ComicBook(srcs)
comic.progressBar.update = spy()
comic.progressBar.update = sinon.spy()
comic.preload()
comic.on('preload:finish', () => {
assert.equal(comic.progressBar.update.callCount, 5)
assert(comic.progressBar.update.calls[0].calledWith(20))
assert(comic.progressBar.update.calls[1].calledWith(40))
assert(comic.progressBar.update.calls[2].calledWith(60))
assert(comic.progressBar.update.calls[3].calledWith(80))
assert(comic.progressBar.update.calls[4].calledWith(100))
assert(comic.progressBar.update.getCall(0).calledWith(20))
assert(comic.progressBar.update.getCall(1).calledWith(40))
assert(comic.progressBar.update.getCall(2).calledWith(60))
assert(comic.progressBar.update.getCall(3).calledWith(80))
assert(comic.progressBar.update.getCall(4).calledWith(100))
done()
})
})
@ -106,24 +106,24 @@ describe('ComicBook', () => {
it('should draw a given page', () => {
let comic = new ComicBook(srcs)
comic.canvas.drawImage = spy()
comic.canvas.drawImage = sinon.spy()
comic.drawPage(1)
assert.equal(comic.canvas.drawImage.callCount, 1)
assert(comic.canvas.drawImage.calls[0].calledWith(comic.pages.get(1)))
assert(comic.canvas.drawImage.getCall(0).calledWith(comic.pages.get(1)))
})
it('should default to drawing the current page', () => {
let comic = new ComicBook(srcs)
comic.canvas.drawImage = spy()
comic.canvas.drawImage = sinon.spy()
comic.currentPageIndex = 2
comic.drawPage()
assert.equal(comic.canvas.drawImage.callCount, 1)
assert(comic.canvas.drawImage.calls[0].calledWith(comic.pages.get(2)))
assert(comic.canvas.drawImage.getCall(0).calledWith(comic.pages.get(2)))
})
it('should update the current page index after drawing', () => {
@ -154,7 +154,37 @@ describe('ComicBook', () => {
assert.throws(comic.drawPage.bind(comic))
})
it('should draw two pages in double page mode')
it('should draw two pages in double page mode', done => {
let comic = new ComicBook(srcs, { doublePage: true })
comic.canvas.drawImage = sinon.spy()
comic.on('preload:finish', () => {
comic.drawPage(0)
assert(comic.canvas.drawImage.calledWith(comic.pages.get(0), comic.pages.get(1)))
done()
})
comic.preload()
})
it('should reverse page order in manga double page mode', done => {
let comic = new ComicBook(srcs, {
doublePage: true,
rtl: true
})
comic.canvas.drawImage = sinon.spy()
comic.on('preload:finish', () => {
comic.drawPage(0)
assert(comic.canvas.drawImage.calledWith(comic.pages.get(1), comic.pages.get(0)))
done()
})
comic.preload()
})
})
describe('drawNextPage()', () => {
@ -162,12 +192,12 @@ describe('ComicBook', () => {
it('should draw the next page', done => {
let comic = new ComicBook(srcs)
comic.drawPage = spy()
comic.drawPage = sinon.spy()
comic.currentPageIndex = 1
comic.on('preload:finish', () => {
comic.drawNextPage()
assert(comic.drawPage.calls[0].calledWith(2))
assert(comic.drawPage.getCall(0).calledWith(2))
done()
})
@ -177,13 +207,13 @@ describe('ComicBook', () => {
it('should draw the next page in double page mode', done => {
let comic = new ComicBook(srcs)
comic.drawPage = spy()
comic.drawPage = sinon.spy()
comic.currentPageIndex = 1
comic.options.doublePage = true
comic.on('preload:finish', () => {
comic.drawNextPage()
assert(comic.drawPage.calls[0].calledWith(3))
assert(comic.drawPage.getCall(0).calledWith(3))
done()
})
@ -193,13 +223,13 @@ describe('ComicBook', () => {
it('should handle the final page of double page mode being a single page', done => {
let comic = new ComicBook(srcs)
comic.drawPage = spy()
comic.drawPage = sinon.spy()
comic.currentPageIndex = 3
comic.options.doublePage = true
comic.on('preload:finish', () => {
comic.drawNextPage()
assert(comic.drawPage.calls[0].calledWith(4))
assert(comic.drawPage.getCall(0).calledWith(4))
done()
})
@ -212,12 +242,12 @@ describe('ComicBook', () => {
it('should draw the previous page', done => {
let comic = new ComicBook(srcs)
comic.drawPage = spy()
comic.drawPage = sinon.spy()
comic.currentPageIndex = 2
comic.on('preload:finish', () => {
comic.drawPreviousPage()
assert(comic.drawPage.calls[0].calledWith(1))
assert(comic.drawPage.getCall(0).calledWith(1))
done()
})
@ -227,13 +257,13 @@ describe('ComicBook', () => {
it('should draw the previous page in double page mode', done => {
let comic = new ComicBook(srcs)
comic.drawPage = spy()
comic.drawPage = sinon.spy()
comic.currentPageIndex = 3
comic.options.doublePage = true
comic.on('preload:finish', () => {
comic.drawPreviousPage()
assert(comic.drawPage.calls[0].calledWith(1))
assert(comic.drawPage.getCall(0).calledWith(1))
done()
})
@ -243,20 +273,18 @@ describe('ComicBook', () => {
it('should handle navigating back to an uneven first page in double page mode', done => {
let comic = new ComicBook(srcs)
comic.drawPage = spy()
comic.drawPage = sinon.spy()
comic.currentPageIndex = 1
comic.options.doublePage = true
comic.on('preload:finish', () => {
comic.drawPreviousPage()
assert(comic.drawPage.calls[0].calledWith(0))
assert(comic.drawPage.getCall(0).calledWith(0))
done()
})
comic.preload()
})
it('should reverse image order in double page manga mode')
})
})

View file

@ -12,10 +12,8 @@ describe('Canvas', function () {
assert.throws(canvas.drawImage, 'Invalid image')
canvas.options.doublePage = true
assert.throws(canvas.drawImage.bind(canvas, image), 'Invalid image')
assert.doesNotThrow(canvas.drawImage.bind(canvas, image, image), 'Invalid image')
assert.throws(canvas.drawImage.bind(canvas, image, { doublePage: true }), 'Invalid image')
assert.doesNotThrow(canvas.drawImage.bind(canvas, image, image, { doublePage: true }), 'Invalid image')
})
// TODO fix test