GithubHelp home page GithubHelp logo

wix-incubator / react-native-keyboard-input Goto Github PK

View Code? Open in Web Editor NEW
818.0 281.0 150.0 8.61 MB

Use your own custom input component instead of the system keyboard

License: MIT License

JavaScript 29.40% Objective-C 33.08% Java 29.16% Objective-C++ 3.41% Ruby 3.12% Starlark 1.83%
react-native ios android keyboard-input keyboard keyboard-component inputaccessoryview

react-native-keyboard-input's Introduction

Important: deprecation alert

This library is being deprecated and the repository will not be maintaned, the components have moved to our UI library - please start migrating to RN-UILib.
If you want to try out our excelent (and constantly improving) UI compoenent library, please use:

import {Keyboard} from 'react-native-ui-lib';
const KeyboardAccessoryView = Keyboard.KeyboardAccessoryView;

If you don't want to import the whole library, you can use only the keyboard package:

import {KeyboardAccessoryView} from 'react-native-ui-lib/keyboard';

React Native Keyboard Input

Presents a React component as an input view which replaces the system keyboard. Can be used for creating custom input views such as an image gallery, stickers, etc.

Supports both iOS and Android.

Installation

Install the package from npm:

yarn add react-native-keyboard-input or npm i --save react-native-keyboard-input

Android

Update your dependencies in android/app/build.gradle:

dependencies {
  // Add this dependency:
  compile project(":reactnativekeyboardinput")
}

Update your android/settings.gradle:

include ':reactnativekeyboardinput'
project(':reactnativekeyboardinput').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keyboard-input/lib/android')

In your MainApplication.java, add to the getPackages() list:

import com.wix.reactnativekeyboardinput.KeyboardInputPackage;

@Override
protected List<ReactPackage> getPackages() {
  return Arrays.<ReactPackage>asList(
      // Add this package:
      new KeyboardInputPackage(this) // (this = Android application object)
    );
}

ProGuard

If you have pro-guard enabled and are having trouble with your build, apply this to your project's main proguard-rules.pro:

-dontwarn com.wix.reactnativekeyboardinput.**

iOS

In Xcode, drag both RCTCustomInputController.xcodeproj and KeyboardTrackingView.xcodeproj from your node_modules to the Libraries folder in the Project Navigator, then add libRCTCustomInputController.a and libKeyboardTrackingView.a to your app target "Linked Frameworks and Libraries".

Covering the whold keyboard in predictive mode

To utilize this feature you'll need to add KeyboardTrackingView to your projects scheme build action.

From Xcode menu:

  1. product -> scheme -> manage schemes -> double-click your project
  2. Slect build at the right menu, click the + icon at the bottom of the targets list and select KeyboardTrackingView.
  3. Drag and position KeyboardTrackingView to be first, above your project, and unmark "Parallelize Build" option at the top.

If necessary, you can take a look at how it is set-up in the demo project.

Usage

There are 2 main parts necessary for the implementation:

1. A keyboard component

Create a component that you wish to use as a keyboard input. For example:

class KeyboardView extends Component {
  static propTypes = {
    title: PropTypes.string,
  };
  render() {
    return (
      <ScrollView contentContainerStyle={[styles.keyboardContainer, {backgroundColor: 'purple'}]}>
        <Text style={{color: 'white'}}>HELOOOO!!!</Text>
        <Text style={{color: 'white'}}>{this.props.title}</Text>
      </ScrollView>
    );
  }
}

Now register with the keyboard registry so it can be used later as a keyboard:

import {KeyboardRegistry} from 'react-native-keyboard-input';

KeyboardRegistry.registerKeyboard('MyKeyboardView', () => KeyboardView);

When you need to notify about selecting an item in the keyboard, use:

KeyboardRegistry.onItemSelected(`MyKeyboardView`, params);

2. Using the keyboard component as an input view

While this package provides several component and classes for low-level control over custom keyboard inputs, the easiets way would be to use KeyboardAccessoryView. It's the only thing you'll need to show your Keyboard component as a custom input. For example:

<KeyboardAccessoryView
  renderContent={this.keyboardToolbarContent}
  kbInputRef={this.textInputRef}
  kbComponent={this.state.customKeyboard.component}
  kbInitialProp={this.state.customKeyboard.initialProps}
/>
Prop Type Description
renderContent Function a fucntion for rendering the content of the keyboard toolbar
kbInputRef Object A ref to the input component which triggers the showing of the keyboard
kbComponent String The registered component name
kbInitialProps Object Initial props to pass to the registered keyboard component
onItemSelected Function a callback function for a selection of an item in the keyboard component

This component takes care of making your toolbar (which is rendered via renderContent ) "float" above the keyboard (necessary for iOS), and for setting your component as the keyboard input when the kbComponent changes.

Demo

See demoScreen.js for a full working example.

react-native-keyboard-input's People

Contributors

armbox avatar artald avatar d4vidi avatar ethanshar avatar guyca avatar leonatan avatar m-i-k-e-l avatar mendyedri avatar ofirdagan avatar radex avatar thorbenandresen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-native-keyboard-input's Issues

Does this work on Web?

I want to build a special keyboard where several suggestions come up and users can click on them. Of course on dekstop web, you would normally use your keyboard to type. But the suggestions would still be useful to click on. Would it be possible to share this keyboard in web and an android/ios app?

Use KeyboardAvoidingView ?

Is there a specific reason why there is a dependency on react-native-keyboard-tracking-view? Why not use KeyboardAvoidingView?

Changing orientation doesn't update input

Hey, guys.
Take a look at this gif.

apr-26-2018 10-45-57

As you can see, message box input keeps the same width after orientation changes.
I tried this.forceUpdate()with no luck :(

Can you help me?

Warning KeyboardTrackingViewManager/RCTCustomInputController requires main queue setup

Just installed this library and got two warnings:

  • Module KeyboardTrackingViewManager requires main queue setup since it overrides 'constantsToExport' but doesn't implement 'requiresMainQueueSetup'[...].
  • Module RCTCustomInputController requires main queue setup since it overrides 'init' but doesn't implement 'requiresMainQueueSetup'[...].
"react": "^16.4.1",
"react-native": "^0.55.4",
"react-native-keyboard-input": "^5.2.3",

bug?

qq 20171021164603
"react": "16.0.0-beta.5",
"react-native": "0.49.3",

iOS: Cannot expand the keyboard-input from current component

Repro

  1. Open demoApp on iOS
  2. Click on 'show1'
  3. Keyboard will expand
  4. Dismiss keyboard input
  5. Click on 'show1'

Expected:

  • Keyboard will expand

Actual:

  • nothing happens (However 'show2' works)

Notes:

I have been working around this by resetting the this.state.customKeyboard to an empty object whenever the keyboard is hidden: https://gist.github.com/Thorbenandresen/ff416493dfed8c2860fdeb6c01fcc91b (see componentDidUpdate)

In order to prevent the keyboard from popping up, I have commented out TextInputKeyboardManagerIOS.removeInputComponent(inputRef); from CustomKeyboardView.js

However I am not sure yet if this is the way to go or if this introduced un-intended consequences.

Random red box around accessory?

Heya guys. I have a red box around my "KeyboardAccessoryViewContent"
Im pretty much using the code from the "Getting Started" section. On android, it looks fine, but iOS has this red box around the accessory, as you can see below.

RN version: 48.1
RNKI version: 5.0.0

screen shot 2018-01-25 at 3 25 30 pm

Using this package with second Text Input in KeyboardAccessoryView

This more a feature idea than an issue.

I have another Text Input in the KeyboardAccessoryView for Gif Search.

Example

simulator screen shot apr 5 2017 5 35 43 pm

The problem is, that if this second TextInput is focused and I dismiss the keyboard, the KeyboardAccessoryView will stain in place (no matter if I use keyboardDismissMode 'interactive' or 'on-drag'.)

This worked for me with keyboardDismissMode = {'on-drag'} on version 2 releases.

simulator screen shot apr 5 2017 5 43 53 pm

How to adjust custom keyboard's height?

How do I make the custom keyboard adapt to its height? See gif of current behavior, when the keyboard switches between views and I switch to the custom keyboard (the image picker) the custom keyboard's height keeps the height of the previous one. My custom keyboard is shorter than all the native ones.

Code:

<KeyboardAccessoryView
  renderContent={this.keyboardAccessoryViewContent}
  kbInputRef={this.textInputRef}
  kbComponent={this.state.customKeyboard}
  onItemSelected={this.onKeyboardItemSelected}
  onKeyboardResigned={this.onKeyboardResigned}
  revealKeyboardInteractive
  requiresSameParentToManageScrollView
/>

and my keyboard

import React, { Component } from 'react';
import { KeyboardRegistry } from 'react-native-keyboard-input';
import { ImagePickerComponent } from '@components';

class ImagePickerKeyboard extends Component {
  state = {
    selectedImages: [],
  };

  handleOnAssetSelected = images => {
    const parsedImages = images.map(image => ({
      ...image.node.image,
      path: image.node.image.uri,
    }));

    this.setState({
      selectedImages: [...this.state.selectedImages, ...parsedImages],
    });

    KeyboardRegistry.onItemSelected('ImagePickerKeyboard', parsedImages);
  };

  render() {
    return (
      <ImagePickerComponent
        assetType="Photos"
        onAssetSelected={this.handleOnAssetSelected}
        selectedImages={this.state.selectedImages}
        confirmQuickSelectAsset
      />
    );
  }
}

export default ImagePickerKeyboard;

kapture 2018-06-01 at 11 20 32

White background while loading component

Hi,

is there a way to supply a color which would be shown instead on the white background while loading a custom keyboard? I sometimes get white flashes when opening/switching custom keyboards, especially if there is a lot going on in the JS thread.

Issues/Questions about keyboard dismiss

Hi,

thanks a lot for making this available to everyone!

I have couple of issues / questions about dismissing the custom keyboards:

  • on iOS with keyboardDismissMode: interactive, the KeyboardAccessoryView's renderContent (i.e. the input bar) will stay fixed, while only the custom keyboard components are dismissed interactively. This is not a problem when the native keyboard is shown.

simulator screen shot mar 29 2017 8 54 22 pm

  • on Android keyboardDismissMode: on-drag does only work when the native keyboard is shown, but not when a custom keyboard is shown.

  • is there a method to dismiss a custom keyboard ? (e.g. which I can attach to an onClick handler outside the keyboard). Keyboard.dismiss() does only dismiss when the native keyboard is shown, but not when a custom keyboard is shown.

RN 0.38 / demoApp.js

Different behavior on iOS simulator vs. physical device

When I'm testing out my app and using the keyboard in the iOS simulator, everything works great. However, when I switch over to testing it out on my physical phone, the text input stays at the bottom of the screen and the keyboard lays on top of it.

Screenshot of iOS simulator
screen shot 2017-11-09 at 9 29 30 am

Screenshot of physical device
screen shot 2017-11-09 at 9 57 00 am

I'm using a <KeyboardAccessoryView> with <AutoGrowingTextInput> within it.

Has anyone experienced similar behavior?

onKeyboardItemSelected is called multiple times

demoApp

Repro

  1. add a console.log() to onKeyboardItemSelected()
  2. Show keyboard by pressing "show2"
  3. click in the text input
  4. repeat the last two steps x times
  5. Click "Click Me too!"

Expected
onKeyboardItemSelected() is only called once

Actual
onKeyboardItemSelected() is called x times

Note:
Kinda hacky, but I currently work around it by debouncing my method calls like this:

   this.latestStickerMessageTimeStamp = Date.now()
   [...]

  onKeyboardItemSelected(keyboardId, params) {

    if (keyboardId === 'KeyboardCustomStickers'){

      if (Date.now() - this.latestStickerMessageTimeStamp > 100) {
        params.stickerObj && this.onSubmitCustomKeyboardImage(params.stickerObj)
      }
      this.latestStickerMessageTimeStamp = Date.now()
}

FlatList not responding to keyboard (looking for help)

So I'm sure I've probably missed something, but I'd like to never cover any content with the keyboard. Basically, KeyboardAvoidingView's behavior="padding", but I cannot figure out to implement it with KeyboardAccessoryView.

Attaching gif to illustrate (this is what I have, not the behavior I want :))
kapture 2018-04-10 at 15 24 31

My code is as following

  return (
    <View style={{ flex: 1 }}>
      <FlatList
        inverted
        data={data}
        ...
      />
      <KeyboardAccessoryView
        renderContent={this.keyboardAccessoryViewContent}
        kbInputRef={this.textInputRef}
        kbComponent={this.state.customKeyboard.component}
        kbInitialProps={this.state.customKeyboard.initialProps}
        onItemSelected={this.onKeyboardItemSelected}
        onKeyboardResigned={this.onKeyboardResigned}
      />
    </View>
  );

Using
"react-native-keyboard-input": "^5.2.0"
"react": "16.0.0"
"react-native": "0.53.0"

Keyboard behavior changed to 'position'

Hi @artald, thanks so much for all the fixes & enhancement, this is really great stuff!

After I installed the latest version (3.0.2) I discovered that the keyboard behavior changed to 'position'. By 'position' I mean that the the underlying view is pushed up when the keyboard appears, while before it was just overlaying the view.

The problem is that I need to implement the keyboardavoidingview with the behavior 'padding', i.e. 'position' behavior is breaking my layout.

Can we make the keyboard behavior a prop?

ListView with empty datasource is not keyboard tracking

hey @artald,

when I pass an empty array into the datasource of the ListView, that ListView (i.e. the underlying scroll component) will not be keyboard tracking.

I know that it worked before, but I can't pinpoint yet when/how it broke. I am currently using:

  • RN 43
  • keyboard-input v3.0.21.
  • keyboard-tracking-view v3.0.9 (added as first level dep, to work around #22)

I don't know if this an actual issue. There are easy ways for us to work around it, so this is not a high priority.

Again, I see if I can provide a repro soon :)

KeyboardAccessoryView offset inconsistent

Hi Artal!

Repro:

  1. Add a background color to the the styles.scrollContainer (e.g. 'red')
  2. Load demo app => no offset, red background is visible through the blur view
  3. open keyboard => no offset, red background is visible through the blur view
  4. close keyboard => offset = height of KeyboardAccessoryView
  5. open keyboard => offset = height of KeyboardAccessoryView
    (see screenshots below)

I don't know what the best solution for this is, either

  • a) no offset, i.e. the developer would implement an offset via padding, renderFooter.
  • b) offset, i.e. the scrollview is always on top.

I eventually want to implement a behavior where the offset is always equal to the height of the KeyboardAccessoryView. So for example whenever my textInput box grows to another line, I also want the offset to increase (Similar to WhatsApp or iMessage). I know how to do this with JS for solution a), but I am not sure how hard it would be if solution b) gets implemented.

Thanks!

simulator screen shot apr 16 2017 6 27 18 pm

simulator screen shot apr 16 2017 6 27 44 pm

Can't build project with react-native-keyboard-input

I'm using RN 0.49.1
After installing and linking react-native-keyboard-input i can't build project. I've done all steps including the last one with proguard. First issue was
"error: method does not override or implement a method from a supertype"
and was fixed by deleting @OverRide in KeyboardInputPackage.java 43.
Then appeared another problem:
error: incompatible types: <anonymous ReactNativeHost> cannot be converted to Application
at the place i'm insert
new KeyboardInputPackage(this)

Are there any ways to fix it?

Crash in RN 0.53 iOS

'[<RCTTextView 0x7fa5b0c91a30> valueForUndefinedKey:]: this class is not key value coding-compliant for the key _backedTextInput.'
*** First throw call stack:

Errors with RN 0.46.*

I've tried to run demo app with react-native v0.46.2 and v0.46.3, but in both cases got an error:

/Users/mindaugasjacionis/Desktop/react-native-keyboard-input/node_modules/react-native-keyboard-tracking-view/lib/KeyboardTrackingViewManager.m:185:39: error: no visible @interface for 'RCTTextField' declares the selector 'setInputAccessoryView:'
            [((RCTTextField*)subview) setInputAccessoryView:[ObservingInputAccessoryView sharedInstance]];
             ~~~~~~~~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~

Any ideas for quick fix? :)

Touchables positioned absolutely outside KeyboardAccessoryView do not respond

Hi @artald ,

I want to make a keyboard-tracking "scroll to bottom" slideout like in WhatsApp (iOS).

I positioned the red slideout absolutely and it displays/ animates correctly. However the part of the slideout which is visually above the KeyboardAccessoryView (green box) does not respond to touches (it actually passes touches right through to the chat list view). The part of the touchable which is inside the KeyboardAccessoryView works fine.

simulator_screen_shot_apr_19__2017__4_50_36_pm

iOSScrollBehavior not working in certain cases

Hi,

I don't have a gist (yet) with a repro but we are experiencing cases where ScrollToBottomInvertedOnlyand FixedOffset iOSScrollBehavior fail. In these cases the keyboard acts like `BehaviorNone.

  • when I open a chat-room while the JS thread is very busy (simulator only)
  • when I open a chat-room through resetting my navigation experimental route stack instead of opening it by simply push a new route.

I know this is kind of a long shot but do you have any idea why this could be happening or can suggest what to investigate?

App Crashes when Backgrounded

Hey Guys,

Running into an issue with this crashing our app on some phones when the app is backgrounded.
calls getWindow(), which returns null, since it's backgrounded, causing a null pointer references, crashing the app.

FRAME	MODULE	CRASH DETAILS
0	com​.wix​.reactnativekeyboardinput	
ViewUtils.java ​ Line 15
ViewUtils.getWindow
1	com​.wix​.reactnativekeyboardinput	
ReactSoftKeyboardMonitor.java ​ Line 136
ReactSoftKeyboardMonitor.removeAllLayoutListeners
2	com​.wix​.reactnativekeyboardinput	
ReactSoftKeyboardMonitor.java ​ Line 98
ReactSoftKeyboardMonitor.onHostDestroy
3	com​.facebook​.react​.bridge	
ReactContext.java ​ Line 236
ReactContext.onHostDestroy
4	com​.facebook​.react	
ReactInstanceManager.java ​ Line 651
ReactInstanceManager.moveToBeforeCreateLifecycleState
5	com​.facebook​.react	
ReactInstanceManager.java ​ Line 575
ReactInstanceManager.onHostDestroy
6	com​.facebook​.react	
ReactInstanceManager.java ​ Line 588
ReactInstanceManager.onHostDestroy
7	com​.facebook​.react	
ReactActivityDelegate.java ​ Line 142
ReactActivityDelegate.onDestroy
8	com​.facebook​.react	
ReactActivity.java ​ Line 72
ReactActivity.onDestroy
9	android​.app	
Activity.java ​ Line 6471
Activity.performDestroy
10	android​.app	
Instrumentation.java ​ Line 1149
Instrumentation.callActivityOnDestroy
11	android​.app	
ActivityThread.java ​ Line 4063
ActivityThread.performDestroyActivity

image

Unwanted behavior on overscroll

Repro

  • open iOS demo App
  • go to custom keyboard "show1" or "show2"
  • over scroll down

Actual

  • keyboard resets and I loose my touch event on the the scrollview

Expected

  • behavior when doing the same repro case while the native keyboard is shown.

keyboardListeners are called multiple times

Hi again,

if I add keyboardListeners to the the demoApp like below, I can see that both are called 3 times. Does that also happen for you?

My problem is that I scroll a view based on the those events, so calling those scrolling function introduces some jankiness.

  componentWillMount() {

    const showEvent = IsIOS ? 'keyboardWillShow' : 'keyboardDidShow';
    const hideEvent = IsIOS ? 'keyboardWillHide' : 'keyboardDidHide';

    if (IsIOS) {
      this.keyboardEventListeners = [
        Keyboard.addListener(showEvent, () => console.log('keyboardWillShow')),
        Keyboard.addListener(hideEvent, () => console.log('keyboardWillHide')),
      ];
    } else {
      this.keyboardEventListeners = [
          Keyboard.addListener(showEvent, this.props.handleKeyboardOpen.bind(this)),
          Keyboard.addListener(hideEvent, this.props.handleKeyboardClose.bind(this)),
      ];
    }

  }

RN 0.38

Is it possible to show nothing? [QUESTION]

Is it possible to show nothing instead of a keyboard? (or an invisible one) and still listen for key down events? I am working on a rfid sensor, wondering if this could be useful as react-native-key-event doesn't seem to work.

Compatibility issue with Typescript?

I am using a Typescript in my project and I get the following issue. Requiring KeyboardAccessoryView and initializing it crashes my packager and writes this error to the terminal

[1] [4/5/2017, 10:39:52 AM] <START> Transforming files
[1] /Users/thorbenandresen/Documents/myProject/node_modules/babylon/lib/index.js:4336
[1]   throw err;
[1]   ^
[1]
[1] SyntaxError: 'import' and 'export' may appear only with 'sourceType: module' (1:0)

I don't know if this is an issue with this repo or an issue on my end.

Current workaround
Copy & paste the src folder from node_modules to my own source folder and import the files directly

Feature Request: isCustomKeyboardOpen

Hi Artal,

I am not sure if the current API already offers it, but I have use case for KeyboardUtils.isCustomKeyboardOpen() method.

Example:
I display the sticker keyboard on Android, which means the native keyboard is not shown. I would like the user to be able to press the Android Button in order to trigger a KeyboardUtils.dismiss(). If the keyboard/custom keyboards are hidden the Android back button should perform another action (pop a route).

My BackAndroid listener is on the root, so KeyboardUtils.isCustomKeyboardOpen() would be very handy. This way I could avoid adding the custom keyboard state to my global state object.

What do you think about this? Do you also think such a method would be useful?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.