allow canvases to change sizes in historical view

This commit is contained in:
HF 2021-04-18 16:47:14 +02:00
parent fb35eb5220
commit 3d4ded29ca
8 changed files with 191 additions and 77 deletions

View File

@ -84,7 +84,13 @@
[ 122, 148, 156 ],
[ 174, 215, 185 ]
],
"size" : 4096,
"size": 16384,
"historicalSizes": [
[
"20210417",
4096
]
],
"hid": false,
"cli": 2,
"bcd": 15000,

View File

@ -69,6 +69,24 @@ export function getMaxTiledZoom(canvasSize: number): number {
return Math.log2(canvasSize / TILE_SIZE) / TILE_ZOOM_LEVEL * 2;
}
export function getHistoricalCanvasSize(
historicalDate: string,
canvasSize: number,
historicalSizes: Array,
) {
if (historicalDate && historicalSizes) {
let i = historicalSizes.length;
while (i > 0) {
i -= 1;
const [date, size] = historicalSizes[i];
if (historicalDate <= date) {
return size;
}
}
}
return canvasSize;
}
export function getCanvasBoundaries(canvasSize: number): number {
const canvasMinXY = -canvasSize / 2;
const canvasMaxXY = canvasSize / 2 - 1;

View File

@ -5,9 +5,10 @@ import type { Cell } from '../core/Cell';
import type { ColorIndex } from '../core/Palette';
import Palette from '../core/Palette';
import {
getMaxTiledZoom,
clamp,
getIdFromObject,
getHistoricalCanvasSize,
getMaxTiledZoom,
} from '../core/utils';
@ -25,7 +26,6 @@ export type CanvasState = {
selectedColor: ColorIndex,
is3D: boolean,
canvasSize: number,
canvasMaxTiledZoom: number,
canvasStartDate: string,
palette: Palette,
clrIgnore: number,
@ -33,6 +33,7 @@ export type CanvasState = {
scale: number,
viewscale: number,
isHistoricalView: boolean,
historicalCanvasSize: number,
historicalDate: string,
historicalTime: string,
// object with all canvas informations from all canvases like colors and size
@ -104,6 +105,7 @@ function getViewFromURL(canvases: Object) {
canvasId,
canvasIdent,
canvasSize,
historicalCanvasSize: canvasSize,
is3D,
canvasStartDate,
canvasMaxTiledZoom: getMaxTiledZoom(canvasSize),
@ -121,6 +123,7 @@ function getViewFromURL(canvases: Object) {
canvasId: DEFAULT_CANVAS_ID,
canvasIdent: canvasd.ident,
canvasSize: canvasd.size,
historicalCanvasSize: canvasd.size,
is3D: !!canvasd.v,
canvasStartDate: null,
canvasMaxTiledZoom: getMaxTiledZoom(canvasd.size),
@ -130,6 +133,7 @@ function getViewFromURL(canvases: Object) {
view: getGivenCoords(),
viewscale: DEFAULT_SCALE,
scale: DEFAULT_SCALE,
canvases,
};
}
}
@ -154,10 +158,13 @@ export default function canvasReducer(
viewscale,
} = state;
const {
canvasSize,
isHistoricalView,
} = state;
const canvasSize = (isHistoricalView)
? state.historicalCanvasSize
: state.canvasSize;
let [hx, hy] = view;
let { scale } = action;
const { zoompoint } = action;
@ -192,8 +199,18 @@ export default function canvasReducer(
date,
time,
} = action;
const {
canvasSize,
canvases,
canvasId,
} = state;
const historicalCanvasSize = getHistoricalCanvasSize(
date, canvasSize, canvases[canvasId].historicalSizes,
);
return {
...state,
historicalCanvasSize,
historicalDate: date,
historicalTime: time,
};
@ -221,7 +238,9 @@ export default function canvasReducer(
case 'SET_VIEW_COORDINATES': {
const { view } = action;
const { canvasSize } = state;
const canvasSize = (state.isHistoricalView)
? state.historicalCanvasSize
: state.canvasSize;
const canvasMinXY = -canvasSize / 2;
const canvasMaxXY = canvasSize / 2 - 1;
const newview = view.map((z) => clamp(z, canvasMinXY, canvasMaxXY));
@ -249,7 +268,7 @@ export default function canvasReducer(
case 'SELECT_CANVAS': {
let { canvasId } = action;
const { canvases, isHistoricalView } = state;
const { canvases } = state;
let canvas = canvases[canvasId];
if (!canvas) {
@ -264,7 +283,12 @@ export default function canvasReducer(
cli: clrIgnore,
colors,
} = canvas;
const canvasMaxTiledZoom = getMaxTiledZoom(canvasSize);
const isHistoricalView = !is3D && state.isHistoricalView;
const historicalCanvasSize = getHistoricalCanvasSize(
state.historicalDate,
canvasSize,
canvas.historicalSizes,
);
const palette = new Palette(colors, 0);
const view = (canvasId === 0) ? getGivenCoords() : [0, 0, 0];
if (!is3D) {
@ -278,13 +302,13 @@ export default function canvasReducer(
canvasSize,
is3D,
canvasStartDate,
canvasMaxTiledZoom,
palette,
clrIgnore,
view,
viewscale: DEFAULT_SCALE,
scale: DEFAULT_SCALE,
isHistoricalView: !is3D && isHistoricalView,
isHistoricalView,
historicalCanvasSize,
};
}
@ -304,7 +328,6 @@ export default function canvasReducer(
cli: clrIgnore,
colors,
} = canvases[canvasId];
const canvasMaxTiledZoom = getMaxTiledZoom(canvasSize);
const palette = new Palette(colors, 0);
if (!is3D) {
@ -319,7 +342,6 @@ export default function canvasReducer(
canvasSize,
is3D,
canvasStartDate,
canvasMaxTiledZoom,
palette,
clrIgnore,
canvases,

View File

@ -15,7 +15,14 @@ export default (store) => (next) => (action) => {
if (type === 'SET_HISTORICAL_TIME') {
const state = store.getState();
const renderer = getRenderer();
renderer.updateOldHistoricalTime(state.canvas.historicalTime);
const {
historicalDate: oldDate,
historicalTime: oldTime,
} = state.canvas;
renderer.updateOldHistoricalTime(
oldDate,
oldTime,
);
}
// executed after reducers
@ -37,7 +44,22 @@ export default (store) => (next) => (action) => {
break;
}
case 'SET_HISTORICAL_TIME':
case 'SET_HISTORICAL_TIME': {
const {
historicalDate,
historicalTime,
historicalCanvasSize,
} = state.canvas;
const renderer = getRenderer();
renderer.updateHistoricalTime(
historicalDate,
historicalTime,
historicalCanvasSize,
);
renderer.forceNextRender = true;
break;
}
case 'REQUEST_BIG_CHUNK':
case 'PRE_LOADED_BIG_CHUNK':
case 'RECEIVE_BIG_CHUNK':
@ -55,14 +77,8 @@ export default (store) => (next) => (action) => {
case 'TOGGLE_HISTORICAL_VIEW':
case 'SET_SCALE': {
const {
viewscale,
canvasMaxTiledZoom,
view,
canvasSize,
} = state.canvas;
const renderer = getRenderer();
renderer.updateScale(viewscale, canvasMaxTiledZoom, view, canvasSize);
renderer.updateScale(state);
break;
}
@ -79,9 +95,8 @@ export default (store) => (next) => (action) => {
}
case 'SET_VIEW_COORDINATES': {
const { view, canvasSize } = state.canvas;
const renderer = getRenderer();
renderer.updateView(view, canvasSize);
renderer.updateView(state);
break;
}

View File

@ -17,28 +17,37 @@ import {
// preLoadedBigChunk,
} from '../actions';
import {
getMaxTiledZoom,
getCellInsideChunk,
getChunkOfPixel,
getHistoricalCanvasSize,
} from '../core/utils';
class ChunkLoader {
store = null;
canvasId: number;
canvasMaxTiledZoom: number;
historicalMaxTiledZooms: Array;
palette;
canvasSize: number;
chunks: Map<string, ChunkRGB>;
constructor(store) {
constructor(store, canvasId, palette, canvasSize, historicalSizes) {
this.store = store;
const state = store.getState();
const {
canvasId,
canvasMaxTiledZoom,
palette,
} = state.canvas;
this.canvasId = canvasId;
this.canvasMaxTiledZoom = canvasMaxTiledZoom;
this.palette = palette;
this.canvasSize = canvasSize;
this.canvasMaxTiledZoom = getMaxTiledZoom(canvasSize);
if (historicalSizes) {
this.historicalMaxTiledZooms = historicalSizes.map((ts) => {
const [date, size] = ts;
return [date, getMaxTiledZoom(size)];
});
} else {
this.historicalMaxTiledZooms = [];
}
this.chunks = new Map();
}
@ -64,8 +73,7 @@ class ChunkLoader {
x: number,
y: number,
) {
const state: State = this.store.getState();
const { canvasSize } = state.canvas;
const { canvasSize } = this;
const [cx, cy] = getChunkOfPixel(canvasSize, x, y);
const key = `${this.canvasMaxTiledZoom}:${cx}:${cy}`;
const chunk = this.chunks.get(key);
@ -79,15 +87,17 @@ class ChunkLoader {
/*
* Get color of pixel in current historical view
* (has to account for canvs size changes in the past
* @param x, y world coordiantes of pixel
* @return ColorIndex or null if chunks not loaded or historical view not set
*/
getHistoricalIndexOfPixel(
x: number,
y: number,
historicalDate: string,
historicalTime: string,
) {
const state: State = this.store.getState();
const { canvasSize, historicalDate, historicalTime } = state.canvas;
const { canvasSize } = this;
if (!historicalDate) {
return null;
}
@ -208,10 +218,15 @@ class ChunkLoader {
}
return (historicalTime) ? null : loadingTiles.getTile(canvasId);
} if (fetch) {
const historicalCanvasMaxTiledZoom = getHistoricalCanvasSize(
historicalDate,
this.canvasMaxTiledZoom,
this.historicalMaxTiledZooms,
);
// fetch tile
const chunkRGB = new ChunkRGB(
this.palette,
this.canvasMaxTiledZoom,
historicalCanvasMaxTiledZoom,
cx,
cy,
);
@ -221,6 +236,7 @@ class ChunkLoader {
cy,
historicalDate,
historicalTime,
historicalCanvasMaxTiledZoom,
chunkRGB,
);
}
@ -232,10 +248,12 @@ class ChunkLoader {
cy: number,
historicalDate: string,
historicalTime: string,
historicalCanvasMaxTiledZoom,
chunkRGB,
) {
const { canvasId, canvasMaxTiledZoom } = this;
const center = [canvasMaxTiledZoom, cx, cy];
const { canvasId } = this;
const center = [historicalCanvasMaxTiledZoom, cx, cy];
let url = `${window.ssv.backupurl}/${historicalDate}/`;
if (historicalTime) {
// incremential tiles

View File

@ -23,15 +23,11 @@ class ChunkLoader {
palette;
chunks: Map<string, Chunk>;
constructor(store) {
constructor(store, canvasId, palette, canvasSize) {
this.store = store;
const state = store.getState();
const {
canvasId,
palette,
} = state.canvas;
this.canvasId = canvasId;
this.palette = palette;
this.canvasSize = canvasSize;
this.chunks = new Map();
}
@ -43,10 +39,7 @@ class ChunkLoader {
}
getVoxel(x: number, y: number, z: number) {
const state = this.store.getState();
const {
canvasSize,
} = state.canvas;
const { canvasSize } = this;
const [xc, zc] = getChunkOfPixel(canvasSize, x, y, z);
const offset = getOffsetOfPixel(canvasSize, x, y, z);
const key = `${xc}:${zc}`;

View File

@ -11,6 +11,7 @@ import { TILE_SIZE } from '../core/constants';
import {
getTileOfPixel,
getPixelFromChunkOffset,
getMaxTiledZoom,
} from '../core/utils';
import {
@ -58,6 +59,8 @@ class Renderer {
this.centerChunk = [null, null];
this.tiledScale = 0;
this.tiledZoom = 4;
this.canvasMaxTiledZoom = 0;
this.historicalCanvasMaxTiledZoom = 0;
this.hover = false;
//--
this.forceNextRender = true;
@ -110,70 +113,100 @@ class Renderer {
setStore(store) {
this.store = store;
const state = store.getState();
const {
canvasMaxTiledZoom,
viewscale,
view,
canvasSize,
} = state.canvas;
this.updateCanvasData(state);
this.updateScale(viewscale, canvasMaxTiledZoom, view, canvasSize);
this.updateScale(state);
this.controls = new PixelPainterControls(this, this.viewport, store);
}
updateCanvasData(state: State) {
const {
canvasMaxTiledZoom,
viewscale,
view,
canvasSize,
canvasId,
} = state.canvas;
if (canvasId !== this.canvasId) {
this.canvasId = canvasId;
if (canvasId !== null) {
this.chunkLoader = new ChunkLoader(this.store);
const {
palette,
canvasSize,
canvases,
} = state.canvas;
this.canvasMaxTiledZoom = getMaxTiledZoom(canvasSize);
this.chunkLoader = new ChunkLoader(
this.store,
canvasId,
palette,
canvasSize,
canvases[canvasId].historicalSizes,
);
}
}
this.updateScale(viewscale, canvasMaxTiledZoom, view, canvasSize);
this.updateScale(state);
}
updateOldHistoricalTime(historicalTime: string) {
if (historicalTime === '0000') {
updateOldHistoricalTime(oldDate, oldTime) {
if (oldTime === '0000') {
this.oldHistoricalTime = null;
} else {
this.oldHistoricalTime = historicalTime;
this.oldHistoricalTime = oldTime;
}
}
updateHistoricalTime(historicalDate, historicalTime, historicalCanvasSize) {
this.historicalCanvasMaxTiledZoom = getMaxTiledZoom(
historicalCanvasSize,
);
}
getColorIndexOfPixel(cx, cy, historical: boolean = false) {
return (historical)
? this.chunkLoader.getHistoricalIndexOfPixel(cx, cy)
: this.chunkLoader.getColorIndexOfPixel(cx, cy);
if (historical) {
const state = this.store.getState();
const {
historicalDate,
historicalTime,
} = state.canvas;
return this.chunkLoader.getHistoricalIndexOfPixel(cx, cy,
historicalDate, historicalTime);
}
return this.chunkLoader.getColorIndexOfPixel(cx, cy);
}
updateScale(
viewscale: number,
canvasMaxTiledZoom: number,
view,
canvasSize,
state,
) {
const {
viewscale,
view,
isHistoricalView,
} = state.canvas;
pixelNotify.updateScale(viewscale);
let tiledScale = (viewscale > 0.5)
? 0
: Math.round(Math.log2(viewscale) / 2);
tiledScale = 4 ** tiledScale;
const canvasSize = (isHistoricalView)
? state.canvas.historicalCanvasSize
: state.canvas.canvasSize;
const canvasMaxTiledZoom = (isHistoricalView)
? this.historicalCanvasMaxTiledZoom
: this.canvasMaxTiledZoom;
const tiledZoom = canvasMaxTiledZoom + Math.log2(tiledScale) / 2;
const relScale = viewscale / tiledScale;
this.tiledScale = tiledScale;
this.tiledZoom = tiledZoom;
this.relScale = relScale;
this.updateView(view, canvasSize);
this.updateView(state);
this.forceNextRender = true;
}
updateView(view, canvasSize) {
updateView(state) {
const {
view,
} = state.canvas;
const canvasSize = (state.canvas.isHistoricalView)
? state.canvas.historicalCanvasSize
: state.canvas.canvasSize;
const [x, y] = view;
let [cx, cy] = this.centerChunk;
const [curcx, curcy] = getTileOfPixel(
@ -506,9 +539,9 @@ class Renderer {
} = this;
const {
viewscale,
canvasSize,
historicalDate,
historicalTime,
historicalCanvasSize,
} = state.canvas;
@ -575,7 +608,7 @@ class Renderer {
const x = xOffset + dx * TILE_SIZE;
const y = yOffset + dy * TILE_SIZE;
const chunkMaxXY = canvasSize / TILE_SIZE;
const chunkMaxXY = historicalCanvasSize / TILE_SIZE;
if (cx < 0 || cx >= chunkMaxXY || cy < 0 || cy >= chunkMaxXY) {
// if out of bounds
context.fillRect(x, y, TILE_SIZE, TILE_SIZE);
@ -638,7 +671,7 @@ class Renderer {
const {
view,
viewscale,
canvasSize,
historicalCanvasSize,
} = state.canvas;
const [x, y] = view;
@ -663,7 +696,7 @@ class Renderer {
viewportCtx.imageSmoothingEnabled = false;
// If scale is so large that neighbouring chunks wouldn't fit in offscreen
// canvas, do scale = 1 in renderChunks and scale in render()
const canvasCenter = canvasSize / 2;
const canvasCenter = historicalCanvasSize / 2;
if (viewscale > SCALE_THREASHOLD) {
viewportCtx.save();
viewportCtx.scale(viewscale, viewscale);

View File

@ -249,7 +249,16 @@ class Renderer {
}
}
this.loadedChunks = new Map();
this.chunkLoader = new ChunkLoader(this.store);
const {
palette,
canvasSize,
} = state.canvas;
this.chunkLoader = new ChunkLoader(
this.store,
canvasId,
palette,
canvasSize,
);
}
}
this.controls.setView(view);