Skip to content

Commit

Permalink
[Canvas][Layout Engine] TypeScript conversion - Stage I (elastic#29390)
Browse files Browse the repository at this point in the history
* Perf: avoid matrix transpose in canvas layout that served only initial docu purpose, don't cons extra arrays
* Chore: switch to ES2015 import/export and direct function access
* Chore: TS conversion for some of the layout engine files
* Chore: rework TS linting for all files under `aeroelastic` (even the `.js` ones)
  • Loading branch information
monfera authored Feb 13, 2019
1 parent 3469347 commit 1db3afc
Show file tree
Hide file tree
Showing 22 changed files with 2,097 additions and 2,206 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import React from 'react';
import PropTypes from 'prop-types';
import aero from '../../lib/aeroelastic';
import { toCSS } from '../../lib/aeroelastic';

export const AlignmentGuide = ({ transformMatrix, width, height }) => {
const newStyle = {
Expand All @@ -16,7 +16,7 @@ export const AlignmentGuide = ({ transformMatrix, width, height }) => {
marginTop: -height / 2,
background: 'magenta',
position: 'absolute',
transform: aero.dom.matrixToCSS(transformMatrix),
transform: toCSS(transformMatrix),
};
return (
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import React from 'react';
import PropTypes from 'prop-types';
import aero from '../../lib/aeroelastic';
import { toCSS } from '../../lib/aeroelastic';

export const BorderConnection = ({ transformMatrix, width, height }) => {
const newStyle = {
Expand All @@ -15,7 +15,7 @@ export const BorderConnection = ({ transformMatrix, width, height }) => {
marginLeft: -width / 2,
marginTop: -height / 2,
position: 'absolute',
transform: aero.dom.matrixToCSS(transformMatrix),
transform: toCSS(transformMatrix),
};
return <div className="canvasBorder--connection canvasLayoutAnnotation" style={newStyle} />;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@

import React from 'react';
import PropTypes from 'prop-types';
import aero from '../../lib/aeroelastic';
import { toCSS } from '../../lib/aeroelastic';

export const BorderResizeHandle = ({ transformMatrix }) => (
<div
className="canvasBorderResizeHandle canvasLayoutAnnotation"
style={{ transform: aero.dom.matrixToCSS(transformMatrix) }}
style={{ transform: toCSS(transformMatrix) }}
/>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@

import React from 'react';
import PropTypes from 'prop-types';
import aero from '../../lib/aeroelastic';
import { toCSS } from '../../lib/aeroelastic';

export const HoverAnnotation = ({ transformMatrix, width, height }) => {
const newStyle = {
width,
height,
marginLeft: -width / 2,
marginTop: -height / 2,
transform: aero.dom.matrixToCSS(transformMatrix),
transform: toCSS(transformMatrix),
};
return <div className="canvasHoverAnnotation canvasLayoutAnnotation" style={newStyle} />;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import React from 'react';
import PropTypes from 'prop-types';
import aero from '../../lib/aeroelastic';
import { toCSS } from '../../lib/aeroelastic';

export const Positionable = ({ children, transformMatrix, width, height }) => {
// Throw if there is more than one child
Expand All @@ -19,7 +19,7 @@ export const Positionable = ({ children, transformMatrix, width, height }) => {
marginLeft: -width / 2,
marginTop: -height / 2,
position: 'absolute',
transform: aero.dom.matrixToCSS(transformMatrix.map((n, i) => (i < 12 ? n : Math.round(n)))),
transform: toCSS(transformMatrix.map((n, i) => (i < 12 ? n : Math.round(n)))),
};

const stepChild = React.cloneElement(child, { size: { width, height } });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@

import React from 'react';
import PropTypes from 'prop-types';
import aero from '../../lib/aeroelastic';
import { toCSS } from '../../lib/aeroelastic';

export const RotationHandle = ({ transformMatrix }) => (
<div
className="canvasRotationHandle canvasRotationHandle--connector canvasLayoutAnnotation"
style={{ transform: aero.dom.matrixToCSS(transformMatrix) }}
style={{ transform: toCSS(transformMatrix) }}
>
<div className="canvasRotationHandle--handle" />
</div>
Expand Down
69 changes: 0 additions & 69 deletions x-pack/plugins/canvas/public/lib/aeroelastic/config.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { transformMatrix3d } from './types';

// converts a transform matrix to a CSS string
const matrixToCSS = transformMatrix =>
export const matrixToCSS = (transformMatrix: transformMatrix3d): string =>
transformMatrix ? 'matrix3d(' + transformMatrix.join(',') + ')' : 'translate3d(0,0,0)';

// converts to string, and adds `px` if non-zero
const px = value => (value === 0 ? '0' : value + 'px');

module.exports = {
matrixToCSS,
px,
};
export const px = (value: number): string => (value === 0 ? '0' : value + 'px');
54 changes: 16 additions & 38 deletions x-pack/plugins/canvas/public/lib/aeroelastic/functional.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@
* @param {*[][]} arrays
* @returns *[]
*/
const flatten = arrays => [].concat(...arrays);
export const flatten = arrays => [].concat(...arrays);

/**
* identity
*
* @param d
* @returns d
*/
const identity = d => d;
export const identity = d => d;

/**
* map
Expand All @@ -32,19 +32,7 @@ const identity = d => d;
* @param {Function} fun
* @returns {function(*): *}
*/
const map = fun => array => array.map(value => fun(value));

/**
* log
*
* @param d
* @param {Function} printerFun
* @returns d
*/
const log = (d, printerFun = identity) => {
console.log(printerFun(d));
return d;
};
export const map = fun => array => array.map(value => fun(value));

/**
* disjunctiveUnion
Expand All @@ -54,7 +42,7 @@ const log = (d, printerFun = identity) => {
* @param {*[]} set2
* @returns *[]
*/
const disjunctiveUnion = (keyFun, set1, set2) =>
export const disjunctiveUnion = (keyFun, set1, set2) =>
set1
.filter(s1 => !set2.find(s2 => keyFun(s2) === keyFun(s1)))
.concat(set2.filter(s2 => !set1.find(s1 => keyFun(s1) === keyFun(s2))));
Expand All @@ -65,9 +53,9 @@ const disjunctiveUnion = (keyFun, set1, set2) =>
* @param {number} b
* @returns {number} the mean of the two parameters
*/
const mean = (a, b) => (a + b) / 2;
export const mean = (a, b) => (a + b) / 2;

const shallowEqual = (a, b) => {
export const shallowEqual = (a, b) => {
if (a === b) {
return true;
}
Expand All @@ -82,31 +70,21 @@ const shallowEqual = (a, b) => {
return true;
};

const not = fun => (...args) => !fun(...args);
export const not = fun => (...args) => !fun(...args);

const removeDuplicates = (idFun, a) =>
export const removeDuplicates = (idFun, a) =>
a.filter((d, i) => a.findIndex(s => idFun(s) === idFun(d)) === i);

const arrayToMap = a => Object.assign({}, ...a.map(d => ({ [d]: true })));
export const arrayToMap = a => Object.assign({}, ...a.map(d => ({ [d]: true })));

const subMultitree = (pk, fk, elements, roots) => {
export const subMultitree = (pk, fk, elements, inputRoots) => {
const getSubgraphs = roots => {
const children = flatten(roots.map(r => elements.filter(e => fk(e) === pk(r))));
return [...roots, ...(children.length && getSubgraphs(children, elements))];
if (children.length) {
return [...roots, ...getSubgraphs(children, elements)];
} else {
return roots;
}
};
return getSubgraphs(roots);
};

module.exports = {
arrayToMap,
disjunctiveUnion,
flatten,
subMultitree,
identity,
log,
map,
mean,
not,
removeDuplicates,
shallowEqual,
return getSubgraphs(inputRoots);
};
25 changes: 10 additions & 15 deletions x-pack/plugins/canvas/public/lib/aeroelastic/geometry.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

const matrix = require('./matrix');
import { invert, mvMultiply, normalize, ORIGIN } from './matrix';

/**
* Pure calculations with geometry awareness - a set of rectangles with known size (a, b) and projection (transform matrix)
Expand Down Expand Up @@ -40,9 +40,9 @@ const shapesAtPoint = (shapes, x, y) =>

// Determine z (depth) by composing the x, y vector out of local unit x and unit y vectors; by knowing the
// scalar multipliers for the unit x and unit y vectors, we can determine z from their respective 'slope' (gradient)
const centerPoint = matrix.normalize(matrix.mvMultiply(transformMatrix, matrix.ORIGIN));
const rightPoint = matrix.normalize(matrix.mvMultiply(transformMatrix, [1, 0, 0, 1]));
const upPoint = matrix.normalize(matrix.mvMultiply(transformMatrix, [0, 1, 0, 1]));
const centerPoint = normalize(mvMultiply(transformMatrix, ORIGIN));
const rightPoint = normalize(mvMultiply(transformMatrix, [1, 0, 0, 1]));
const upPoint = normalize(mvMultiply(transformMatrix, [0, 1, 0, 1]));
const x0 = rightPoint[0] - centerPoint[0];
const y0 = rightPoint[1] - centerPoint[1];
const x1 = upPoint[0] - centerPoint[0];
Expand All @@ -58,8 +58,8 @@ const shapesAtPoint = (shapes, x, y) =>
// Hmm maybe we should reuse the above right and up unit vectors to establish whether we're within the (a, b) 'radius'
// rather than using matrix inversion. Bound to be cheaper.

const inverseProjection = matrix.invert(transformMatrix);
const intersection = matrix.normalize(matrix.mvMultiply(inverseProjection, [x, y, z, 1]));
const inverseProjection = invert(transformMatrix);
const intersection = normalize(mvMultiply(inverseProjection, [x, y, z, 1]));
const [sx, sy] = intersection;

// z is needed downstream, to tell which one is the closest shape hit by an x, y ray (shapes can be tilted in z)
Expand All @@ -76,18 +76,13 @@ const shapesAtPoint = (shapes, x, y) =>
//
// If it were a right handed coordinate system, AND Y still pointed down, then Z should increase away from the
// viewer. But that's not the case. So we maximize the Z value to tell what's on top.
const shapesAt = (shapes, { x, y }) =>
export const shapesAt = (shapes, { x, y }) =>
shapesAtPoint(shapes, x, y)
.filter(shape => shape.inside)
.sort((shape1, shape2) => shape2.z - shape1.z || shape2.index - shape1.index) // stable sort: DOM insertion order!!!
.map(shape => shape.shape); // decreasing order, ie. from front (closest to viewer) to back

const getExtremum = (transformMatrix, a, b) =>
matrix.normalize(matrix.mvMultiply(transformMatrix, [a, b, 0, 1]));
const getExtremum = (transformMatrix, a, b) => normalize(mvMultiply(transformMatrix, [a, b, 0, 1]));

const landmarkPoint = (a, b, transformMatrix, k, l) => getExtremum(transformMatrix, k * a, l * b);

module.exports = {
landmarkPoint,
shapesAt,
};
export const landmarkPoint = (a, b, transformMatrix, k, l) =>
getExtremum(transformMatrix, k * a, l * b);
Loading

0 comments on commit 1db3afc

Please sign in to comment.