Giter VIP home page Giter VIP logo

gre / react-native-view-shot Goto Github PK

View Code? Open in Web Editor NEW
2.6K 16.0 334.0 6.8 MB

Snapshot a React Native view and save it to an image

Home Page: https://github.com/gre/react-native-view-shot-example

License: MIT License

Java 35.11% JavaScript 39.88% Objective-C 6.57% C# 7.04% Ruby 1.34% Starlark 0.44% Makefile 1.12% C++ 5.14% Objective-C++ 2.69% EJS 0.40% TypeScript 0.27%
react-native snapshot capture

react-native-view-shot's Issues

Cannot take snapshot in real Device, but simulator is fine

Hi, I would like to capture my WebView. In the simulator, it works fine, and I can store it to any Dir. However, when I run the code using debug mode or release mode on my device, it always shows the same error. Could you please point out what's wrong here? Thanks.

Here is the error message:

2017-03-07 11:33:35.413 [info][tid:com.facebook.react.JavaScript] { [Error: Failed to capture view snapshot]
  line: 2813,
  column: 24,
  sourceURL: 'file:///var/containers/Bundle/Application/F030ED8C-8964-4991-91A6-6A5AFDFC23A5/Altizure.app/main.jsbundle',
  framesToPop: 1,
  code: 'EUNSPECIFIED',
  nativeStackIOS: 
   [ '0   Altizure                            0x00000001001e0634 RCTJSErrorFromCodeMessageAndNSError + 152',
     '1   Altizure                            0x000000010016a1b4 __41-[RCTModuleMethod processMethodSignature]_block_invoke_2.224 + 184',
     '2   Altizure                            0x00000001003a8b74 __54-[RNViewShot takeSnapshot:withOptions:resolve:reject:]_block_invoke + 988',
     '3   Altizure                            0x000000010021c78c __29-[RCTUIManager flushUIBlocks]_block_invoke + 660',
     '4   libdispatch.dylib                   0x00000001008d9258 _dispatch_call_block_and_release + 24',
     '5   libdispatch.dylib                   0x00000001008d9218 _dispatch_client_callout + 16',
     '6   libdispatch.dylib                   0x00000001008de280 _dispatch_main_queue_callback_4CF + 1200',
     '7   CoreFoundation                      0x000000018c2aa810 <redacted> + 12',
     '8   CoreFoundation                      0x000000018c2a83fc <redacted> + 1660',
     '9   CoreFoundation                      0x000000018c1d62b8 CFRunLoopRunSpecific + 444',
     '10  GraphicsServices                    0x000000018dc8a198 GSEventRunModal + 180',
     '11  UIKit                               0x000000019221d7fc <redacted> + 684',
     '12  UIKit                               0x0000000192218534 UIApplicationMain + 208',
     '13  Altizure                            0x00000001000fa144 main + 124',
     '14  libdyld.dylib                       0x000000018b1b95b8 <redacted> + 4' ],
  domain: 'RCTErrorDomain',
  userInfo: null }

Development environment:
Xcode 8.2.1
iOS 10.2
ReactNative 0.42

To reproduce:

async takeSnapshot() {
        try {
            this.snapshot = await takeSnapshot(this.modelContainer, {
                format: "jpeg",
                quality: 0.7,
                path: PictureDir + "/snapshot.jpeg"
            });
            console.log(this.snapshot);
        } catch (err) {
            console.log(err);
        }
    }
<View style={styles.viewer} ref={(ref) => { this.modelContainer = ref; }}>
     <WkWebView
          ref={(ref) => { this.webview = ref; }}
          startInLoadingState={true}
          renderLoading={this.renderLoading}
          source={require('./earth.html')}
          onMessage={(event) => this.shareSheet.earth(event.body, this.snapshot)}
          injectedJavaScript={jsCode}
          javaScriptEnabled={true}
    />
</View>
viewer: {
    flex: 1,
    zIndex: -1,
    backgroundColor: '#232323'
}

Requiring unknown module "/data/data/..." on Android

I can't seem to Image.getSize nor require() the saved image on Android. Works fine on iOS.

takeSnapshot(this.refs.content, {
    format: 'jpeg',
    quality: 0.8,
})
.then((response) => {
    Image.getSize(response, (width, height) => {
        this.setState({
            modalBackdropProps: {
                imageSize: {
                    height,
                    width,
                },
                source: {
                    uri: response,
                },
            },
        });
    });
});

The image path is: /data/data/<packageName>/cache/ReactNative_snapshot_image_<timestamp>.jpeg.

For Image.getSize I get: "Error: Unsupported uri scheme!"

Image real path to save it to camera roll

I was tried the example code and i got a uri like this:
file:///data/user/0/com.last/cache/ReactNative-snapshot-image1446502249.png

Is there any way to change the uri into the real path? just like:
"/storage/emulated/0/Pictures/ReactNative-snapshot-image799473449.png"

so i could use the path for the CameraRoll library from react native like:
CameraRoll.saveToCameraRoll(path,'photo')

Thanks and please help hehe

[Question] On ScrollView, how to take picture all of it, not only visible part?

Hi, I have a long page which user have to scroll down to read all of it. This page is something user want to share on social media, so I need to take a shot whole scrollview content.
So, I've tried to use this package to take the image but it only returns what's visible on screen at the moment, I've also tried snapshotContentContainer option but no luck so far.

Render off screen area

Hi,

is it possible to capture a whole View, even the parts that are not yet on screen (like in a scrollview)?
Or even better: capture a View that has not yet been given to the render method?
e.g.

createView(){ 
		return <View>
			<Text>Hello World</Text>
		</View>
	}
...
RNViewShot.takeSnapshot(this.createView(), {
					 format: 'png',
					result: 'file',
					 });

Is this planned, and would this at all be possible with the current architecture?
Best, Tim

WebView charts captures blank

webview source require this html,captures blank, in the react-native-view-shot-example project @gre

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>ECharts</title>
  <!-- 引入 echarts.js -->
  <script src="http://cdn.bootcss.com/echarts/3.4.0/echarts.min.js"></script>
</head>

<body>
  <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
  <div id="main" style="width: 600px;height:400px;"></div>
  <script type="text/javascript">
    // 基于准备好的dom,初始化echarts实例
    var myChart = echarts.init(document.getElementById('main'));

    // 指定图表的配置项和数据
    var symbolSize = 20;
    var data = [[15, 0], [-50, 10], [-56.5, 20], [-46.5, 30], [-22.1, 40]];
    var points = [];

    option = {
      title: {
        text: 'Click to Add Points'
      },
      tooltip: {
        formatter: function (params) {
          var data = params.data || [0, 0];
          return data[0].toFixed(2) + ', ' + data[1].toFixed(2);
        }
      },
      grid: {
        left: '3%',
        right: '4%',
        bottom: '3%',
        containLabel: true
      },
      xAxis: {
        min: -60,
        max: 20,
        type: 'value',
        axisLine: { onZero: false }
      },
      yAxis: {
        min: 0,
        max: 40,
        type: 'value',
        axisLine: { onZero: false }
      },
      series: [
        {
          id: 'a',
          type: 'line',
          smooth: true,
          symbolSize: symbolSize,
          data: data
        }
      ]
    };

    // 使用刚指定的配置项和数据显示图表。
    myChart.setOption(option);
  </script>
</body>

</html>

error save: ReferenceError: file is not defined?

I did your example but it always throw the error

error save:  ReferenceError: file is not defined
    at http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:78636:31
    at tryCallOne (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:32137:8)
    at http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:32223:9
    at http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:5651:49
    at Object.callTimer (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:4156:1)
    at Object.callImmediatesPass (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:4260:19)
    at Object.callImmediates (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:4275:25)
    at http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:3962:43
    at guard (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:3794:1)
    at MessageQueue.__callImmediates (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:3962:1)

My code

  snapshot = refname => () => {
    console.log(refname)
      RNViewShot.takeSnapshot(this.refs[refname], {format: "jpeg", quality: 0.8, result: "file"})
          .then(
              uri => {
                  console.log("Image saved to ", file);
              }
          )
          .catch(error => console.log('error save: ', error));
  }

Exporting airbnb/react-native-map results in blank image

Hello first of all great package 😄 .

This is more a question than an issue, but trying to export a MapView from https://github.com/airbnb/react-native-maps the map itself is a blank. Do you have any idea on why this could be happening?. Could it be that is probably a native element so this exporter does not know how to render something that is not a react-native rendered element? (I imagine i can be completely wrong on my self-explanation on why it does not work)

(Android) Trying to resolve view with tag which doesn't exist

I'm getting this issue if my view reference did not specify a backgroundColor.

so the code works fine if I take a Snapshot with the below viewRef

<View   
  style={{backgroundColor: 'yellow'}}   
  ref={ref => viewRefSuccess = ref}>   
  <Text>   
    Hello View Snap Shot   
  </Text>   
</View>   

However it will crash with the "Trying to resolve view with tag 'tagID' which doesn't exist"
if I remove the backgroundColor props.

<View ref={ref => viewRefSuccess = ref}>   
  <Text>   
    Hello View Snap Shot   
  </Text>   
</View>   

Any thought on why this is happening?

Thanks.

available for surfaceview screenshot ?

My app use surfaceview to display the video,and I want to take a screenshot to share to other people when i play the video, i have tried many ways,but did'n work,what i got is black screen, so I want to ask this program can be used to take a screenshot of surfaceview ? Any advice will be appreciated.

React Native Version

Im on RN 0.27.2 and I got it working just great with IOS, However android fails with import com.facebook.react.uimanager.UIBlock; and anything that uses the UIBlock, Does android only work with versions of react-native that are react-native@>=0.30.0?

Can't get Image to show

This is what i get when running my script:
"file:///data/user/0/com.coach/cache/ReactNative-snapshot-image1317300113.png"

When i put it like this:
<Image source={{uri: uriAbove }} />
it shows nothing.

When i put it like this:
<Image source={require(uriAbove)} />
react-native crashes with error:
Unknown named module: 'file:///data/user/0/com.coach/cache/ReactNative-snapshot-image1317300113.png'

Any idea what I can do about it?

Captured view not seen any more

Hi,

I successfully capture the view as png/jpeg in react-native in Android.

I captured the view as file and saved for later use. The view contain image and text. But the original view in the screen disappeared (become empty in the screen) after captured the view.

I want to display the same view (not captured image) even after captured the image. Any way to achieve this ? Please advise ASAP.

Please find attached the before view and after captured view (empty).

error-before
error-after

Blur image

The shot image is blur, even though I set the quality to 1.0.
Is there anyway to get a high quality or clear image?

Refview question

Can anyone give me an example of how to implement the Refview?
I just put view there, and it throws an error 'ExceptionsManager.js:71 Unhandled JS Exception: findNodeHandle(...): Argument is not a component (type: function, keys: displayName,AccessibilityTraits,AccessibilityComponentType,forceTouchAvailable,propTypes)'

Many thanks,
Ian

Getting errors with 1.6.0 after upgrading to RN 0.40 🙏 😢

So I upgraded to RN 0.40 and everything broke. So now I'm trying to go through each library I used and hopefully get it working again.

I upgraded to 1.6.0 and can't get the project to build, with errors like:
image

/MY_APP_LOCATION/node_modules/react-native-view-shot/ios/RNViewShot.m:31:16: Property 'uiManager' cannot be found in forward class object 'RCTBridge'

I npm install the 1.6.0 and react-native unlink react-native-view-shoted then react-native link react-native-view-shoted and cleaned project in xCode but still not compiling. One of the errors is coming from this library as shown in the image above.

Any ideas on how to fix this please 🙏?

could i ask ,how to specifyc img base dir

if i want to specifyc img to path "file:///storage/emulated/0/Tencent/MicroMsg/WeiXin",
i tryed to write like
`path:"file:///storage/emulated/0/Tencent/MicroMsg/WeiXin/qr.png" but failed ,

persistent storage...

instead of writing into tmp file,,why don't store image into persistent storage such as Documents directory..?? after that image can be accessed with ~/Documents/filename...

Take snapshot, when Component is ready

Part of my snapshot is an Image, which is fading in, when the image is loaded and displayed the first time. When I take a snapshot, while the image is still not completely displayed, I get a grayed out image.

Is there a way to trigger the snapshot, when the View is ready and rendered completely?

What I am currently doing is trigger the snapshot with onLayout of the outer View and a relatively long timer, that waits another second, before the snapshot is taken. But that is making my app less responsive and sometimes the image is still not there, when the snapshot fires. I tried onLoad and onLayout of the Image, but those did not work any better.

Any Idea?

Thanks, Tim

Image Resolution Doubled?

When I load an image into a view and then use react-native-view-shot to create an image from that view the resolution seems to be doubled.

I don't think I'm doing anything weird...

Here is the function I'm using to take the image:

        console.log('taking picture of size: ', width, height);
        RNViewShot.takeSnapshot(this.refs['layout'], {
            format: 'png',
            quality: 0.8,
            width,
            height
        })
        .then(
            uri => {
                console.log('Image saved to', uri);
                Image.getSize(uri, (width, height) => {
                    console.log(`Image dimensions: ${width}x${height}`);
                });
            },
            error => console.error('Oops, snapshot failed', error)
        );
    }

And the output:

[PERF ASSETS] Loading image at size {3600, 3600}, which is larger than the screen size {750, 1334}
index.ios.js:21 taking picture of size:  3600 3600
index.ios.js:30 Image saved to /Users/chris/Library/Developer/CoreSimulator/Devices/A0EC9E9C-B184-46B8-80BE-DCCA88E4C699/data/Containers/Data/Application/2552626F-31AC-4F3D-86BF-12EFCC163100/tmp/ReactNative/DB9581E0-E465-460C-A3E9-FC904218C47E.png
index.ios.js:32 Image dimensions: 7200x7200

Rejecting while taking snapshot of "zero height" view

I got following error/rejection:

2016-11-12 13:43:43.339 [info][tid:com.facebook.react.JavaScript] 'Taking snapshot', true
Nov 12 13:43:43  rnSnapshooter[96767] <Error>: CGContextSaveGState: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
Nov 12 13:43:43  rnSnapshooter[96767] <Error>: CGContextRestoreGState: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
2016-11-12 13:43:43.380 [error][tid:com.facebook.react.JavaScript] 'Oops, snapshot failed', { [Error: Failed to capture view snapshot]
  line: 3548,
  column: 20,
  sourceURL: 'http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false',
  framesToPop: 1,
  code: 'EUNSPECIFIED',
  nativeStackIOS: 
   [ '0   rnSnapshooter                       0x000000010a054ea6 RCTJSErrorFromCodeMessageAndNSError + 134',
     '1   rnSnapshooter                       0x0000000109fd4aa3 __41-[RCTModuleMethod processMethodSignature]_block_invoke_2.224 + 147',
     '2   rnSnapshooter                       0x000000010a0fb899 __54-[RNViewShot takeSnapshot:withOptions:resolve:reject:]_block_invoke + 1161',
     '3   rnSnapshooter                       0x000000010a08f4d8 __29-[RCTUIManager flushUIBlocks]_block_invoke + 792',
     '4   libdispatch.dylib                   0x000000010e57fe5d _dispatch_call_block_and_release + 12',
     '5   libdispatch.dylib                   0x000000010e5a049b _dispatch_client_callout + 8',
     '6   libdispatch.dylib                   0x000000010e5882af _dispatch_main_queue_callback_4CF + 1738',
     '7   CoreFoundation                      0x000000010b59bd09 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9',
     '8   CoreFoundation                      0x000000010b55d2c9 __CFRunLoopRun + 2073',
     '9   CoreFoundation                      0x000000010b55c828 CFRunLoopRunSpecific + 488',
     '10  GraphicsServices                    0x000000011003cad2 GSEventRunModal + 161',
     '11  UIKit                               0x000000010cf59610 UIApplicationMain + 171',
     '12  rnSnapshooter                       0x0000000109fac8bf main + 111',
     '13  libdyld.dylib                       0x000000010e5d492d start + 1' ],
  domain: 'RCTErrorDomain',
  userInfo: null }

with following view to snapshot:

      <View ref="root" style={{backgroundColor: 'yellow'}}>
        <DemoApp/>
      </View>

everything works with style={{flex:1,backgroundColor: 'yellow'}}. Without the flex I can see DemoApp but I don't see yellow background.

Feel free to close this issue if you don't want to handle such cases. Just wanted to document somewhere my troubles and how to "workaround" them if anyone would come to this problem.

Detect snap

Is there a any way for detect user manual snapshot ?

save as base64 throw error

when i save image as base64, throw a error, and set result to 'data-uri' is same.

RN version: 0.36.1.

code:
RNViewShot.takeSnapshot(this.ref, { format: "png", quality: 0.8, result: 'base64', })

error:

'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]'
*** First throw call stack:
(
0 CoreFoundation 0x0000000106df8d85 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010642bdeb objc_exception_throw + 48
2 CoreFoundation 0x0000000106cb1a52 -[__NSPlaceholderArray initWithObjects:count:] + 290
3 CoreFoundation 0x0000000106d0e0b4 +[NSArray arrayWithObjects:count:] + 52
4 mofang_app 0x0000000102908edf -[RCTPhotoLibraryImageLoader loadImageForURL:size:scale:resizeMode:progressHandler:partialLoadHandler:completionHandler:] + 447
5 mofang_app 0x0000000102a155d3 __118-[RCTImageLoader _loadImageOrDataWithURLRequest:size:scale:resizeMode:progressBlock:partialLoadBlock:completionBlock:]_block_invoke.191 + 355
6 libdispatch.dylib 0x0000000107edbd9d _dispatch_call_block_and_release + 12
7 libdispatch.dylib 0x0000000107efc3eb _dispatch_client_callout + 8
8 libdispatch.dylib 0x0000000107ee282c _dispatch_queue_drain + 2215
9 libdispatch.dylib 0x0000000107ee1d4d _dispatch_queue_invoke + 601
10 libdispatch.dylib 0x0000000107ee4996 _dispatch_root_queue_drain + 1420
11 libdispatch.dylib 0x0000000107ee4405 _dispatch_worker_thread3 + 111
12 libsystem_pthread.dylib 0x00000001082394de _pthread_wqthread + 1129
13 libsystem_pthread.dylib 0x0000000108237341 start_wqthread + 13
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)

Support for ReactNativeART?

Hi,
Thanks for this good plugin.

Is there any way for this plugin to support the ReactNativeART library? Or do you have any plans to add this feature?

I would love to use it with a components like Surface, Shape, Path from ReactNativeART.

Thanks for advance.

Cannot read property 'takeSnapshot' of undefined

Hey so I'm having this issue. I can't seem to figure out if this is something that I'm doing wrong or an actual issue with the package. Please help!
simulator screen shot sep 29 2016 6 00 06 pm

The code:

snapshot = view => () => takeSnapshot(this.refs[view], { format: "jpeg", quality: 0.8 }) .then( uri => console.log("Image saved to", uri), error => console.error("Oops, snapshot failed", error) )

and

<View ref = "main"> <Button rounded danger style = {{ width: 55, height: 55 }} onPress = {this.snapshot("main")} > test </Button> </View>

Introduce a `<Snapshotable>` to make it easier ?

just the reason we (most of the time!) needs to do collapsable={false} on Android, and sometimes even needs to wrap a parent <View collapsable={false}> (e.g. WebView) makes me think maybe we should hide that from the lib user ( note https://github.com/gre/react-native-view-shot#specific-to-android-implementation ).

Maybe the library should (only?) be available through a wrapper Component.

<Snapshotable ref="snap"> ... </Snapshotable>

snap.capture().then(...

WDYT?

one downside is introducing a <View> wrapping changes the hierarchy.

A few Questions

Hi there, first thing thanks very much for your hard work on this project :)

I would like to know if there is a way to take a snapshot without passing the ref, and i'm asking this because to get the ref (correct me if i'm wrong) you need to render the element, and that's my problem, i have to create images of about 80 views. as you understand this is a performance killer.

If you believe it's possible to make this in some way.
i'm very interesting to know your toughs's on this one.

in the native code side i was think something like this:
Pass to bridge Component and props-->In the Native side call react-native method to create the View in the background--> create a image of the view --> return path

All this procedure made with multi threading support.

Attention, i never create a native module for react-native, it's probably that i said something stupid above.

This issue is to know if Its possible to do, if you can do it, and if you can't , if you could assist me to do it.

Error: findNodeHandle failed to resolve view=undefined

Hi
I integrated rnvs few weeks back and it was working perfectly then. Suddenly I am seeing error whenever I am trying to capture screenshot.
Here is my code for taking screenshot.

takeScreenShot(){
    RNViewShot.takeSnapshot(this.refs.screenshot, {
      format: "jpeg",
      quality: 0.8
    })
    .then(
      uri => this.saveScreenshot(uri),
      error => console.error("Oops, snapshot failed", error)
    );
  }

This is the error I am getting whenever calling takeScreenShot function.

2016-12-06 14:34:22.635 [error][tid:com.facebook.react.JavaScript] 'Oops, snapshot failed', { [Error: findNodeHandle failed to resolve view=undefined]
line: 525,
column: 133,
sourceURL: 'file:///Users/ABC/Library/Developer/CoreSimulator/Devices/17A973BC-5639-4C55-B52E-D7FE972F2651/data/Containers/Bundle/Application/87DDE253-950F-4BB2-8F4C-C8C468862DD2/MYAPP.app/main.jsbundle' }

[Android] Sharing the generated image with a share intent

Hi, maybe this is more a general purpose Android question, but I thought perhaps you could help. Since the uri that is generated for a snapshot only exists in the app cache, passing its uri to a share intent always fails. As soon as I change it to a file saved on external storage, it works. Obviously I'd like to avoid doing this, so I'm looking for other ways to achieve this. More than willing to submit a PR. Thanks!

EDIT: My proposal would be an option like {saveToDisk: true} being passed in which would cause the module to call something like createPermanentFile instead of createTempFile, but my native Android fu is limited, so there's probably a better way.

Custom width height of snapshot

How can I custom size of Image file after take snapshot? I tested on iPhone 6 simulator, file result only have 750px width.

Example: I wanna result file have 2048x2048 px.

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.