Skip to content

Commit 3ac33e0

Browse files
author
Michael Johnston
committed
Initial commit
0 parents  commit 3ac33e0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+4398
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
build
2+
node_modules

LICENSE

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
Copyright (c) 2015, Flipboard
2+
All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without modification,
5+
are permitted provided that the following conditions are met:
6+
7+
* Redistributions of source code must retain the above copyright notice, this
8+
list of conditions and the following disclaimer.
9+
10+
* Redistributions in binary form must reproduce the above copyright notice, this
11+
list of conditions and the following disclaimer in the documentation and/or
12+
other materials provided with the distribution.
13+
14+
* Neither the name of Flipboard nor the names of its
15+
contributors may be used to endorse or promote products derived from
16+
this software without specific prior written permission.
17+
18+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# react-canvas
2+
3+
[Introductory blog post](http://engineering.flipboard.com/2015/02/mobile-web/)
4+
5+
React Canvas adds the ability for React components to render to `<canvas>` rather than DOM.
6+
7+
This project is a work-in-progress. Though much of the code is in production on flipboard.com, the React canvas bindings are relatively new and the API is subject to change.
8+
9+
## Motivation
10+
11+
Having a long history of building interfaces geared toward mobile devices, we found that the reason mobile web apps feel slow when compared to native apps is the DOM. CSS animations and transitions are the fastest path to smooth animations on the web, but they have several limitiations. React Canvas leverages the fact that most modern mobile browsers now have hardware accelerated canvas.
12+
13+
While there have been other attempts to bind canvas drawing APIs to React, they are more focused on visualizations and games. Where React Canvas differs is in the focus on building application user interfaces. The fact that it renders to canvas is an implementation detail.
14+
15+
React Canvas brings some of the APIs web developers are familiar with and blends them with a high performance drawing engine.
16+
17+
## React Canvas Components
18+
19+
React Canvas provides a set of standard React components that abstract the underlying rendering implementation.
20+
21+
### &lt;Surface&gt;
22+
23+
**Surface** is the top-level component. Think of it as a drawing canvas in which you can place other components.
24+
25+
### &lt;Layer&gt;
26+
27+
**Layer** is the the base component by which other components build upon. Common styles and properties such as top, width, left, height, backgroundColor and zIndex are expressed at this level.
28+
29+
### &lt;Group&gt;
30+
31+
**Group** is a container component. Because React enforces that all components return a single component in `render()`, Groups can be useful for parenting a set of child components. The Group is also an important component for optimizing scrolling performance, as it allows the rendering engine to cache expensive drawing operations.
32+
33+
### &lt;Text&gt;
34+
35+
**Text** is a flexible component that supports multi-line truncation, something which has historically been difficult and very expensive to do in DOM.
36+
37+
### &lt;Image&gt;
38+
39+
**Image** is exactly what you think it is. However, it adds the ability to hide an image until it is fully loaded and optionally fade it in on load.
40+
41+
### &lt;ListView&gt;
42+
43+
**ListView** is a touch scrolling container that renders a list of elements in a column. Think of it like UITableView for the web. It leverages many of the same optimizations that make table views on iOS and list views on Android fast.
44+
45+
## Events
46+
47+
React Canvas components support the same event model as normal React components. However, not all event types are currently supported.
48+
49+
For a full list of supported events see [EventTypes](lib/EventTypes.js).
50+
51+
## Building Components
52+
53+
Here is a very simple component that renders text below an image:
54+
55+
```javascript
56+
var React = require('react');
57+
var ReactCanvas = require('react-canvas');
58+
59+
var Surface = ReactCanvas.Surface;
60+
var Image = ReactCanvas.Image;
61+
var Text = ReactCanvas.Text;
62+
63+
var MyComponent = React.createClass({
64+
65+
render: function () {
66+
var surfaceWidth = window.innerWidth;
67+
var surfaceHeight = window.innerHeight;
68+
var imageStyle = this.getImageStyle();
69+
var textStyle = this.getTextStyle();
70+
71+
return (
72+
<Surface width={surfaceWidth} height={surfaceHeight} left={0} top={0}>
73+
<Image style={imageStyle} src='...' />
74+
<Text style={textStyle}>
75+
Here is some text below an image.
76+
</Text>
77+
</Surface>
78+
);
79+
},
80+
81+
getImageHeight: function () {
82+
return Math.round(window.innerHeight / 2);
83+
},
84+
85+
getImageStyle: function () {
86+
return {
87+
top: 0,
88+
left: 0,
89+
width: window.innerWidth,
90+
height: this.getImageHeight()
91+
};
92+
},
93+
94+
getTextStyle: function () {
95+
return {
96+
top: this.getImageHeight() + 10,
97+
left: 0,
98+
width: window.innerWidth,
99+
height: 20,
100+
lineHeight: 20,
101+
fontSize: 12
102+
};
103+
}
104+
105+
});
106+
```
107+
108+
## ListView
109+
110+
Many mobile interfaces involve an infinitely long scrolling list of items. React Canvas provides the ListView component to do just that.
111+
112+
Because ListView virtualizes elements outside of the viewport, passing children to it is different than a normal React component where children are declared in render().
113+
114+
The `numberOfItemsGetter`, `itemHeightGetter` and `itemGetter` props are all required.
115+
116+
```javascript
117+
var ListView = ReactCanvas.ListView;
118+
119+
var MyScrollingListView = React.createClass({
120+
121+
render: function () {
122+
return (
123+
<ListView
124+
numberOfItemsGetter={this.getNumberOfItems}
125+
itemHeightGetter={this.getItemHeight}
126+
itemGetter={this.renderItem} />
127+
);
128+
},
129+
130+
getNumberOfItems: function () {
131+
// Return the total number of items in the list
132+
},
133+
134+
getItemHeight: function () {
135+
// Return the height of a single item
136+
},
137+
138+
renderItem: function (index) {
139+
// Render the item at the given index, usually a <Group>
140+
},
141+
142+
});
143+
```
144+
145+
See the [timeline example](examples/timeline/app.js) for a more complete example.
146+
147+
Currently, ListView requires that each item is of the same height. Future versions will support variable height items.
148+
149+
## Text sizing
150+
151+
React Canvas provides the `measureText` function for computing text metrics.
152+
153+
The [Page component](examples/timeline/components/Page.js) in the timeline example contains an example of using measureText to achieve precise multi-line ellipsized text.
154+
155+
Custom fonts are not currently supported but will be added in a future version.
156+
157+
## css-layout
158+
159+
There is experimental support for using [css-layout](https://github.com/facebook/css-layout) to style React Canvas components. This is a more expressive way of defining styles for a component using standard CSS styles and flexbox.
160+
161+
Future versions may not support css-layout out of the box. The performance implications need to be investigated before baking this in as a core layout principle.
162+
163+
See the [css-layout example](examples/css-layout).
164+
165+
## Accessibility
166+
167+
This area needs further exploration. Using fallback content (the canvas DOM sub-tree) should allow screen readers such as VoiceOver to interact with the content. We've seen mixed results with the iOS devices we've tested. Additionally there is a standard for [focus management](http://www.w3.org/TR/2010/WD-2dcontext-20100304/#dom-context-2d-drawfocusring) that is not supported by browsers yet.
168+
169+
One approach that was raised by [Bespin](http://vimeo.com/3195079) in 2009 is to keep a [parallel DOM](http://robertnyman.com/2009/04/03/mozilla-labs-online-code-editor-bespin/#comment-560310) in sync with the elements rendered in canvas.
170+
171+
## Running the examples
172+
173+
```
174+
npm install
175+
npm start
176+
```
177+
178+
This will start a live reloading server on port 8080.
179+
180+
**A note on NODE_ENV and React**: running the examples with `NODE_ENV=production` will noticeably improve scrolling performance. This is because React skips propType validation in production mode.

examples/common/data.js

Lines changed: 52 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/common/examples.css

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
html, body {
2+
margin: 0;
3+
padding: 0;
4+
font: 16px Helvetica, sans-serif;
5+
height: 100%;
6+
overflow: hidden;
7+
background: #ddd;
8+
}
9+
10+
#main {
11+
background: #fff;
12+
position: relative;
13+
height: 100%;
14+
max-width: 420px;
15+
max-height: 700px;
16+
}

0 commit comments

Comments
 (0)