port drawPage function
This commit is contained in:
parent
a1766f5e54
commit
155edf4935
7 changed files with 231 additions and 113 deletions
12
app/index.js
12
app/index.js
|
@ -1,12 +1,21 @@
|
||||||
// let ComicBook = window.ComicBook = require('./comic-book')
|
// let ComicBook = window.ComicBook = require('./comic-book')
|
||||||
let Canvas = require('./view/canvas')
|
let Canvas = require('./view/canvas')
|
||||||
|
let canvas = new Canvas({ zoomMode: 'fitWidth' })
|
||||||
|
/*
|
||||||
|
let image = new window.Image()
|
||||||
|
image.onload = () => {
|
||||||
|
canvas.drawImage(image)
|
||||||
|
document.body.appendChild(canvas.canvas)
|
||||||
|
}
|
||||||
|
image.src = 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_01.jpg'
|
||||||
|
*/
|
||||||
|
|
||||||
let testImages = require('../test/data')
|
let testImages = require('../test/data')
|
||||||
let fixtureImages = require('../test/fixture')
|
let fixtureImages = require('../test/fixture')
|
||||||
let imagediff = require('imagediff')
|
let imagediff = require('imagediff')
|
||||||
|
|
||||||
testImages.portrait1((testImage) => {
|
testImages.portrait1((testImage) => {
|
||||||
fixtureImages.singlePortrait((fixtureImage) => {
|
fixtureImages.singlePortrait((fixtureImage) => {
|
||||||
let canvas = new Canvas()
|
|
||||||
canvas.drawImage(testImage)
|
canvas.drawImage(testImage)
|
||||||
|
|
||||||
console.log(imagediff.equal(canvas.canvas, fixtureImage))
|
console.log(imagediff.equal(canvas.canvas, fixtureImage))
|
||||||
|
@ -18,3 +27,4 @@ testImages.portrait1((testImage) => {
|
||||||
document.body.appendChild(canvas.canvas)
|
document.body.appendChild(canvas.canvas)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
let EventEmitter = require('events').EventEmitter
|
let EventEmitter = require('events').EventEmitter
|
||||||
|
|
||||||
|
// TODO replace
|
||||||
|
function windowWidth () {
|
||||||
|
return window.innerWidth
|
||||||
|
}
|
||||||
|
|
||||||
class Canvas extends EventEmitter {
|
class Canvas extends EventEmitter {
|
||||||
|
|
||||||
constructor (options) {
|
constructor (options) {
|
||||||
|
@ -16,74 +21,122 @@ class Canvas extends EventEmitter {
|
||||||
|
|
||||||
this.canvas = document.createElement('canvas')
|
this.canvas = document.createElement('canvas')
|
||||||
this.context = this.canvas.getContext('2d')
|
this.context = this.canvas.getContext('2d')
|
||||||
|
|
||||||
this.on('draw:start', this.clearCanvas.bind(this))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getScale () {
|
drawImage (page, page2) {
|
||||||
|
this.emit('draw:start')
|
||||||
|
|
||||||
}
|
if (!(page instanceof window.Image) || (this.options.doublePage && !(page2 instanceof window.Image))) {
|
||||||
|
throw new Error('Invalid image')
|
||||||
fitCanvasToImage (image) {
|
|
||||||
// make sure the canvas is always at least full screen, even if the page is more narrow than the screen
|
|
||||||
this.canvas.width = (this.canvas.width < window.innerWidth) ? window.innerWidth : this.canvas.width
|
|
||||||
this.canvas.height = (this.canvas.height < window.innerHeight) ? window.innerHeight : this.canvas.height
|
|
||||||
}
|
|
||||||
|
|
||||||
getDimensions (image) {
|
|
||||||
let dimensions = {
|
|
||||||
width: image.width,
|
|
||||||
height: image.height
|
|
||||||
}
|
}
|
||||||
return dimensions
|
|
||||||
}
|
|
||||||
|
|
||||||
getOffset (dimensions) {
|
let zoomScale
|
||||||
let offset = {
|
let offsetW = 0
|
||||||
width: 0,
|
let offsetH = 0
|
||||||
height: 0
|
let width = page.width
|
||||||
|
let height = page.height
|
||||||
|
let doublePageMode = this.options.doublePage
|
||||||
|
let canvasWidth
|
||||||
|
let canvasHeight
|
||||||
|
let pageWidth
|
||||||
|
let pageHeight
|
||||||
|
|
||||||
|
// reset the canvas to stop duplicate pages showing
|
||||||
|
this.canvas.width = 0
|
||||||
|
this.canvas.height = 0
|
||||||
|
|
||||||
|
// show double page spreads on a single page
|
||||||
|
let isDoublePageSpread = (
|
||||||
|
page2 &&
|
||||||
|
(page.width > page.height || page2.width > page2.height) &&
|
||||||
|
doublePageMode
|
||||||
|
)
|
||||||
|
|
||||||
|
if (isDoublePageSpread) doublePageMode = false
|
||||||
|
|
||||||
|
if (doublePageMode) {
|
||||||
|
|
||||||
|
// for double page spreads, factor in the width of both pages
|
||||||
|
if (typeof page2 === 'object') {
|
||||||
|
width += page2.width
|
||||||
|
// if this is the last page and there is no page2, still keep the canvas wide
|
||||||
|
} else {
|
||||||
|
width += width
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update the page this.scale if a non manual mode has been chosen
|
||||||
|
switch (this.options.zoomMode) {
|
||||||
|
|
||||||
|
case 'manual':
|
||||||
|
document.body.style.overflowX = 'auto'
|
||||||
|
zoomScale = (doublePageMode) ? this.scale * 2 : this.scale
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'fitWidth':
|
||||||
|
document.body.style.overflowX = 'hidden'
|
||||||
|
|
||||||
|
// this.scale up if the window is wider than the page, scale down if the window
|
||||||
|
// is narrower than the page
|
||||||
|
zoomScale = (windowWidth() > width) ? ((windowWidth() - width) / windowWidth()) + 1 : windowWidth() / width
|
||||||
|
this.scale = zoomScale
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'fitWindow':
|
||||||
|
document.body.style.overflowX = 'hidden'
|
||||||
|
|
||||||
|
let widthScale = (windowWidth() > width)
|
||||||
|
? ((windowWidth() - width) / windowWidth()) + 1 // scale up if the window is wider than the page
|
||||||
|
: windowWidth() / width // scale down if the window is narrower than the page
|
||||||
|
let windowHeight = window.innerHeight
|
||||||
|
let heightScale = (windowHeight > height)
|
||||||
|
? ((windowHeight - height) / windowHeight) + 1 // scale up if the window is wider than the page
|
||||||
|
: windowHeight / height // scale down if the window is narrower than the page
|
||||||
|
|
||||||
|
zoomScale = (widthScale > heightScale) ? heightScale : widthScale
|
||||||
|
this.scale = zoomScale
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
canvasHeight = pageHeight
|
||||||
|
|
||||||
|
// make sure the canvas is always at least full screen, even if the page is narrower than the screen
|
||||||
|
this.canvas.width = (canvasWidth < windowWidth()) ? windowWidth() : canvasWidth
|
||||||
|
this.canvas.height = (canvasHeight < window.innerHeight) ? window.innerHeight : canvasHeight
|
||||||
|
|
||||||
// always keep pages centered
|
// always keep pages centered
|
||||||
if (this.options.zoomMode === 'manual' || this.options.zoomMode === 'fitWindow') {
|
if (this.options.zoomMode === 'manual' || this.options.zoomMode === 'fitWindow') {
|
||||||
|
|
||||||
// work out a horizontal position
|
// work out a horizontal position
|
||||||
if (this.canvas.width < window.innerWidth) {
|
if (canvasWidth < windowWidth()) {
|
||||||
offset.width = (window.innerWidth - dimensions.width) / 2
|
offsetW = (windowWidth() - pageWidth) / 2
|
||||||
if (this.options.doublePage) {
|
if (this.options.doublePage) { offsetW = offsetW - pageWidth / 2 }
|
||||||
offset.width = offset.width - dimensions.width / 2
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// work out a vertical position
|
// work out a vertical position
|
||||||
if (this.canvas.height < window.innerHeight) {
|
if (canvasHeight < window.innerHeight) {
|
||||||
offset.height = (window.innerHeight - dimensions.height) / 2
|
offsetH = (window.innerHeight - pageHeight) / 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return offset
|
// in manga double page mode reverse the page(s)
|
||||||
}
|
if (this.options.manga && this.options.doublePage && typeof page2 === 'object') {
|
||||||
|
let tmpPage = page
|
||||||
clearCanvas () {
|
let tmpPage2 = page2
|
||||||
this.canvas.width = 0
|
page = tmpPage2
|
||||||
this.canvas.height = 0
|
page2 = tmpPage
|
||||||
}
|
|
||||||
|
|
||||||
drawImage (image, image2) {
|
|
||||||
this.emit('draw:start')
|
|
||||||
|
|
||||||
if (!(image instanceof window.Image) || (this.options.doublePage && !(image2 instanceof window.Image))) {
|
|
||||||
throw new Error('Invalid image')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fitCanvasToImage()
|
// draw the page(s)
|
||||||
|
this.context.drawImage(page, offsetW, offsetH, pageWidth, pageHeight)
|
||||||
let dimensions = this.getDimensions(image)
|
if (this.options.doublePage && typeof page2 === 'object') {
|
||||||
let offset = this.getOffset(dimensions)
|
this.context.drawImage(page2, pageWidth + offsetW, offsetH, pageWidth, pageHeight)
|
||||||
|
|
||||||
this.context.drawImage(image, offset.width, offset.height, dimensions.width, dimensions.height)
|
|
||||||
if (this.options.doublePage && image2) {
|
|
||||||
this.context.drawImage(image2, dimensions.width + offset.width, offset.height, dimensions.width, dimensions.height)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit('draw:finish')
|
this.emit('draw:finish')
|
||||||
|
|
168
dist/comicbook.js
vendored
168
dist/comicbook.js
vendored
|
@ -3,13 +3,22 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var Canvas = require('./view/canvas');
|
var Canvas = require('./view/canvas');
|
||||||
|
var canvas = new Canvas({ zoomMode: 'fitWidth' });
|
||||||
|
/*
|
||||||
|
let image = new window.Image()
|
||||||
|
image.onload = () => {
|
||||||
|
canvas.drawImage(image)
|
||||||
|
document.body.appendChild(canvas.canvas)
|
||||||
|
}
|
||||||
|
image.src = 'https://raw.githubusercontent.com/balaclark/HTML5-Comic-Book-Reader/master/examples/goldenboy/goldenboy_01.jpg'
|
||||||
|
*/
|
||||||
|
|
||||||
var testImages = require('../test/data');
|
var testImages = require('../test/data');
|
||||||
var fixtureImages = require('../test/fixture');
|
var fixtureImages = require('../test/fixture');
|
||||||
var imagediff = require('imagediff');
|
var imagediff = require('imagediff');
|
||||||
|
|
||||||
testImages.portrait1(function (testImage) {
|
testImages.portrait1(function (testImage) {
|
||||||
fixtureImages.singlePortrait(function (fixtureImage) {
|
fixtureImages.singlePortrait(function (fixtureImage) {
|
||||||
var canvas = new Canvas();
|
|
||||||
canvas.drawImage(testImage);
|
canvas.drawImage(testImage);
|
||||||
|
|
||||||
console.log(imagediff.equal(canvas.canvas, fixtureImage));
|
console.log(imagediff.equal(canvas.canvas, fixtureImage));
|
||||||
|
@ -48,6 +57,11 @@ var _Object$assign = require('babel-runtime/core-js/object/assign')['default'];
|
||||||
|
|
||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
|
|
||||||
|
// TODO replace
|
||||||
|
function windowWidth() {
|
||||||
|
return window.innerWidth;
|
||||||
|
}
|
||||||
|
|
||||||
var Canvas = (function (_EventEmitter) {
|
var Canvas = (function (_EventEmitter) {
|
||||||
_inherits(Canvas, _EventEmitter);
|
_inherits(Canvas, _EventEmitter);
|
||||||
|
|
||||||
|
@ -67,79 +81,121 @@ var Canvas = (function (_EventEmitter) {
|
||||||
|
|
||||||
this.canvas = document.createElement('canvas');
|
this.canvas = document.createElement('canvas');
|
||||||
this.context = this.canvas.getContext('2d');
|
this.context = this.canvas.getContext('2d');
|
||||||
|
|
||||||
this.on('draw:start', this.clearCanvas.bind(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_createClass(Canvas, [{
|
_createClass(Canvas, [{
|
||||||
key: 'getScale',
|
key: 'drawImage',
|
||||||
value: function getScale() {}
|
value: function drawImage(page, page2) {
|
||||||
}, {
|
this.emit('draw:start');
|
||||||
key: 'fitCanvasToImage',
|
|
||||||
value: function fitCanvasToImage(image) {
|
if (!(page instanceof window.Image) || this.options.doublePage && !(page2 instanceof window.Image)) {
|
||||||
// make sure the canvas is always at least full screen, even if the page is more narrow than the screen
|
throw new Error('Invalid image');
|
||||||
this.canvas.width = this.canvas.width < window.innerWidth ? window.innerWidth : this.canvas.width;
|
}
|
||||||
this.canvas.height = this.canvas.height < window.innerHeight ? window.innerHeight : this.canvas.height;
|
|
||||||
}
|
var zoomScale = undefined;
|
||||||
}, {
|
var offsetW = 0;
|
||||||
key: 'getDimensions',
|
var offsetH = 0;
|
||||||
value: function getDimensions(image) {
|
var width = page.width;
|
||||||
var dimensions = {
|
var height = page.height;
|
||||||
width: image.width,
|
var doublePageMode = this.options.doublePage;
|
||||||
height: image.height
|
var canvasWidth = undefined;
|
||||||
};
|
var canvasHeight = undefined;
|
||||||
return dimensions;
|
var pageWidth = undefined;
|
||||||
}
|
var pageHeight = undefined;
|
||||||
}, {
|
|
||||||
key: 'getOffset',
|
// reset the canvas to stop duplicate pages showing
|
||||||
value: function getOffset(dimensions) {
|
this.canvas.width = 0;
|
||||||
var offset = {
|
this.canvas.height = 0;
|
||||||
width: 0,
|
|
||||||
height: 0
|
// show double page spreads on a single page
|
||||||
};
|
var isDoublePageSpread = page2 && (page.width > page.height || page2.width > page2.height) && doublePageMode;
|
||||||
|
|
||||||
|
if (isDoublePageSpread) doublePageMode = false;
|
||||||
|
|
||||||
|
if (doublePageMode) {
|
||||||
|
|
||||||
|
// for double page spreads, factor in the width of both pages
|
||||||
|
if (typeof page2 === 'object') {
|
||||||
|
width += page2.width
|
||||||
|
// if this is the last page and there is no page2, still keep the canvas wide
|
||||||
|
;
|
||||||
|
} else {
|
||||||
|
width += width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the page this.scale if a non manual mode has been chosen
|
||||||
|
switch (this.options.zoomMode) {
|
||||||
|
|
||||||
|
case 'manual':
|
||||||
|
document.body.style.overflowX = 'auto';
|
||||||
|
zoomScale = doublePageMode ? this.scale * 2 : this.scale;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'fitWidth':
|
||||||
|
document.body.style.overflowX = 'hidden';
|
||||||
|
|
||||||
|
// this.scale up if the window is wider than the page, scale down if the window
|
||||||
|
// is narrower than the page
|
||||||
|
zoomScale = windowWidth() > width ? (windowWidth() - width) / windowWidth() + 1 : windowWidth() / width;
|
||||||
|
this.scale = zoomScale;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'fitWindow':
|
||||||
|
document.body.style.overflowX = 'hidden';
|
||||||
|
|
||||||
|
var widthScale = windowWidth() > width ? (windowWidth() - width) / windowWidth() + 1 // scale up if the window is wider than the page
|
||||||
|
: windowWidth() / width; // scale down if the window is narrower than the page
|
||||||
|
var windowHeight = window.innerHeight;
|
||||||
|
var heightScale = windowHeight > height ? (windowHeight - height) / windowHeight + 1 // scale up if the window is wider than the page
|
||||||
|
: windowHeight / height; // scale down if the window is narrower than the page
|
||||||
|
|
||||||
|
zoomScale = widthScale > heightScale ? heightScale : widthScale;
|
||||||
|
this.scale = zoomScale;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
canvasHeight = pageHeight;
|
||||||
|
|
||||||
|
// make sure the canvas is always at least full screen, even if the page is narrower than the screen
|
||||||
|
this.canvas.width = canvasWidth < windowWidth() ? windowWidth() : canvasWidth;
|
||||||
|
this.canvas.height = canvasHeight < window.innerHeight ? window.innerHeight : canvasHeight;
|
||||||
|
|
||||||
// always keep pages centered
|
// always keep pages centered
|
||||||
if (this.options.zoomMode === 'manual' || this.options.zoomMode === 'fitWindow') {
|
if (this.options.zoomMode === 'manual' || this.options.zoomMode === 'fitWindow') {
|
||||||
|
|
||||||
// work out a horizontal position
|
// work out a horizontal position
|
||||||
if (this.canvas.width < window.innerWidth) {
|
if (canvasWidth < windowWidth()) {
|
||||||
offset.width = (window.innerWidth - dimensions.width) / 2;
|
offsetW = (windowWidth() - pageWidth) / 2;
|
||||||
if (this.options.doublePage) {
|
if (this.options.doublePage) {
|
||||||
offset.width = offset.width - dimensions.width / 2;
|
offsetW = offsetW - pageWidth / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// work out a vertical position
|
// work out a vertical position
|
||||||
if (this.canvas.height < window.innerHeight) {
|
if (canvasHeight < window.innerHeight) {
|
||||||
offset.height = (window.innerHeight - dimensions.height) / 2;
|
offsetH = (window.innerHeight - pageHeight) / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return offset;
|
// in manga double page mode reverse the page(s)
|
||||||
}
|
if (this.options.manga && this.options.doublePage && typeof page2 === 'object') {
|
||||||
}, {
|
var tmpPage = page;
|
||||||
key: 'clearCanvas',
|
var tmpPage2 = page2;
|
||||||
value: function clearCanvas() {
|
page = tmpPage2;
|
||||||
this.canvas.width = 0;
|
page2 = tmpPage;
|
||||||
this.canvas.height = 0;
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'drawImage',
|
|
||||||
value: function drawImage(image, image2) {
|
|
||||||
this.emit('draw:start');
|
|
||||||
|
|
||||||
if (!(image instanceof window.Image) || this.options.doublePage && !(image2 instanceof window.Image)) {
|
|
||||||
throw new Error('Invalid image');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fitCanvasToImage();
|
// draw the page(s)
|
||||||
|
this.context.drawImage(page, offsetW, offsetH, pageWidth, pageHeight);
|
||||||
var dimensions = this.getDimensions(image);
|
if (this.options.doublePage && typeof page2 === 'object') {
|
||||||
var offset = this.getOffset(dimensions);
|
this.context.drawImage(page2, pageWidth + offsetW, offsetH, pageWidth, pageHeight);
|
||||||
|
|
||||||
this.context.drawImage(image, offset.width, offset.height, dimensions.width, dimensions.height);
|
|
||||||
if (this.options.doublePage && image2) {
|
|
||||||
this.context.drawImage(image2, dimensions.width + offset.width, offset.height, dimensions.width, dimensions.height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit('draw:finish');
|
this.emit('draw:finish');
|
||||||
|
|
6
dist/comicbook.js.map
vendored
6
dist/comicbook.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/comicbook.min.js
vendored
4
dist/comicbook.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/comicbook.min.js.map
vendored
2
dist/comicbook.min.js.map
vendored
File diff suppressed because one or more lines are too long
|
@ -20,7 +20,6 @@ describe('Canvas', function () {
|
||||||
|
|
||||||
it('should draw a single page', (done) => {
|
it('should draw a single page', (done) => {
|
||||||
let canvas = new Canvas()
|
let canvas = new Canvas()
|
||||||
// TODO update fixture once centering is working again
|
|
||||||
testImage.portrait1((testImage) => {
|
testImage.portrait1((testImage) => {
|
||||||
fixtureImage.singlePortrait((fixtureImage) => {
|
fixtureImage.singlePortrait((fixtureImage) => {
|
||||||
canvas.drawImage(testImage)
|
canvas.drawImage(testImage)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue