Support viewport resizing (#16)
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import {has, toFixed} from './utils.js';
|
import {has} from './utils.js';
|
||||||
|
import {pick} from './funky';
|
||||||
|
|
||||||
const SETTINGS_DEFAULTS = {
|
const DEFAULTS = {
|
||||||
// in pixels
|
// in pixels
|
||||||
scale: 50,
|
scale: 50,
|
||||||
scaleMin: 10,
|
scaleMin: 10,
|
||||||
@@ -17,18 +18,20 @@ export default class Cartographer {
|
|||||||
|
|
||||||
'move',
|
'move',
|
||||||
'_checkMove',
|
'_checkMove',
|
||||||
'_setOriginX',
|
'setOriginX',
|
||||||
'_setOriginY',
|
'setOriginY',
|
||||||
|
|
||||||
'zoom',
|
'zoom',
|
||||||
].map(method => this[method] = this[method].bind(this));
|
].map(method => this[method] = this[method].bind(this));
|
||||||
|
|
||||||
Object.assign(this, SETTINGS_DEFAULTS, settings);
|
this.settings = Object.assign({}, DEFAULTS, settings);
|
||||||
|
|
||||||
this._checkScale(this.canvasHeight, this.canvasWidth);
|
Object.assign(this, pick(this.settings, ['height', 'width', 'negativeTiles']));
|
||||||
|
|
||||||
this._setOriginX();
|
this.checkScale(this.settings.canvasHeight, this.settings.canvasWidth);
|
||||||
this._setOriginY();
|
|
||||||
|
this.setOriginX(this.settings.canvasWidth, this.settings.centerX);
|
||||||
|
this.setOriginY(this.settings.canvasHeight, this.settings.centerY);
|
||||||
}
|
}
|
||||||
|
|
||||||
getOriginX() {return this.originX;}
|
getOriginX() {return this.originX;}
|
||||||
@@ -36,41 +39,43 @@ export default class Cartographer {
|
|||||||
|
|
||||||
getScale() {return this.scale;}
|
getScale() {return this.scale;}
|
||||||
|
|
||||||
_checkScale(canvasHeight, canvasWidth) {
|
checkScale(canvasHeight, canvasWidth) {
|
||||||
const heightMin = this.height ? this.calculateVerticalScale(canvasHeight, this.height) : 0;
|
const heightMin = this.height ? this.calculateVerticalScale(canvasHeight, this.height) : 0;
|
||||||
const widthMin = this.width ? this.calculateHorizontalScale(canvasWidth, this.width) : 0;
|
const widthMin = this.width ? this.calculateHorizontalScale(canvasWidth, this.width) : 0;
|
||||||
this.scaleMin = Math.max(this.scaleMin, heightMin, widthMin);
|
|
||||||
this.scale = this.scaleMin > this.scale ? this.scaleMin : this.scale;
|
this.scaleMax = this.settings.scaleMax;
|
||||||
|
this.scaleMin = Math.max(this.settings.scaleMin, heightMin, widthMin);
|
||||||
|
|
||||||
|
this.scale = this.scaleMin > this.settings.scale ? this.scaleMin : this.settings.scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
_setOriginX () {
|
setOriginX (canvasWidth, centerX) {
|
||||||
this.originX = has(this, 'originX') ? this.originX :
|
this.originX = centerX ? centerX - canvasWidth / 2 :
|
||||||
this.negativeTiles ? parseInt(this.canvasWidth / 2) :
|
this.negativeTiles ? parseInt(canvasWidth / 2) :
|
||||||
this.width ? ((this.width * this.tileWidth()) / -2) + (this.canvasWidth / 2) + (this.tileWidth() / 2) :
|
this.width ? ((this.width * this.tileWidth()) / -2) + (canvasWidth / 2) + (this.tileWidth() / 2) :
|
||||||
this.tileWidth() / 2;
|
this.tileWidth() / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
_setOriginY () {
|
setOriginY (canvasHeight, centerY) {
|
||||||
const boardHeight = this.height * this.tileHeight();
|
const boardHeight = this.height * this.tileHeight();
|
||||||
|
|
||||||
this.originY = has(this, 'originY') ? this.originY :
|
this.originY = centerY ? centerY + canvasHeight / 2 :
|
||||||
this.negativeTiles ? parseInt(this.canvasHeight / 2) :
|
this.negativeTiles ? parseInt(canvasHeight / 2) :
|
||||||
this.height ? (boardHeight) - ((boardHeight - this.canvasHeight) / 2) - (this.tileHeight() / 2) :
|
this.height ? (boardHeight) - ((boardHeight - canvasHeight) / 2) - (this.tileHeight() / 2) :
|
||||||
this.canvasHeight - (this.tileHeight() / 2);
|
canvasHeight - (this.tileHeight() / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
move(event) {
|
move(event) {
|
||||||
if (event.deltaX) {
|
const newX = this.originX + event.deltaX;
|
||||||
|
const newY = this.originY + event.deltaY;
|
||||||
|
|
||||||
this.originX = toFixed(this.originX + event.deltaX);
|
this.originX = newX;
|
||||||
}
|
this.originY = newY;
|
||||||
|
|
||||||
if (event.deltaY) {
|
|
||||||
|
|
||||||
this.originY = toFixed(this.originY + event.deltaY);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._checkMove(event);
|
this._checkMove(event);
|
||||||
|
|
||||||
|
// return if the move succeeded or not
|
||||||
|
return this.originX === newX && this.originY === newY;
|
||||||
}
|
}
|
||||||
|
|
||||||
_checkMove(event) {
|
_checkMove(event) {
|
||||||
|
|||||||
@@ -1,17 +1,21 @@
|
|||||||
|
|
||||||
import {noop} from './utils.js';
|
import {noop} from './utils.js';
|
||||||
|
|
||||||
export default class Sketch {
|
export default class Sketch {
|
||||||
constructor(settings) {
|
constructor (settings) {
|
||||||
this.lastNow = null;
|
this.lastNow = null;
|
||||||
|
|
||||||
['getContext', 'onResize', 'render'].map(method => this[method] = this[method].bind(this));
|
[
|
||||||
|
'getContext',
|
||||||
|
'onResize',
|
||||||
|
'render'
|
||||||
|
].map(method => this[method] = this[method].bind(this));
|
||||||
|
|
||||||
this.drawDelay = settings.drawDelay || 50;
|
|
||||||
this.draw = settings.draw || noop;
|
this.draw = settings.draw || noop;
|
||||||
|
this.resize = settings.resize || noop;
|
||||||
|
this.drawDelay = settings.drawDelay || 50;
|
||||||
this.container = settings.element || document.body;
|
this.container = settings.element || document.body;
|
||||||
|
|
||||||
window.addEventListener('optimizedResize', this.onResize);
|
window.addEventListener('resize', this.onResize);
|
||||||
|
|
||||||
this.canvas = document.createElement('canvas');
|
this.canvas = document.createElement('canvas');
|
||||||
this.canvas.width = this.container.offsetWidth;
|
this.canvas.width = this.container.offsetWidth;
|
||||||
@@ -24,13 +28,36 @@ export default class Sketch {
|
|||||||
requestAnimationFrame(this.render);
|
requestAnimationFrame(this.render);
|
||||||
}
|
}
|
||||||
|
|
||||||
getContext() { return this.context; }
|
getContext () {
|
||||||
|
return this.context;
|
||||||
onResize(event) {
|
|
||||||
console.log('sketch - onResize', arguments);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render(now) {
|
onResize (event) {
|
||||||
|
const width = this.container.offsetWidth;
|
||||||
|
const height = this.container.offsetHeight;
|
||||||
|
|
||||||
|
const oldWidth = this.canvas.width;
|
||||||
|
const oldHeight = this.canvas.height;
|
||||||
|
|
||||||
|
const deltaX = width - oldWidth;
|
||||||
|
const deltaY = height - oldHeight;
|
||||||
|
|
||||||
|
this.canvas.width = width;
|
||||||
|
this.canvas.height = height;
|
||||||
|
|
||||||
|
Object.assign(event, {
|
||||||
|
height, width,
|
||||||
|
oldHeight, oldWidth,
|
||||||
|
deltaX, deltaY,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.resize(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
render (now) {
|
||||||
|
this.canvas.width = this.container.offsetWidth;
|
||||||
|
this.canvas.height = this.container.offsetHeight;
|
||||||
|
|
||||||
this.context.now = now;
|
this.context.now = now;
|
||||||
this.context.lastNow = this.lastNow;
|
this.context.lastNow = this.lastNow;
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export class Tessellate {
|
|||||||
static get utils() {return utils}
|
static get utils() {return utils}
|
||||||
static get funky() {return funky}
|
static get funky() {return funky}
|
||||||
|
|
||||||
constructor(settings) {
|
constructor (settings) {
|
||||||
[
|
[
|
||||||
'checkSettings',
|
'checkSettings',
|
||||||
'tap',
|
'tap',
|
||||||
@@ -88,14 +88,16 @@ export class Tessellate {
|
|||||||
'pixelToTile',
|
'pixelToTile',
|
||||||
'tileToPixel',
|
'tileToPixel',
|
||||||
'getTilePoints',
|
'getTilePoints',
|
||||||
'draw'
|
'draw',
|
||||||
|
'resize',
|
||||||
].map(method => {this[method] = this[method].bind(this)});
|
].map(method => {this[method] = this[method].bind(this)});
|
||||||
|
|
||||||
this.checkSettings(settings);
|
this.checkSettings(settings);
|
||||||
|
|
||||||
this.sketch = new Sketch({
|
this.sketch = new Sketch({
|
||||||
element: this.settings.element,
|
element: this.settings.element,
|
||||||
draw: this.draw
|
draw: this.draw,
|
||||||
|
resize: this.resize,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.onTap = new OnTap(Object.assign({
|
this.onTap = new OnTap(Object.assign({
|
||||||
@@ -112,10 +114,10 @@ export class Tessellate {
|
|||||||
this.cartographer = new cartographer(Object.assign({
|
this.cartographer = new cartographer(Object.assign({
|
||||||
canvasWidth: this.sketch.getContext().canvas.width,
|
canvasWidth: this.sketch.getContext().canvas.width,
|
||||||
canvasHeight: this.sketch.getContext().canvas.height,
|
canvasHeight: this.sketch.getContext().canvas.height,
|
||||||
}, funky.pick(this.settings, ['originX', 'originY', 'height', 'width', 'scale', 'negativeTiles'])));
|
}, funky.pick(this.settings, ['centerX', 'centerY', 'height', 'width', 'scale', 'negativeTiles'])));
|
||||||
}
|
}
|
||||||
|
|
||||||
checkSettings(settings) {
|
checkSettings (settings) {
|
||||||
|
|
||||||
this.settings = Object.assign({}, DEFAULTS, settings);
|
this.settings = Object.assign({}, DEFAULTS, settings);
|
||||||
this.settings.element = this.settings.element instanceof HTMLElement ? this.settings.element :
|
this.settings.element = this.settings.element instanceof HTMLElement ? this.settings.element :
|
||||||
@@ -132,7 +134,7 @@ export class Tessellate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tap(event) {
|
tap (event) {
|
||||||
let point = new Point(event.offsetX, event.offsetY);
|
let point = new Point(event.offsetX, event.offsetY);
|
||||||
let tile = this.cartographer.pixelToTile(point);
|
let tile = this.cartographer.pixelToTile(point);
|
||||||
|
|
||||||
@@ -145,7 +147,7 @@ export class Tessellate {
|
|||||||
this.settings.tap(tap);
|
this.settings.tap(tap);
|
||||||
}
|
}
|
||||||
|
|
||||||
doubletap(event) {
|
doubletap (event) {
|
||||||
console.log('DOUBLETAP', event);
|
console.log('DOUBLETAP', event);
|
||||||
let point = new Point(event.offsetX, event.offsetY);
|
let point = new Point(event.offsetX, event.offsetY);
|
||||||
let tile = this.cartographer.pixelToTile(point);
|
let tile = this.cartographer.pixelToTile(point);
|
||||||
@@ -159,7 +161,7 @@ export class Tessellate {
|
|||||||
console.log(tap);
|
console.log(tap);
|
||||||
}
|
}
|
||||||
|
|
||||||
pressStart(event) {
|
pressStart (event) {
|
||||||
let point = new Point(event.offsetX, event.offsetY);
|
let point = new Point(event.offsetX, event.offsetY);
|
||||||
let tile = this.cartographer.pixelToTile(point);
|
let tile = this.cartographer.pixelToTile(point);
|
||||||
|
|
||||||
@@ -172,7 +174,7 @@ export class Tessellate {
|
|||||||
this.settings.pressStart(tap);
|
this.settings.pressStart(tap);
|
||||||
}
|
}
|
||||||
|
|
||||||
press(event) {
|
press (event) {
|
||||||
let point = new Point(event.offsetX, event.offsetY);
|
let point = new Point(event.offsetX, event.offsetY);
|
||||||
let tile = this.cartographer.pixelToTile(point);
|
let tile = this.cartographer.pixelToTile(point);
|
||||||
|
|
||||||
@@ -185,23 +187,23 @@ export class Tessellate {
|
|||||||
this.settings.press(tap);
|
this.settings.press(tap);
|
||||||
}
|
}
|
||||||
|
|
||||||
move(event) {
|
move (event) {
|
||||||
this.cartographer.move(event);
|
return this.cartographer.move(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
zoom(event) {
|
zoom (event) {
|
||||||
this.cartographer.zoom(event);
|
this.cartographer.zoom(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
pixelToTile(x, y) {
|
pixelToTile (x, y) {
|
||||||
return this.cartographer.pixelToTile(x, y);
|
return this.cartographer.pixelToTile(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
tileToPixel(x, y, z) {
|
tileToPixel (x, y, z) {
|
||||||
return this.cartographer.tileToPixel(x, y, z);
|
return this.cartographer.tileToPixel(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
getTilePoints({upperLeftX, upperLeftY, lowerRightX, lowerRightY}) {
|
getTilePoints ({upperLeftX, upperLeftY, lowerRightX, lowerRightY}) {
|
||||||
const upperLeft = new Point(upperLeftX, upperLeftY);
|
const upperLeft = new Point(upperLeftX, upperLeftY);
|
||||||
const upperRight = new Point(lowerRightX, 0);
|
const upperRight = new Point(lowerRightX, 0);
|
||||||
const lowerLeft = new Point(0, lowerRightY);
|
const lowerLeft = new Point(0, lowerRightY);
|
||||||
@@ -210,7 +212,7 @@ export class Tessellate {
|
|||||||
return funky.flatten(this.cartographer.boundingBox(upperLeft, upperRight, lowerLeft, lowerRight));
|
return funky.flatten(this.cartographer.boundingBox(upperLeft, upperRight, lowerLeft, lowerRight));
|
||||||
}
|
}
|
||||||
|
|
||||||
draw(context) {
|
draw (context) {
|
||||||
const canvas = context.canvas;
|
const canvas = context.canvas;
|
||||||
const width = canvas.width;
|
const width = canvas.width;
|
||||||
const height = canvas.height;
|
const height = canvas.height;
|
||||||
@@ -230,4 +232,34 @@ export class Tessellate {
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resize (event) {
|
||||||
|
const originX = this.cartographer.getOriginX();
|
||||||
|
const originY = this.cartographer.getOriginY();
|
||||||
|
const scaleOrig = this.cartographer.getScale();
|
||||||
|
|
||||||
|
const moveForResize = Object.assign({}, event, {
|
||||||
|
deltaX: event.deltaX / 2,
|
||||||
|
deltaY: event.deltaY / 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.move(moveForResize);
|
||||||
|
|
||||||
|
this.cartographer.checkScale(event.height, event.width);
|
||||||
|
|
||||||
|
const centerX = event.width / 2;
|
||||||
|
const centerY = event.height / 2;
|
||||||
|
const scaleNew = this.cartographer.getScale();
|
||||||
|
|
||||||
|
const moveForScale = {
|
||||||
|
deltaX: (((centerX - originX) / scaleOrig) * (scaleOrig - scaleNew)),
|
||||||
|
deltaY: (((centerY - originY) / scaleOrig) * (scaleOrig - scaleNew)),
|
||||||
|
target: {
|
||||||
|
offsetWidth: event.width,
|
||||||
|
offsetHeight: event.height,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
this.move(moveForScale);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
38
src/utils.js
38
src/utils.js
@@ -9,25 +9,25 @@ export const sqrt2 = Math.sqrt(2);
|
|||||||
// (2*S gives long width)
|
// (2*S gives long width)
|
||||||
export const sqrt3 = Math.sqrt(3);
|
export const sqrt3 = Math.sqrt(3);
|
||||||
|
|
||||||
export function throttleEvent(type, name, obj) {
|
//export function throttleEvent(type, name, obj) {
|
||||||
obj = obj || window;
|
// obj = obj || window;
|
||||||
let running = false;
|
// let running = false;
|
||||||
|
//
|
||||||
let throttle = () => {
|
// let throttle = () => {
|
||||||
if (!running) {
|
// if (!running) {
|
||||||
running = true;
|
// running = true;
|
||||||
|
//
|
||||||
requestAnimationFrame(() => {
|
// requestAnimationFrame(() => {
|
||||||
obj.dispatchEvent(new CustomEvent(name));
|
// obj.dispatchEvent(new CustomEvent(name));
|
||||||
running = false;
|
// running = false;
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
obj.addEventListener(type, throttle);
|
// obj.addEventListener(type, throttle);
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
throttleEvent('resize', 'optimizedResize');
|
//throttleEvent('resize', 'optimizedResize');
|
||||||
|
|
||||||
export function clone(obj) {
|
export function clone(obj) {
|
||||||
return JSON.parse(JSON.stringify(obj));
|
return JSON.parse(JSON.stringify(obj));
|
||||||
|
|||||||
Reference in New Issue
Block a user