Skip to content

Commit

Permalink
use maps also for anims and other internals
Browse files Browse the repository at this point in the history
  • Loading branch information
niklasf committed Jul 5, 2020
1 parent a4a6e9f commit c190c18
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 61 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"eqeqeq": ["error", "smart"],
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-non-null-assertion": "warn",
"@typescript-eslint/no-use-before-define": ["error", { "functions": false }],
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
Expand Down
29 changes: 11 additions & 18 deletions src/anim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,9 @@ export type Mutation<A> = (state: State) => A;
// 2,3 animation current status
export type AnimVector = cg.NumberQuad;

export interface AnimVectors {
[key: string]: AnimVector | undefined;
}
export type AnimVectors = Map<cg.Key, AnimVector>;

export interface AnimFadings {
[key: string]: cg.Piece | undefined;
}
export type AnimFadings = Map<cg.Key, cg.Piece>;

export interface AnimPlan {
anims: AnimVectors;
Expand Down Expand Up @@ -42,9 +38,7 @@ interface AnimPiece {
pos: cg.Pos;
piece: cg.Piece;
}
interface AnimPieces {
[key: string]: AnimPiece | undefined;
}
type AnimPieces = Map<cg.Key, AnimPiece>;

function makePiece(key: cg.Key, piece: cg.Piece): AnimPiece {
return {
Expand All @@ -61,19 +55,19 @@ function closer(piece: AnimPiece, pieces: AnimPiece[]): AnimPiece | undefined {
}

function computePlan(prevPieces: cg.Pieces, current: State): AnimPlan {
const anims: AnimVectors = {},
const anims: AnimVectors = new Map(),
animedOrigs: cg.Key[] = [],
fadings: AnimFadings = {},
fadings: AnimFadings = new Map(),
missings: AnimPiece[] = [],
news: AnimPiece[] = [],
prePieces: AnimPieces = {};
prePieces: AnimPieces = new Map();
let curP: cg.Piece | undefined, preP: AnimPiece | undefined, vector: cg.NumberPair;
for (const [k, p] of prevPieces) {
prePieces[k] = makePiece(k, p);
prePieces.set(k, makePiece(k, p));
}
for (const key of util.allKeys) {
curP = current.pieces.get(key);
preP = prePieces[key];
preP = prePieces.get(key);
if (curP) {
if (preP) {
if (!util.samePiece(curP, preP.piece)) {
Expand All @@ -87,12 +81,12 @@ function computePlan(prevPieces: cg.Pieces, current: State): AnimPlan {
preP = closer(newP, missings.filter(p => util.samePiece(newP.piece, p.piece)));
if (preP) {
vector = [preP.pos[0] - newP.pos[0], preP.pos[1] - newP.pos[1]];
anims[newP.key] = vector.concat(vector) as AnimVector;
anims.set(newP.key, vector.concat(vector) as AnimVector);
animedOrigs.push(preP.key);
}
}
for (const p of missings) {
if (!animedOrigs.includes(p.key)) fadings[p.key] = p.piece;
if (!animedOrigs.includes(p.key)) fadings.set(p.key, p.piece);
}

return {
Expand All @@ -113,8 +107,7 @@ function step(state: State, now: DOMHighResTimeStamp): void {
state.dom.redrawNow();
} else {
const ease = easing(rest);
for (const i in cur.plan.anims) {
const cfg = cur.plan.anims[i]!;
for (const cfg of cur.plan.anims.values()) {
cfg[2] = cfg[0] * ease;
cfg[3] = cfg[1] * ease;
}
Expand Down
2 changes: 1 addition & 1 deletion src/drag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ function processDrag(s: State): void {
const cur = s.draggable.current;
if (!cur) return;
// cancel animations while dragging
if (s.animation.current?.plan.anims[cur.orig]) s.animation.current = undefined;
if (s.animation.current?.plan.anims.has(cur.orig)) s.animation.current = undefined;
// if moving piece is gone, cancel
const origPiece = s.pieces.get(cur.orig);
if (!origPiece || !util.samePiece(origPiece, cur.piece)) cancel(s);
Expand Down
43 changes: 22 additions & 21 deletions src/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,9 @@ import { AnimCurrent, AnimVectors, AnimVector, AnimFadings } from './anim'
import { DragCurrent } from './drag'
import * as cg from './types'

// `$color $role`
type PieceName = string;
type PieceName = string; // `$color $role`

interface SamePieces { [key: string]: boolean }
interface MovedPieces { [pieceName: string]: cg.PieceNode[] | undefined }
type SquareClasses = Map<cg.Key, string>
type SquareClasses = Map<cg.Key, string>;

// ported from https://github.com/veloce/lichobile/blob/master/src/js/chessground/view.js
// in case of bugs, blame @veloce
Expand All @@ -22,13 +19,13 @@ export function render(s: State): void {
boardEl: HTMLElement = s.dom.elements.board,
pieces: cg.Pieces = s.pieces,
curAnim: AnimCurrent | undefined = s.animation.current,
anims: AnimVectors = curAnim ? curAnim.plan.anims : {},
fadings: AnimFadings = curAnim ? curAnim.plan.fadings : {},
anims: AnimVectors = curAnim ? curAnim.plan.anims : new Map(),
fadings: AnimFadings = curAnim ? curAnim.plan.fadings : new Map(),
curDrag: DragCurrent | undefined = s.draggable.current,
squares: SquareClasses = computeSquareClasses(s),
samePieces: SamePieces = {},
samePieces: Set<cg.Key> = new Set(),
sameSquares: Set<cg.Key> = new Set(),
movedPieces: MovedPieces = {},
movedPieces: Map<PieceName, cg.PieceNode[]> = new Map(),
movedSquares: Map<string, cg.SquareNode[]> = new Map(); // by class name
let k: cg.Key,
el: cg.PieceNode | cg.SquareNode | undefined,
Expand All @@ -47,8 +44,8 @@ export function render(s: State): void {
k = el.cgKey;
if (isPieceNode(el)) {
pieceAtKey = pieces.get(k);
anim = anims[k];
fading = fadings[k];
anim = anims.get(k);
fading = fadings.get(k);
elPieceName = el.cgPiece;
// if piece not being dragged anymore, remove dragging style
if (el.cgDragging && (!curDrag || curDrag.orig !== k)) {
Expand Down Expand Up @@ -79,29 +76,27 @@ export function render(s: State): void {
}
// same piece: flag as same
if (elPieceName === pieceNameOf(pieceAtKey) && (!fading || !el.cgFading)) {
samePieces[k] = true;
samePieces.add(k);
}
// different piece: flag as moved unless it is a fading piece
else {
if (fading && elPieceName === pieceNameOf(fading)) {
el.classList.add('fading');
el.cgFading = true;
} else {
if (movedPieces[elPieceName]) movedPieces[elPieceName]!.push(el);
else movedPieces[elPieceName] = [el];
appendValue(movedPieces, elPieceName, el);
}
}
}
// no piece: flag as moved
else {
if (movedPieces[elPieceName]) movedPieces[elPieceName]!.push(el);
else movedPieces[elPieceName] = [el];
appendValue(movedPieces, elPieceName, el);
}
}
else if (isSquareNode(el)) {
const cn = el.className;
if (squares.get(k) === cn) sameSquares.add(k);
else movedSquares.set(cn, [...(movedSquares.get(cn) || []), el]);
else appendValue(movedSquares, cn, el);
}
el = el.nextSibling as cg.PieceNode | cg.SquareNode | undefined;
}
Expand Down Expand Up @@ -129,9 +124,9 @@ export function render(s: State): void {
// walk over all pieces in current set, apply dom changes to moved pieces
// or append new pieces
for (const [k, p] of pieces) {
anim = anims[k];
if (!samePieces[k]) {
pMvdset = movedPieces[pieceNameOf(p)];
anim = anims.get(k);
if (!samePieces.has(k)) {
pMvdset = movedPieces.get(pieceNameOf(p));
pMvd = pMvdset && pMvdset.pop();
// a same piece was moved
if (pMvd) {
Expand Down Expand Up @@ -176,7 +171,7 @@ export function render(s: State): void {
}

// remove any element that remains in the moved sets
for (const i in movedPieces) removeNodes(s, movedPieces[i]!);
for (const nodes of movedPieces.values()) removeNodes(s, nodes);
for (const nodes of movedSquares.values()) removeNodes(s, nodes);
}

Expand Down Expand Up @@ -248,3 +243,9 @@ function addSquare(squares: SquareClasses, key: cg.Key, klass: string): void {
if (classes) squares.set(key, `${classes} ${klass}`);
else squares.set(key, klass)
}

function appendValue<K, V>(map: Map<K, V[]>, key: K, value: V): void {
const arr = map.get(key);
if (arr) arr.push(value);
else map.set(key, [value]);
}
36 changes: 16 additions & 20 deletions src/svg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,9 @@ interface Shape {
hash: Hash;
}

interface CustomBrushes {
[hash: string]: DrawBrush;
}
type CustomBrushes = Map<string, DrawBrush>; // by hash

interface ArrowDests {
[key: string]: number; // how many arrows land on a square
}
type ArrowDests = Map<cg.Key, number>; // how many arrows land on a square

type Hash = string;

Expand All @@ -28,11 +24,11 @@ export function renderSvg(state: State, root: SVGElement): void {
const d = state.drawable,
curD = d.current,
cur = curD && curD.mouseSq ? curD as DrawShape : undefined,
arrowDests: ArrowDests = {},
arrowDests: ArrowDests = new Map(),
bounds = state.dom.bounds();

for (const s of d.shapes.concat(d.autoShapes).concat(cur ? [cur] : [])) {
if (s.dest) arrowDests[s.dest] = (arrowDests[s.dest] || 0) + 1;
if (s.dest) arrowDests.set(s.dest, (arrowDests.get(s.dest) || 0) + 1);
}

const shapes: Shape[] = d.shapes.concat(d.autoShapes).map((s: DrawShape) => {
Expand Down Expand Up @@ -60,37 +56,37 @@ export function renderSvg(state: State, root: SVGElement): void {

// append only. Don't try to update/remove.
function syncDefs(d: Drawable, shapes: Shape[], defsEl: SVGElement) {
const brushes: CustomBrushes = {};
const brushes: CustomBrushes = new Map();
let brush: DrawBrush;
for (const s of shapes) {
if (s.shape.dest) {
brush = d.brushes[s.shape.brush];
if (s.shape.modifiers) brush = makeCustomBrush(brush, s.shape.modifiers);
brushes[brush.key] = brush;
brushes.set(brush.key, brush);
}
}
const keysInDom: {[key: string]: boolean} = {};
const keysInDom = new Set();
let el: SVGElement | undefined = defsEl.firstChild as SVGElement;
while (el) {
keysInDom[el.getAttribute('cgKey') as string] = true;
keysInDom.add(el.getAttribute('cgKey'));
el = el.nextSibling as SVGElement | undefined;
}
for (const key in brushes) {
if (!keysInDom[key]) defsEl.appendChild(renderMarker(brushes[key]));
for (const [key, brush] of brushes.entries()) {
if (!keysInDom.has(key)) defsEl.appendChild(renderMarker(brush));
}
}

// append and remove only. No updates.
function syncShapes(state: State, shapes: Shape[], brushes: DrawBrushes, arrowDests: ArrowDests, root: SVGElement, defsEl: SVGElement): void {
const bounds = state.dom.bounds(),
hashesInDom: {[hash: string]: boolean} = {},
hashesInDom = new Map(), // by hash
toRemove: SVGElement[] = [];
for (const sc of shapes) hashesInDom[sc.hash] = false;
for (const sc of shapes) hashesInDom.set(sc.hash, false);
let el: SVGElement | undefined = defsEl.nextSibling as SVGElement, elHash: Hash;
while (el) {
elHash = el.getAttribute('cgHash') as Hash;
// found a shape element that's here to stay
if (hashesInDom.hasOwnProperty(elHash)) hashesInDom[elHash] = true;
if (hashesInDom.has(elHash)) hashesInDom.set(elHash, true);
// or remove it
else toRemove.push(el);
el = el.nextSibling as SVGElement | undefined;
Expand All @@ -99,12 +95,12 @@ function syncShapes(state: State, shapes: Shape[], brushes: DrawBrushes, arrowDe
for (const el of toRemove) root.removeChild(el);
// insert shapes that are not yet in dom
for (const sc of shapes) {
if (!hashesInDom[sc.hash]) root.appendChild(renderShape(state, sc, brushes, arrowDests, bounds));
if (!hashesInDom.get(sc.hash)) root.appendChild(renderShape(state, sc, brushes, arrowDests, bounds));
}
}

function shapeHash({orig, dest, brush, piece, modifiers}: DrawShape, arrowDests: ArrowDests, current: boolean, bounds: ClientRect): Hash {
return [bounds.width, bounds.height, current, orig, dest, brush, dest && arrowDests[dest] > 1,
return [bounds.width, bounds.height, current, orig, dest, brush, dest && (arrowDests.get(dest) || 0) > 1,
piece && pieceHash(piece),
modifiers && modifiersHash(modifiers)
].filter(x => x).join(',');
Expand Down Expand Up @@ -135,7 +131,7 @@ function renderShape(state: State, {shape, current, hash}: Shape, brushes: DrawB
orig,
orient(key2pos(shape.dest), state.orientation),
current,
arrowDests[shape.dest] > 1,
(arrowDests.get(shape.dest) || 0) > 1,
bounds);
}
else el = renderCircle(brushes[shape.brush], orig, current, bounds);
Expand Down

0 comments on commit c190c18

Please sign in to comment.