├── .babelrc ├── .eslintrc ├── .gitignore ├── README.md ├── app ├── GUI │ ├── TextComponent │ │ ├── textComponent.js │ │ ├── textContainer.js │ │ └── wrappedComponent.js │ ├── filter │ │ ├── filterComponent.js │ │ └── filterContainer.js │ ├── mainComponent.js │ ├── mainContainer.js │ ├── test.js │ └── viz │ │ ├── helpers │ │ └── prepVizData.js │ │ ├── nameLengthComponent.js │ │ ├── nameLengthContainer.js │ │ ├── perLetterComponent.js │ │ └── perLetterContainer.js ├── actions │ ├── FilterActions.js │ └── RawActions.js ├── constants │ └── ActionTypes.js ├── main.js └── reducers │ ├── coreReducer.js │ ├── helpers │ └── filterData.js │ └── index.js ├── build ├── data │ ├── 20151001_hundenamen.csv │ └── 20151001_hundenamen.json └── index.html ├── dist ├── 448c34a56d699c29117adc64c43affeb.woff2 ├── 89889688147bd7575d6327160d64e760.svg ├── app.js ├── data │ ├── 20151001_hundenamen.csv │ └── 20151001_hundenamen.json ├── e18bbf611f2a2e43afc071aa2f4e1512.ttf ├── f4769f9bdb7466be65088239c12046d1.eot ├── fa2772327f55d8198301fdb8bcfc8158.woff └── index.html ├── package.json ├── server.js ├── webpack.config_HOT.js └── webpack.config_PROD.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2", "react"] 3 | } 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | //"indent": [2, 2, {"SwitchCase": 1}], 5 | "indent": [0], 6 | "id-length": [0], 7 | "new-cap": [2, {"capIsNewExceptions": ["Arc"]}], 8 | "react/no-multi-comp": [0] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # -------------------- 2 | # OSX Files 3 | # -------------------- 4 | .DS_Store 5 | .AppleDouble 6 | .LSOverride 7 | Icon 8 | ._* 9 | .Spotlight-V100 10 | .Trashes 11 | 12 | # -------------------- 13 | # IntelliJ Files 14 | # -------------------- 15 | *.iml 16 | *.ipr 17 | *.iws 18 | .idea/ 19 | 20 | # -------------------- 21 | # Netbeans Files 22 | # -------------------- 23 | nbproject/private/ 24 | #build/ 25 | nbbuild/ 26 | #dist/ 27 | nbdist/ 28 | nbactions.xml 29 | nb-configuration.xml 30 | 31 | # -------------------- 32 | # Node Files 33 | # -------------------- 34 | .nodemonignore 35 | npm-debug.log 36 | node_modules/ 37 | 38 | # -------------------- 39 | # SASS Files 40 | # -------------------- 41 | .sass-cache/ 42 | 43 | # -------------------- 44 | # Bower Files 45 | # -------------------- 46 | .bower-*/ 47 | bower_components 48 | 49 | # -------------------- 50 | # Build Files 51 | # -------------------- 52 | #build/* 53 | #!build/index.html 54 | #!assets/img 55 | 56 | # -------------------- 57 | # Public Files 58 | # -------------------- 59 | #dist/* 60 | 61 | # -------------------- 62 | # Other 63 | # -------------------- 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # d3-react-squared-dogs-blog 2 | [LIVE EXAMPLE](http://bgrsquared.com/dogs/) 3 | 4 | An example how to use [d3-react-squared](https://github.com/bgrsquared/d3-react-squared) (using Dog-Names-Data in Zurich) 5 | 6 | This is just an example on how you **could** use [d3-react-squared](https://github.com/bgrsquared/d3-react-squared), it doesn't make really much sense in terms of graphs... 7 | 8 | See also the [blog post on medium](https://medium.com/@ilikepiecharts/about-using-d3-react-squared-an-example-8cc5e5a6b58e#.3pizom3ax) 9 | 10 | [Data Source](https://data.stadt-zuerich.ch/dataset/pd-stapo-hundenamen/resource/11207c68-fc9f-4883-a2ef-3b4a60dd048a) 11 | [(under CC-Zero)](http://www.opendefinition.org/licenses/cc-zero) 12 | -------------------------------------------------------------------------------- /app/GUI/TextComponent/textComponent.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | 3 | import DR2 from 'd3-react-squared'; 4 | import WrappedComponent from './wrappedComponent'; 5 | 6 | export default class TextComponent extends Component { 7 | render() { 8 | return (); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/GUI/TextComponent/textContainer.js: -------------------------------------------------------------------------------- 1 | import { bindActionCreators } from 'redux'; 2 | import { connect } from 'react-redux'; 3 | import * as FilterActions from '../../actions/FilterActions'; 4 | 5 | import TextComponent from './textComponent'; 6 | 7 | function mapStateToProps(state) { 8 | return { 9 | dogData: state.dogData, 10 | }; 11 | } 12 | 13 | function mapDispatchToProps(dispatch) { 14 | const allActions = Object.assign({}, 15 | bindActionCreators(FilterActions, dispatch), {dispatch}); 16 | return allActions; 17 | } 18 | 19 | export default connect(mapStateToProps, 20 | mapDispatchToProps)(TextComponent); 21 | -------------------------------------------------------------------------------- /app/GUI/TextComponent/wrappedComponent.js: -------------------------------------------------------------------------------- 1 | import React, {Component, PropTypes} from 'react'; 2 | 3 | export default class WrappedText extends Component { 4 | sendEvent(id, grp, event) { 5 | const {setEvent} = this.props; 6 | const eventObj = { 7 | data: {id}, 8 | event, 9 | eventGroup: grp, 10 | }; 11 | setEvent(eventObj); 12 | } 13 | 14 | render() { 15 | const {dogData, eventData, setFilter} = this.props; 16 | const {filtered, raw} = dogData; 17 | const {timeStamp} = eventData; 18 | const ratio = (filtered.length / raw.length) || 0; 19 | 20 | let eventText; 21 | if (timeStamp) { 22 | eventText = 'The last event was called ' + eventData.event + 23 | ' on eventGroup "' + eventData.eventGroup.join(', ') + '"' + 24 | ' and happened on ' + (new Date(timeStamp)); 25 | } else { 26 | eventText = 'So far, no event happened. Nothing noteworthy...'; 27 | } 28 | 29 | 30 | return ( 31 |
32 |

Here's a wrapped component

33 |
Using redux data
34 | So, we are currently looking at {filtered.length} dogs (after filtering)... 35 |
36 | Let's add an interactive svg here, without d3: 37 | 38 | 44 | 50 | 51 | {Math.round(filtered.length / raw.length * 10000) / 100 + '% of all dogs (filtering)'} 52 | 53 | 54 |
Sending events from text...
55 | Names starting with{' '} 56 | {this.sendEvent('L', ['perLetter'], 'mouseover');}} 59 | onMouseOut={()=>{this.sendEvent('', ['perLetter'], 'mouseout');}} 60 | > 61 | L (mouseover here) 62 | 63 | ... bla bla ... or{' '} 64 | {this.sendEvent('0-5', ['nameLength'], 'mouseover');}} 67 | onMouseOut={()=>{this.sendEvent('', ['nameLength'], 'mouseout');}} 68 | > 69 | short names (mouseover here) 70 | 71 |
Or send redux actions from text
72 | So{' '} 73 | {setFilter({sex: new Set(['w'])});}} 76 | > 77 | female dogs (filter on mouseover!) 78 | 79 | ... blah blah ...{' '} 80 | {setFilter({sex: new Set(['m'])});}} 83 | > 84 | male dogs (filter on mouseover!) 85 | 86 | ... blah blah ...{' '} 87 | {setFilter({sex: new Set(['m', 'w'])});}} 90 | > 91 | both sexes (filter on mouseover!) 92 | 93 |
Using eventData from d3-react-squared
94 | {eventText} 95 |
96 | ); 97 | } 98 | } 99 | 100 | WrappedText.propTypes = { 101 | dogData: PropTypes.object.isRequired, 102 | eventData: PropTypes.object.isRequired, 103 | setEvent: PropTypes.func.isRequired, 104 | setFilter: PropTypes.func.isRequired, 105 | }; 106 | -------------------------------------------------------------------------------- /app/GUI/filter/filterComponent.js: -------------------------------------------------------------------------------- 1 | import React, {Component, PropTypes} from 'react'; 2 | 3 | import {Button, ButtonGroup} from 'react-bootstrap'; 4 | 5 | export default class FilterComponent extends Component { 6 | constructor() { 7 | super(); 8 | this.state = { 9 | showFilter: true, 10 | }; 11 | } 12 | 13 | onFilter(obj) { 14 | const {setFilter} = this.props; 15 | setFilter(obj); 16 | } 17 | 18 | render() { 19 | const {dogData} = this.props; 20 | const {showFilter} = this.state; 21 | const {sex, nameLengthMax, nameLengthMin} = dogData; 22 | 23 | const nameLengthMaxButtons = []; 24 | const nameLengthsMax = [3, 5, 10, 20, Infinity]; 25 | nameLengthsMax.map(n => { 26 | nameLengthMaxButtons.push( 27 | ); 34 | }); 35 | 36 | const nameLengthMinButtons = []; 37 | const nameLengthsMin = [0, 3, 5, 10, 20]; 38 | nameLengthsMin.map(n => { 39 | nameLengthMinButtons.push( 40 | ); 47 | }); 48 | 49 | const filterControls = (
50 |

Sex

51 | 52 | 57 | 62 | 67 | 68 |

Length of Dog's name

69 | 70 | 75 | 80 | 85 | 86 | 87 |
Minimal number of letters
88 | 89 | {nameLengthMinButtons} 90 | 91 |
Maximal number of letters
92 | 93 | {nameLengthMaxButtons} 94 | 95 |
); 96 | 97 | return ( 98 |
99 |

Filter{' '} 100 | 105 |

106 | {showFilter ? filterControls : ''} 107 |
); 108 | } 109 | } 110 | 111 | FilterComponent.propTypes = { 112 | dogData: PropTypes.object.isRequired, 113 | setFilter: PropTypes.func.isRequired, 114 | }; 115 | -------------------------------------------------------------------------------- /app/GUI/filter/filterContainer.js: -------------------------------------------------------------------------------- 1 | import { bindActionCreators } from 'redux'; 2 | import { connect } from 'react-redux'; 3 | import * as FilterActions from '../../actions/FilterActions'; 4 | 5 | import FilterComponent from './filterComponent'; 6 | 7 | function mapStateToProps(state) { 8 | return { 9 | dogData: state.dogData, 10 | }; 11 | } 12 | 13 | function mapDispatchToProps(dispatch) { 14 | const allActions = Object.assign({}, 15 | bindActionCreators(FilterActions, dispatch), {dispatch}); 16 | return allActions; 17 | } 18 | 19 | export default connect(mapStateToProps, 20 | mapDispatchToProps)(FilterComponent); 21 | -------------------------------------------------------------------------------- /app/GUI/mainComponent.js: -------------------------------------------------------------------------------- 1 | /* global ga */ 2 | 3 | import React, {Component, PropTypes} from 'react'; 4 | 5 | import {Grid, Well, Col, Row} from 'react-bootstrap'; 6 | 7 | import PerLetter from './viz/perLetterContainer'; 8 | import NameLength from './viz/nameLengthContainer'; 9 | import Filter from './filter/filterContainer'; 10 | import TextComponent from './TextComponent/textContainer'; 11 | 12 | export default class mainComponent extends Component { 13 | componentDidMount() { 14 | if (document.location.hostname !== 'localhost') { 15 | ga('send', 'pageview', '/dogs'); 16 | } 17 | const {getRaw, dispatch} = this.props; 18 | getRaw()(dispatch); 19 | } 20 | 21 | render() { 22 | return ( 23 |

Dog Names in Zurich - a showcase

24 |

a.k.a. why do we need d3-react-squared?

25 | Source: Open Data Zurich 29 | {' '} 30 | (under CC-Zero) 31 | 32 | 33 | 34 |

Note/Disclaimer:

35 | This page is to demonstrate a use-case 36 | for d3-react-squared. 38 |
39 | 55 | The graphs are just examples and by no means useful regarding the information presented 56 | (or the way it is presented). 57 | d3-react squared was designed to link charts, information, events. 58 |
59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 |
); 78 | } 79 | } 80 | 81 | mainComponent.propTypes = { 82 | dispatch: PropTypes.func.isRequired, 83 | dogData: PropTypes.object.isRequired, 84 | getRaw: PropTypes.func.isRequired, 85 | }; 86 | -------------------------------------------------------------------------------- /app/GUI/mainContainer.js: -------------------------------------------------------------------------------- 1 | import { bindActionCreators } from 'redux'; 2 | import { connect } from 'react-redux'; 3 | import * as RawActions from '../actions/RawActions'; 4 | 5 | import MainComponent from './mainComponent'; 6 | 7 | function mapStateToProps(state) { 8 | return { 9 | dogData: state.dogData, 10 | }; 11 | } 12 | 13 | function mapDispatchToProps(dispatch) { 14 | const allActions = Object.assign({}, 15 | bindActionCreators(RawActions, dispatch), {dispatch}); 16 | return allActions; 17 | } 18 | 19 | export default connect(mapStateToProps, 20 | mapDispatchToProps)(MainComponent); 21 | -------------------------------------------------------------------------------- /app/GUI/test.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | 3 | export default class Text extends Component { 4 | render() { 5 | return (
HUIIII
); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/GUI/viz/helpers/prepVizData.js: -------------------------------------------------------------------------------- 1 | export function prepPerLetter(data) { 2 | const myData = []; 3 | const loopData = new Map; 4 | 5 | data.map(d => { 6 | let letter = d[0].substr(0, 1).toUpperCase(); 7 | if (!letter.match(/[A-Z]/i)) { 8 | letter = '-'; 9 | } 10 | if (loopData.has(letter)) { 11 | const n = loopData.get(letter); 12 | loopData.set(letter, n + 1); 13 | } else { 14 | loopData.set(letter, 1); 15 | } 16 | }); 17 | loopData.forEach((v, k) => { 18 | myData.push({ 19 | id: k, 20 | value: v, 21 | }); 22 | }); 23 | return myData; 24 | } 25 | 26 | export function prepNameLength(data) { 27 | const myData = []; 28 | const loopData = new Map([ 29 | ['0-5', 0], 30 | ['6-10', 0], 31 | ['11-20', 0], 32 | ['21+', 0], 33 | ]); 34 | let lbl = '21+'; 35 | 36 | data.map(d=> { 37 | const l = d[0].length; 38 | if (l < 6) { 39 | lbl = '0-5'; 40 | } else if (l < 11) { 41 | lbl = '6-10'; 42 | } else if (l < 21) { 43 | lbl = '11-20'; 44 | } 45 | const v = loopData.get(lbl); 46 | loopData.set(lbl, v + 1); 47 | }); 48 | loopData.forEach((v, k) => { 49 | myData.push({ 50 | id: k, 51 | value: v, 52 | }); 53 | }); 54 | return myData; 55 | } 56 | -------------------------------------------------------------------------------- /app/GUI/viz/nameLengthComponent.js: -------------------------------------------------------------------------------- 1 | import React, {Component, PropTypes} from 'react'; 2 | 3 | import {Grid, Col} from 'react-bootstrap'; 4 | 5 | import {prepNameLength} from './helpers/prepVizData'; 6 | import DR2 from 'd3-react-squared'; 7 | 8 | export default class NameLength extends Component { 9 | render() { 10 | const {dogData} = this.props; 11 | const {raw, filtered} = dogData; 12 | 13 | const myDataRaw = prepNameLength(raw); 14 | const myDataFiltered = prepNameLength(filtered); 15 | 16 | return ( 17 | 18 |

Dog names by Length

19 | 20 |

All Dogs

21 | 29 | 30 | 31 |

Filtered Data

32 | 40 | 41 |
42 | ); 43 | } 44 | } 45 | 46 | NameLength.propTypes = { 47 | dogData: PropTypes.object.isRequired, 48 | }; 49 | -------------------------------------------------------------------------------- /app/GUI/viz/nameLengthContainer.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux'; 2 | 3 | import NameLength from './nameLengthComponent'; 4 | 5 | function mapStateToProps(state) { 6 | return { 7 | dogData: state.dogData, 8 | }; 9 | } 10 | 11 | function mapDispatchToProps() { 12 | const allActions = {}; 13 | return allActions; 14 | } 15 | 16 | export default connect(mapStateToProps, 17 | mapDispatchToProps)(NameLength); 18 | -------------------------------------------------------------------------------- /app/GUI/viz/perLetterComponent.js: -------------------------------------------------------------------------------- 1 | import React, {Component, PropTypes} from 'react'; 2 | 3 | import {Grid, Col} from 'react-bootstrap'; 4 | 5 | import {prepPerLetter} from './helpers/prepVizData'; 6 | import DR2 from 'd3-react-squared'; 7 | 8 | export default class PerLetter extends Component { 9 | render() { 10 | const {dogData} = this.props; 11 | const {raw, filtered} = dogData; 12 | 13 | const myDataRaw = prepPerLetter(raw); 14 | const myDataFiltered = prepPerLetter(filtered); 15 | 16 | return ( 17 | 18 |

Dog names by Letter

19 | 20 |

All Dogs

21 | 29 | 30 | 31 |

Filtered Data

32 | 40 | 41 |
42 | ); 43 | } 44 | } 45 | 46 | PerLetter.propTypes = { 47 | dogData: PropTypes.object.isRequired, 48 | }; 49 | -------------------------------------------------------------------------------- /app/GUI/viz/perLetterContainer.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux'; 2 | 3 | import PerLetter from './perLetterComponent'; 4 | 5 | function mapStateToProps(state) { 6 | return { 7 | dogData: state.dogData, 8 | }; 9 | } 10 | 11 | function mapDispatchToProps() { 12 | const allActions = {}; 13 | return allActions; 14 | } 15 | 16 | export default connect(mapStateToProps, 17 | mapDispatchToProps)(PerLetter); 18 | -------------------------------------------------------------------------------- /app/actions/FilterActions.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/ActionTypes'; 2 | 3 | export function setFilter(filterAction) { 4 | // action: add, remove, overwrite? 5 | return { 6 | type: types.SET_FILTER, 7 | filterAction, 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /app/actions/RawActions.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/ActionTypes'; 2 | 3 | import fetch from 'isomorphic-fetch'; 4 | 5 | const rawData = './data/20151001_hundenamen.json'; 6 | 7 | export function setRaw(raw) { 8 | return { 9 | type: types.SET_RAW, 10 | raw, 11 | }; 12 | } 13 | 14 | export function getRaw() { 15 | return dispatch => { 16 | return fetch(rawData) 17 | .then(response => response.json()) 18 | .then(json => { 19 | return dispatch(setRaw(json)); 20 | }); 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /app/constants/ActionTypes.js: -------------------------------------------------------------------------------- 1 | // COORDINATE HIGHLIGHTS 2 | export const SET_RAW = 'SET_RAW'; 3 | export const SET_FILTER = 'SET_FILTER'; 4 | -------------------------------------------------------------------------------- /app/main.js: -------------------------------------------------------------------------------- 1 | /* global __DEVTOOLS__ */ 2 | 3 | // BASICS 4 | require('react-bootstrap'); 5 | require('../node_modules/bootstrap/dist/css/bootstrap.min.css'); 6 | require('babel-polyfill'); 7 | 8 | // REACT-ROUTER 9 | import React, {Component, PropTypes} from 'react'; 10 | import ReactDOM from 'react-dom'; 11 | import {Route} from 'react-router'; 12 | import {Button} from 'react-bootstrap'; 13 | 14 | // REDUX 15 | import {combineReducers, createStore, compose, } 16 | from 'redux'; 17 | import { Provider } from 'react-redux'; 18 | import * as reducers from './reducers'; 19 | import { devTools } from 'redux-devtools'; 20 | import { DevTools, DebugPanel, LogMonitor } from 'redux-devtools/lib/react'; 21 | 22 | import createHistory from 'history/lib/createBrowserHistory'; 23 | 24 | // REDUX-REACT-ROUTER 25 | import { 26 | ReduxRouter, 27 | routerStateReducer, 28 | reduxReactRouter, 29 | } from 'redux-react-router'; 30 | 31 | import Main from './GUI/mainContainer'; 32 | 33 | const reducer = combineReducers(Object 34 | .assign({}, reducers, {router: routerStateReducer})); 35 | 36 | class App extends Component { 37 | render() { 38 | return ( 39 |
40 | {this.props.children} 41 |
42 | ); 43 | } 44 | } 45 | 46 | 47 | App.propTypes = { 48 | children: PropTypes.object, 49 | }; 50 | 51 | const routes = ( 52 | 53 | } 54 | } 55 | 56 | ); 57 | 58 | const store = compose( 59 | reduxReactRouter({ 60 | routes, 61 | createHistory, 62 | }), 63 | devTools() 64 | )(createStore)(reducer); 65 | 66 | class Root extends Component { 67 | constructor() { 68 | super(); 69 | this.state = { 70 | showDebug: false, 71 | }; 72 | } 73 | 74 | render() { 75 | const {showDebug} = this.state; 76 | const debug = []; 77 | const debugButton = []; 78 | if (__DEVTOOLS__) { 79 | debugButton.push(); 86 | debugButton.push(
); 87 | if (showDebug) { 88 | debug.push( 89 | 90 | 91 | 92 | ); 93 | } 94 | } 95 | 96 | return ( 97 |
98 | 99 | 100 | 101 | {debug} 102 |
103 | {debugButton} 104 |
105 | ); 106 | } 107 | } 108 | 109 | ReactDOM.render(, document.getElementById('app')); 110 | 111 | -------------------------------------------------------------------------------- /app/reducers/coreReducer.js: -------------------------------------------------------------------------------- 1 | import { 2 | SET_RAW, 3 | SET_FILTER, 4 | } from '../constants/ActionTypes'; 5 | 6 | import filterData from './helpers/filterData'; 7 | 8 | const initialState = { 9 | raw: [], 10 | filtered: [], 11 | nameLengthMax: Infinity, 12 | nameLengthMin: 0, 13 | sex: new Set(['m', 'w']), 14 | }; 15 | 16 | export default function dogsReducer(state = initialState, action) { 17 | let newState = {}; 18 | switch (action.type) { 19 | case SET_RAW: 20 | newState = Object.assign({}, state, {raw: action.raw, filtered: action.raw}); 21 | return newState; 22 | case SET_FILTER: 23 | newState = Object.assign({}, state, action.filterAction); 24 | newState.filtered = filterData(newState); 25 | return newState; 26 | default: 27 | return state; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/reducers/helpers/filterData.js: -------------------------------------------------------------------------------- 1 | export default function filterData(state) { 2 | const {raw, sex, nameLengthMax, nameLengthMin} = state; 3 | return raw.filter(d => { 4 | return ( 5 | sex.has(d[2]) && 6 | d[0].length <= nameLengthMax && 7 | d[0].length >= nameLengthMin 8 | ); 9 | }); 10 | } 11 | -------------------------------------------------------------------------------- /app/reducers/index.js: -------------------------------------------------------------------------------- 1 | export {default as dogData} from './coreReducer'; 2 | -------------------------------------------------------------------------------- /build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dogs 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /dist/448c34a56d699c29117adc64c43affeb.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bgrsquared/d3-react-squared-dogs-blog/a3471c571f0159dc5998aaf56703e73cda19a1ab/dist/448c34a56d699c29117adc64c43affeb.woff2 -------------------------------------------------------------------------------- /dist/89889688147bd7575d6327160d64e760.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | -------------------------------------------------------------------------------- /dist/e18bbf611f2a2e43afc071aa2f4e1512.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bgrsquared/d3-react-squared-dogs-blog/a3471c571f0159dc5998aaf56703e73cda19a1ab/dist/e18bbf611f2a2e43afc071aa2f4e1512.ttf -------------------------------------------------------------------------------- /dist/f4769f9bdb7466be65088239c12046d1.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bgrsquared/d3-react-squared-dogs-blog/a3471c571f0159dc5998aaf56703e73cda19a1ab/dist/f4769f9bdb7466be65088239c12046d1.eot -------------------------------------------------------------------------------- /dist/fa2772327f55d8198301fdb8bcfc8158.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bgrsquared/d3-react-squared-dogs-blog/a3471c571f0159dc5998aaf56703e73cda19a1ab/dist/fa2772327f55d8198301fdb8bcfc8158.woff -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dogs... 7 | 8 | 25 | 26 | 27 | 28 | 29 |
30 |
31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Dogs", 3 | "version": "0.0.2", 4 | "description": "", 5 | "main": "app/main.js", 6 | "scripts": { 7 | "deploy": "NODE_ENV=production webpack -p --config webpack.config_PROD.js", 8 | "dev": "node server.js", 9 | "start": "node server.js" 10 | }, 11 | "author": "Christan Roth (christian.roth@bgrsquared.com", 12 | "license": "tbd, (c) bgrsquared.com 2015", 13 | "devDependencies": { 14 | "babel-core": "^6.2.1", 15 | "babel-loader": "^6.2.0", 16 | "babel-polyfill": "^6.2.0", 17 | "babel-preset-es2015": "^6.1.18", 18 | "babel-preset-react": "^6.1.18", 19 | "babel-preset-stage-2": "^6.1.18", 20 | "bootstrap": "^3.3.5", 21 | "css-loader": "^0.23.0", 22 | "d3": "^3.5.9", 23 | "d3-react-squared": "^0.3.6", 24 | "eslint": "^1.10.1", 25 | "eslint-config-airbnb": "^1.0.0", 26 | "eslint-loader": "^1.1.0", 27 | "eslint-plugin-react": "^3.10.0", 28 | "file-loader": "^0.8.4", 29 | "history": "^1.13.1", 30 | "isomorphic-fetch": "^2.2.0", 31 | "node-sass": "^3.4.1", 32 | "raw-loader": "^0.5.1", 33 | "react": "^0.14.3", 34 | "react-bootstrap": "^0.28.1", 35 | "react-dom": "^0.14.3", 36 | "react-hot-loader": "^1.3.0", 37 | "react-redux": "^4.0.0", 38 | "react-router": "^1.0.0", 39 | "redux": "^3.0.4", 40 | "redux-devtools": "^2.1.5", 41 | "redux-react-router": "^1.0.0-beta3", 42 | "redux-thunk": "^1.0.0", 43 | "sass-loader": "^3.1.2", 44 | "style-loader": "~0.13.0", 45 | "url-loader": "~0.5.6", 46 | "webpack": "^1.12.8", 47 | "webpack-dev-server": "~1.12.1" 48 | }, 49 | "dependencies": {} 50 | } 51 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var config = require('./webpack.config_HOT.js'); 4 | 5 | new WebpackDevServer(webpack(config), { 6 | contentBase: 'build/', 7 | publicPath: config.output.publicPath, 8 | hot: true, 9 | historyApiFallback: true, 10 | stats: { colors: true } 11 | }).listen(3000, 'localhost', function (err, result) { 12 | if (err) { 13 | console.log(err); 14 | } 15 | 16 | console.log('Listening at localhost:3000'); 17 | }); 18 | -------------------------------------------------------------------------------- /webpack.config_HOT.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var app_dir = path.join(__dirname, 'app'); 4 | 5 | module.exports = { 6 | devtool: 'eval-source-map', 7 | entry: { 8 | app: [ 9 | 'webpack-dev-server/client?http://localhost:3000', 10 | 'webpack/hot/only-dev-server', 11 | './app/main' 12 | ] 13 | }, 14 | output: { 15 | path: path.join(__dirname, 'build'), 16 | filename: '[name].js', 17 | publicPath: '/build/' 18 | }, 19 | plugins: [ 20 | new webpack.HotModuleReplacementPlugin(), 21 | new webpack.DefinePlugin({ 22 | __PRODUCTION__: false, 23 | __DEVELOPMENT__: true, 24 | __DEVTOOLS__: true 25 | }) 26 | ], 27 | module: { 28 | loaders: [{ 29 | test: /\.js$/, 30 | loaders: ['react-hot', 'babel'], 31 | include: [app_dir] 32 | }, 33 | { 34 | test: /\.css$/, 35 | loader: 'style-loader!css-loader' 36 | }, 37 | { 38 | test: /\.(woff|png)$/, 39 | loader: 'url-loader?limit=100000' 40 | }, 41 | { 42 | test: /\.scss$/, 43 | loader: 'style-loader!css-loader!sass-loader' 44 | }, 45 | // {test: /\.(png|jpg|gif)$/, loader: 'url-loader?limit=8192'}, 46 | {test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&minetype=image/svg+xml'}, 47 | {test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&minetype=application/font-woff'}, 48 | {test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&minetype=application/font-woff2'}, 49 | {test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&minetype=application/octet-stream'}, 50 | {test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file'}, 51 | {test: /\.json$/, loader: "json"} 52 | ], 53 | preLoaders: [ 54 | { 55 | test: /\.js$/, 56 | include: [app_dir], 57 | loader: 'eslint' 58 | } 59 | ] 60 | } 61 | }; 62 | -------------------------------------------------------------------------------- /webpack.config_PROD.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var path = require('path'); 3 | var node_modules_dir = path.join(__dirname, 'node_modules'); 4 | var app_dir = path.join(__dirname, 'app'); 5 | 6 | var licenseBanner = 'LICENSES: \n' + 7 | 'I hereby list the LICENSES of the javascript vendor resources I used. ' + 8 | 'A big THANK YOU is in order here!\n' + 9 | 'All components are used without any modification and were just bundled using standard webpack.\n\n' + 10 | '--Famo.us: MPLV2.0, see here: https://github.com/Famous/famous/blob/develop/LICENSE\n' + 11 | '--Webpack: MIT License, see here: https://github.com/webpack/webpack/blob/master/LICENSE\n' + 12 | '--Bootstrap: MIT License, see here: https://github.com/twbs/bootstrap/blob/master/LICENSE\n' + 13 | '--MomentJS: Special (open) License, see here: https://github.com/moment/moment/blob/develop/LICENSE\n' + 14 | '--Font Awesome by Dave Gandy - http://fontawesome.io: MIT License, see here: http://fontawesome.io/license\n' + 15 | '--jQuery/jQuery UI: MIT License, see here: https://jquery.org/license/\n' + 16 | '--react: BSD License, see here: https://github.com/facebook/react/blob/master/LICENSE\n' + 17 | '--react-intl: Copyright 2014 Yahoo Inc. All rights reserved., see here: https://github.com/yahoo/react-intl/blob/master/LICENSE.md\n' + 18 | '--underscore: MIT license, see here: https://github.com/jashkenas/underscore/blob/master/LICENSE\n' + 19 | '--griddle-react: MIT License, see here: https://github.com/DynamicTyped/Griddle/blob/master/LICENSE\n' + 20 | '--D3:\n' + 21 | 'Copyright (c) 2010-2015, Michael Bostock \n' + 22 | 'All rights reserved.\n\n' + 23 | 'Redistribution and use in source and binary forms, with or without ' + 24 | 'modification, are permitted provided that the following conditions are met:\n\n' + 25 | '* Redistributions of source code must retain the above copyright notice, this ' + 26 | 'list of conditions and the following disclaimer.\n\n' + 27 | '* Redistributions in binary form must reproduce the above copyright notice, ' + 28 | 'this list of conditions and the following disclaimer in the documentation ' + 29 | 'and/or other materials provided with the distribution.\n\n' + 30 | '* The name Michael Bostock may not be used to endorse or promote products ' + 31 | 'derived from this software without specific prior written permission.\n\n' + 32 | 'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \'AS IS\' ' + 33 | 'AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ' + 34 | 'IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ' + 35 | 'DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT, ' + 36 | 'INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, ' + 37 | 'BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ' + 38 | 'DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY ' + 39 | 'OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ' + 40 | 'NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, ' + 41 | 'EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.' + 42 | '\n\nEND OF LICENSES DECLARATION' 43 | 44 | var config = { 45 | context: __dirname, 46 | entry: { 47 | app: ['./app/main.js'] 48 | }, 49 | output: { 50 | publicPath: '/dogs/', 51 | path: path.resolve('./dist'), 52 | filename: '[name].js' 53 | }, 54 | resolve: { 55 | alias: {} 56 | }, 57 | module: { 58 | noParse: [], 59 | loaders: [ 60 | { 61 | test: /\.js$/, 62 | include: [app_dir], 63 | loaders: ['babel'] 64 | }, { 65 | test: /\.css$/, 66 | loader: 'style-loader!css-loader' 67 | }, { 68 | test: /\.(woff|png)$/, 69 | loader: 'url-loader?limit=100000' 70 | }, { 71 | test: /\.scss$/, 72 | loader: 'style-loader!css-loader!sass-loader' 73 | }, 74 | // {test: /\.(png|jpg|gif)$/, loader: 'url-loader?limit=8192'}, 75 | {test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&minetype=image/svg+xml'}, 76 | {test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&minetype=application/font-woff'}, 77 | {test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&minetype=application/font-woff2'}, 78 | {test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&minetype=application/octet-stream'}, 79 | {test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file'}, 80 | {test: /\.json$/, loader: "json"} 81 | ], 82 | preLoaders: [ 83 | { 84 | test: /\.js$/, 85 | include: [app_dir], 86 | loader: 'eslint' 87 | } 88 | ] 89 | }, 90 | plugins: [ 91 | new webpack.optimize.CommonsChunkPlugin('app', null, false), 92 | new webpack.BannerPlugin(licenseBanner), 93 | new webpack.DefinePlugin({ 94 | __PRODUCTION__: true, 95 | __DEVELOPMENT__: false, 96 | __DEVTOOLS__: false 97 | }) 98 | ] 99 | }; 100 | 101 | module.exports = config; --------------------------------------------------------------------------------