Support viewport resizing (#16)

This commit is contained in:
gavin
2018-08-30 01:02:58 +00:00
committed by Gitea
parent a2d7402cfa
commit 2c83c47afc
4 changed files with 137 additions and 73 deletions

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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);
}
} }

View File

@@ -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));