Skip to content

Commit

Permalink
feat: create shape from existing DOM nodes
Browse files Browse the repository at this point in the history
Closes #8.
  • Loading branch information
colinmeinke committed Jun 30, 2016
1 parent e398777 commit 83a1437
Show file tree
Hide file tree
Showing 10 changed files with 184 additions and 18 deletions.
26 changes: 20 additions & 6 deletions README.md
Expand Up @@ -470,9 +470,9 @@ one shape to the next.
A **shape** represents a shape over time.

A shape is created by passing one or more
[plain shape object](#plain-shape-object) into the
[plain shape objects](#plain-shape-object) into the
[`shape()` function](#shape-function). Plain shape objects
passed to the `shape()` function have
passed to the `shape()` function may have
[animation properties](#animation-properties).

Shapes are *renderable* and can be passed into the
Expand Down Expand Up @@ -545,10 +545,24 @@ shape( shape1[, shape2[, ..., shapeN ]]);

Where:

- `shape1` is a *[plain shape object](#plain-shape-object)*
that represents the initial state of a shape
- `shapeN` is a *plain shape object* that represents the state
of a shape at a specific point in time
- `shape1` is either:
- a *[plain shape object](#plain-shape-object)* that
represents the initial state of a shape
- an *object* that includes:
- `selector` is a *string* that will be passed to
[querySelector](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector)
to get an existing element from the DOM. This must
return an SVG shape that will be used to create a plain
shape object
- `shapeN` is either:
- a *plain shape object* that represents the state of a
shape at a specific point in time
- an *object* that includes:
- `selector` is a *string* that will be passed to
[querySelector](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector)
to get an existing element from the DOM. This must
return an SVG shape that will be used to create a plain
shape object

### `timeline()` function

Expand Down
3 changes: 3 additions & 0 deletions examples/multi/.gitignore
@@ -0,0 +1,3 @@
client.dist.js
node_modules/
npm-debug.log
10 changes: 10 additions & 0 deletions examples/multi/README.md
@@ -0,0 +1,10 @@
# Wilderness multi example

## Usage

```
npm install
npm run build
```

Then open `index.html` in your browser.
16 changes: 16 additions & 0 deletions examples/multi/client.js
@@ -0,0 +1,16 @@
import { shape, render, play } from '../../src';

const animation = shape(
{ selector: '.positionA' },
{ selector: '.positionB', duration: 800, reverse: true },
{ selector: '.positionC', duration: 1200, reverse: true, moveIndex: 2 },
{ selector: '.positionD', duration: 2000, reverse: true, easing: 'easeOutElastic' },
{ selector: '.positionA', duration: 3000, easing: 'easeInElastic' }
);

render({ selector: '.svg' }, animation );

play( animation, {
alternate: true,
iterations: Infinity,
});
40 changes: 40 additions & 0 deletions examples/multi/index.html
@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html>
<head>
<title>Wilderness multi example</title>
<style>
html,
body {
height: 100%;
}

body {
margin: 0;
}

.svg {
height: 100%;
width: 100%;
}

.hide {
display: none;
}
</style>
</head>
<body>
<svg
class="svg"
height="100"
preserveAspectRatio="xMidYMid meet"
viewBox="0 0 100 100"
width="100"
>
<circle class="positionA" cx="70" cy="80" r="10" fill="#E54"></circle>
<rect class="positionB hide" x="10" y="10" width="50" height="30" fill="#0FA"></rect>
<path class="positionC hide" d="M25,55l20,15h-30z" fill="#E54"></path>
<path class="positionD hide" d="M70,35h10l5,-5,5,5v10l5,5-5,5h-10l-5,5,-5,-5v-10l-5,-5z" fill="#0FA"></path>
</svg>
<script src="./client.dist.js"></script>
</body>
</html>
34 changes: 34 additions & 0 deletions examples/multi/package.json
@@ -0,0 +1,34 @@
{
"author": {
"name": "Colin Meinke",
"email": "hello@colinmeinke.com",
"url": "www.colinmeinke.com"
},
"babel": {
"plugins": [
"transform-object-rest-spread"
],
"presets": [
"es2015"
]
},
"bugs": {
"url": "https://github.com/colinmeinke/wilderness/issues"
},
"description": "Wilderness multi example",
"devDependencies": {
"babel-plugin-transform-object-rest-spread": "^6.8.0",
"babel-preset-es2015": "^6.9.0",
"babelify": "^7.3.0",
"browserify": "^13.0.1"
},
"license": "ISC",
"repository": {
"type": "git",
"url": "https://github.com/colinmeinke/wilderness.git"
},
"scripts": {
"build": "browserify ./client.js -o ./client.dist.js -t babelify"
},
"version": "0.0.0-semantically-released"
}
9 changes: 6 additions & 3 deletions src/core/helpers/tween.js
Expand Up @@ -10,9 +10,12 @@ export default ( shape1, shape2, time, duration, ease ) => {
if ( typeof from === 'number' && typeof to === 'number' ) {
return ease( time, from, to, duration );
} else if ( typeof from === 'string' && typeof to === 'string' ) {
return colorOut(
match( colorIn( from ), colorIn( to ), tween )
);
const f = colorIn( from );
const t = colorIn( to );

if ( typeof f === 'object' && typeof t === 'object' ) {
return colorOut( match( f, t, tween ));
}
}

return from;
Expand Down
2 changes: 1 addition & 1 deletion src/core/shape/update.js
Expand Up @@ -38,7 +38,7 @@ const currentShape = ({ shapes, state, timeline }) => {
const duration = animation.duration * scale;
const time = duration * offset / scale;

const easing = animation.easing || shape2.animation.easing;
const easing = shape2.animation.easing || animation.easing;
const ease = typeof easing === 'function' ? easing : easingFunc( easing );

return tween( shape1, shape2, time, duration, ease );
Expand Down
20 changes: 14 additions & 6 deletions src/dom/render/index.js
Expand Up @@ -6,9 +6,7 @@ const svgAttrs = [
];

const render = ( target, ...playable ) => {
const { selector, ...attrs } = target;

const container = document.querySelector( selector );
const container = document.querySelector( target.selector );

let svg;

Expand All @@ -17,16 +15,26 @@ const render = ( target, ...playable ) => {
} else {
svg = document.createElementNS( 'http://www.w3.org/2000/svg', 'svg' );

Object.keys( attrs )
Object.keys( target )
.filter( attr => svgAttrs.indexOf( attr ) !== -1 )
.forEach( attr => {
svg.setAttribute( attr, attrs[ attr ]);
svg.setAttribute( attr, target[ attr ]);
});

container.appendChild( svg );
}

playable.forEach(({ state }) => svg.appendChild( state.node ));
playable.map(({ selector, state }) => {
if ( selector ) {
const el = svg.querySelector( selector );

if ( el ) {
return el.parentNode.replaceChild( state.node, el );
}
}

return svg.appendChild( state.node );
});
}

export default render;
42 changes: 40 additions & 2 deletions src/dom/shape/index.js
@@ -1,4 +1,32 @@
import { createShape, updateShape } from '../../core';
import { stylePropAttrMap } from '../../core/shape/props';

const attrMap = { ...stylePropAttrMap };
const attrKeys = Object.keys( attrMap );
const attrValues = attrKeys.map( k => attrMap[ k ]);

const shapeFromDom = selector => {
if ( !selector ) {
return {};
}

const { attributes, nodeName: type } = document.querySelector( selector );
const shape = { type };

Object.keys( attributes ).map( k => {
let { name, value } = attributes[ k ];

const i = attrValues.indexOf( name );

if ( i > -1 ) {
name = attrKeys[ i ];
}

shape[ name ] = isNaN( value ) ? value : parseFloat( value );
});

return shape;
};

const createNode = shape => {
shape.state.node = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );
Expand All @@ -16,9 +44,19 @@ const update = shape => {
updateNode( shape );
};

const create = ( ...args ) => {
const shape = createShape( ...args );
const create = ( ...shapes ) => {
const s = shapes.map(({ selector, ...props }) => {
return { ...shapeFromDom( selector ), ...props };
});

const shape = createShape( ...s );

if ( shapes[ 0 ].selector ) {
shape.selector = shapes[ 0 ].selector;
}

createNode( shape );

return shape;
};

Expand Down

0 comments on commit 83a1437

Please sign in to comment.