right shift -> place from historical view

This commit is contained in:
HF 2021-01-27 17:04:22 +01:00
parent e4a6171666
commit 2d0c31fac6
4 changed files with 106 additions and 17 deletions

View File

@ -37,7 +37,8 @@ const HelpModal = () => (
<p className="modaltext">Drag mouse to move</p>
<p className="modaltext">Scroll mouse wheel to zoom</p>
<p className="modaltext">Click middle mouse button to current hovering color</p>
<p className="modaltext">Hold shift for placing while moving mouse</p>
<p className="modaltext">Hold left shift for placing while moving mouse</p>
<p className="modaltext">Hold right shift for placing while moving mouse according to historical view</p>
<p className="modaltext">Pinch to zoom (on touch devices)</p>
<p className="modaltext">Pan to move (on touch devices)</p>
<p className="modaltext">Click or tap to place a pixel</p>

View File

@ -61,8 +61,13 @@ class PixelPlainterControls {
this.isMultiTab = false;
// on touch: timeout to detect long-press
this.tapTimeout = null;
// if we are shift-hold-painting
this.holdPainting = false;
/*
* if we are shift-hold-painting
* 0: no
* 1: left shift
* 2: right shift
*/
this.holdPainting = 0;
// if we are waiting before placeing pixel via holdPainting again
this.coolDownDelta = false;
@ -162,14 +167,20 @@ class PixelPlainterControls {
return null;
}
static placePixel(store, renderer, cell) {
/*
* place pixel
* either with given colorIndex or with selected color if none is given
*/
static placePixel(store, renderer, cell, colorIndex = null) {
const state = store.getState();
const { autoZoomIn } = state.gui;
const {
scale,
isHistoricalView,
selectedColor,
} = state.canvas;
const selectedColor = (colorIndex === null)
? state.canvas.selectedColor
: colorIndex;
if (isHistoricalView) return;
@ -393,16 +404,42 @@ class PixelPlainterControls {
|| y < -maxCoords || y >= maxCoords
) {
if (hover) {
store.dispatch(unsetHover(screenCoor));
store.dispatch(unsetHover());
}
return;
}
if (!hover || hover[0] !== x || hover[1] !== y) {
store.dispatch(setHover(screenCoor));
}
if (this.holdPainting && !this.coolDownDelta) {
PixelPlainterControls.placePixel(store, this.renderer, screenCoor);
/* shift placing */
if (!this.coolDownDelta) {
switch (this.holdPainting) {
case 1: {
/* left shift: from selected color */
PixelPlainterControls.placePixel(
store,
this.renderer,
screenCoor,
);
break;
}
case 2: {
/* right shift: from historical view */
const colorIndex = this.renderer
.getColorIndexOfPixel(x, y, true);
if (colorIndex !== null) {
PixelPlainterControls.placePixel(
store,
this.renderer,
screenCoor,
colorIndex,
);
}
break;
}
default:
}
}
}
}
}
@ -412,7 +449,7 @@ class PixelPlainterControls {
viewport.style.cursor = 'auto';
store.dispatch(unsetHover());
store.dispatch(onViewFinishChange());
this.holdPainting = false;
this.holdPainting = 0;
this.clearTabTimeout();
}
@ -448,7 +485,7 @@ class PixelPlainterControls {
switch (event.key) {
case 'Shift':
case 'CapsLock':
this.holdPainting = false;
this.holdPainting = 0;
break;
default:
}
@ -496,19 +533,28 @@ class PixelPlainterControls {
if (event.key === 'Control') {
// ctrl
const clrIndex = this.renderer.getColorIndexOfPixel(...hover);
if (clrIndex !== null) {
store.dispatch(selectColor(clrIndex));
}
store.dispatch(selectColor(clrIndex));
return;
}
if (event.location === KeyboardEvent.DOM_KEY_LOCATION_LEFT) {
// left shift
this.holdPainting = true;
this.holdPainting = 1;
PixelPlainterControls.placePixel(store, this.renderer, hover);
return;
}
if (event.location === KeyboardEvent.DOM_KEY_LOCATION_RIGHT) {
// right shift
this.holdPainting = 2;
const colorIndex = this.renderer
.getColorIndexOfPixel(...hover, true);
if (colorIndex !== null) {
PixelPlainterControls.placePixel(
store,
this.renderer,
hover,
colorIndex,
);
}
}
}
break;

View File

@ -77,6 +77,46 @@ class ChunkLoader {
);
}
/*
* Get color of pixel in current historical view
* @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,
) {
const state: State = this.store.getState();
const { canvasSize, historicalDate, historicalTime } = state.canvas;
if (!historicalDate) {
return null;
}
const [cx, cy] = getChunkOfPixel(canvasSize, x, y);
const px = getCellInsideChunk(canvasSize, [x, y]);
const curTime = Date.now();
if (!historicalTime || historicalTime !== '0000') {
// eslint-disable-next-line max-len
const incrementialChunkKey = `${historicalDate}${historicalTime}:${cx}:${cy}`;
const incrementialChunk = this.chunks.get(incrementialChunkKey);
if (incrementialChunk) {
const incrementialColor = incrementialChunk.getColorIndex(px);
incrementialChunk.timestamp = curTime;
if (incrementialColor !== null) {
return incrementialColor;
}
}
}
const chunkKey = `${historicalDate}:${cx}:${cy}`;
const chunk = this.chunks.get(chunkKey);
if (!chunk) {
return null;
}
chunk.timestamp = curTime;
return chunk.getColorIndex(px);
}
/*
* preLoad chunks by generating them out of
* available lower zoomlevel chunks

View File

@ -146,8 +146,10 @@ class Renderer {
}
}
getColorIndexOfPixel(cx, cy) {
return this.chunkLoader.getColorIndexOfPixel(cx, cy);
getColorIndexOfPixel(cx, cy, historical: boolean = false) {
return (historical)
? this.chunkLoader.getHistoricalIndexOfPixel(cx, cy)
: this.chunkLoader.getColorIndexOfPixel(cx, cy);
}
updateScale(