Skip to content

Instantly share code, notes, and snippets.

@mnishiguchi
Last active September 15, 2016 08:35
Show Gist options
  • Save mnishiguchi/287d4043c7b69442af23 to your computer and use it in GitHub Desktop.
Save mnishiguchi/287d4043c7b69442af23 to your computer and use it in GitHub Desktop.
React.js + Chart.jsでインタラクティブなグラフを書く ref: http://qiita.com/mnishiguchi/items/226c0a4bd85e4da54f42
R = React.DOM
# Canvases for charts
PieChartCanvas = React.createClass
render: ->
R.canvas
style: { height: 200, width: 200 }
BarChartCanvas = React.createClass
render: ->
R.canvas
style: { height: 200, width: 400 }
@MovingRecordsApp = React.createClass
getInitialState: ->
records: @props.data
# Remember Chart.js instances so we can delete them later.
barChartInstance: null
pieChartInstance: null
getDefaultProps: ->
records: []
addRecord: (record) ->
records = React.addons.update(@state.records, { $unshift: [record] })
@setState records: records
deleteRecord: (record) ->
index = @state.records.indexOf record
records = React.addons.update(@state.records, { $splice: [[index, 1]] })
@replaceState records: records
updateRecord: (record, newRecord) ->
index = @state.records.indexOf record
records = React.addons.update(@state.records, { $splice: [[index, 1, newRecord]] })
@replaceState records: records
chartsPanel: ->
R.div
className: "panel panel-blue"
R.div
className: 'panel-heading'
R.div
className: "row"
R.div
className: "col-xs-3"
R.div
className: "fa fa-home fa-5x"
R.div
className: "col-xs-9 text-right"
R.div
className: 'huge'
"Total: #{@totalVolume()}"
R.div null,
"cubic feet"
R.div
className: 'panel-body'
R.div
className: 'row text-center'
R.div
className: 'col-sm-6'
React.createElement BarChartCanvas,
ref: "bar"
R.div
className: 'col-sm-6'
React.createElement PieChartCanvas,
ref: "chart"
totalVolume: ->
sum = 0
for obj in @state.records
sum += (obj.volume * obj.quantity)
sum
render: ->
R.div
className: "app_wrapper"
@chartsPanel()
R.hr null
R.h2 null, "Add a new item"
React.createElement NewMovingRecordForm,
handleNewRecord: @addRecord
roomSuggestions: @props.roomSuggestions
categorySuggestions: @props.categorySuggestions
R.hr null
React.createElement Records,
records: @state.records,
handleDeleteRecord: @deleteRecord,
handleUpdateRecord: @updateRecord
# 部品がDOMに搭載された後に、グラフを書く。
componentDidMount: ->
@drawCharts()
# 部品が更新された後に、古いグラフを破壊し新しいグラフを書く。
componentWillUnmount: ->
@state.barChartInstance.destroy()
@state.pieChartInstance.destroy()
# DOM上のキャンバスを探し、そこにグラフを描画。
drawCharts: ->
# 棒グラフ
canvas = React.findDOMNode(@refs.bar) # refを手掛かりにキャンバスを探します。
ctx = canvas.getContext("2d") # 絵を書くための場所をゲットします。
# グラフ用データを渡し、グラフのオブジェクトを作ります。
# そのオブジェクトを後ほど破壊するためにポインターを保存しておきます。
@setState.barChartInstance = new Chart(ctx).Bar(@dataForBarChart())
# 円グラフ
canvas = React.findDOMNode(@refs.chart)
ctx = canvas.getContext("2d")
@setState.pieChartInstance = new Chart(ctx).Pie(@dataForPieChart())
dataForPieChart: ->
[
{
value: 300
color:"#F7464A"
highlight: "#FF5A5E"
label: "Red"
}
{
value: 50
color: "#46BFBD"
highlight: "#5AD3D1"
label: "Green"
}
{
value: 100
color: "#FDB45C"
highlight: "#FFC870"
label: "Yellow"
}
]
dataForBarChart: ->
labels: ["January", "February", "March", "April", "May", "June", "July"]
datasets: [
{
label: "My First dataset"
fillColor: "rgba(220,220,220,0.5)"
strokeColor: "rgba(220,220,220,0.8)"
highlightFill: "rgba(220,220,220,0.75)"
highlightStroke: "rgba(220,220,220,1)"
data: [65, 59, 80, 81, 56, 55, 40]
}
{
label: "My Second dataset"
fillColor: "rgba(151,187,205,0.5)"
strokeColor: "rgba(151,187,205,0.8)"
highlightFill: "rgba(151,187,205,0.75)"
highlightStroke: "rgba(151,187,205,1)"
data: [28, 48, 40, 19, 86, 27, 90]
}
]
dataForPieChart: ->
source = @volumeSortedBy("room")
ary = []
colors = ["#FE2E2E", "#FE9A2E", "#F7FE2EB", "#9AFE2E", "#2EFE2E", "#2EFE9A",
"#2EFEF7", "#2E9AFE", "#2E2EFE", "#9A2EFE", "#FE2EF7", "#FE2E9A"]
@shuffleArray(colors)
for item, i in source
obj =
value: item.volume
color: colors[i]
highlight: colors[i]
label: item.room
ary.push(obj)
ary
dataForBarChart: ->
source = @volumeSortedBy("category")
labels = source.map (obj) -> obj.category
data = source.map (obj) -> obj.volume
datasets = [
{
fillColor: "rgba(151,187,205,0.5)"
strokeColor: "rgba(151,187,205,0.8)"
highlightFill: "rgba(151,187,205,0.75)"
highlightStroke: "rgba(151,187,205,1)"
data: data
}
]
{ labels: labels, datasets: datasets }
...
# 部品がDOMに搭載された後に、グラフを書く。
componentDidMount: ->
@drawCharts()
# 部品が更新された後に、古いグラフを破壊し新しいグラフを書く。
componentWillUnmount: ->
@state.barChartInstance.destroy()
@state.pieChartInstance.destroy()
# DOM上のキャンバスを探し、そこにグラフを描画。
drawCharts: ->
# 棒グラフ
canvas = React.findDOMNode(@refs.bar) # refを手掛かりにキャンバスを探します。
ctx = canvas.getContext("2d") # 絵を書くための場所をゲットします。
# グラフ用データを渡し、グラフのオブジェクトを作ります。
# そのオブジェクトを後ほど破壊するためにポインターを保存しておきます。
@setState.barChartInstance = new Chart(ctx).Bar(@dataForBarChart())
# 円グラフ
canvas = React.findDOMNode(@refs.chart)
ctx = canvas.getContext("2d")
@setState.pieChartInstance = new Chart(ctx).Pie(@dataForPieChart())
# 棒グラフ用データ(これはドキュメンテーションから引用した例)
# ここで実際は@state.recordsのデータを加工してデータを準備します。
dataForBarChart: ->
labels: ["January", "February", "March", "April", "May", "June", "July"]
datasets: [
{
label: "My First dataset"
fillColor: "rgba(220,220,220,0.5)"
strokeColor: "rgba(220,220,220,0.8)"
highlightFill: "rgba(220,220,220,0.75)"
highlightStroke: "rgba(220,220,220,1)"
data: [65, 59, 80, 81, 56, 55, 40]
}
{
label: "My Second dataset"
fillColor: "rgba(151,187,205,0.5)"
strokeColor: "rgba(151,187,205,0.8)"
highlightFill: "rgba(151,187,205,0.75)"
highlightStroke: "rgba(151,187,205,1)"
data: [28, 48, 40, 19, 86, 27, 90]
}
]
# 円グラフ用データ(これはドキュメンテーションから引用した例)
# ここで実際は@state.recordsのデータを加工してデータを準備します。
dataForPieChart: ->
[
{
value: 300
color:"#F7464A"
highlight: "#FF5A5E"
label: "Red"
}
{
value: 50
color: "#46BFBD"
highlight: "#5AD3D1"
label: "Green"
}
{
value: 100
color: "#FDB45C"
highlight: "#FFC870"
label: "Yellow"
}
]
@MovingRecordsApp = React.createClass
getInitialState: ->
records: @props.data
# グラフのオブジェクトを覚えておくための変数。
barChartInstance: null
pieChartInstance: null
# React.DOMの記述を省略するための変数。
R = React.DOM
PieChartCanvas = React.createClass
render: ->
R.canvas
style: { height: 200, width: 200 }
BarChartCanvas = React.createClass
render: ->
R.canvas
style: { height: 200, width: 400 }
# React.DOMの記述を省略するための変数。
R = React.DOM
# メインの部品
@MovingRecordsApp = React.createClass
getInitialState: ->
records: @props.data # 外部から供給されるデータ。
# グラフのオブジェクトを覚えておくための変数。
barChartInstance: null
pieChartInstance: null
getDefaultProps: ->
records: []
...
# グラフと額縁のテンプレート
chartsPanel: ->
R.div
className: "panel panel-blue"
R.div
className: 'panel-heading'
R.div
className: "row"
R.div
className: "col-xs-3"
R.div
className: "fa fa-home fa-5x"
R.div
className: "col-xs-9 text-right"
R.div
className: 'huge'
"Total: #{@totalVolume()}"
R.div null,
"cubic feet"
R.div
className: 'panel-body'
R.div
className: 'row text-center'
# 棒グラフ用キャンバス
R.div
className: 'col-sm-6'
React.createElement BarChartCanvas,
ref: "bar" # 後にアクセスするために使用
# 円グラフ用キャンバス
R.div
className: 'col-sm-6'
React.createElement PieChartCanvas,
ref: "chart" # 後にアクセスするために使用
render: ->
R.div
className: "app_wrapper"
# グラフと額縁
R.div null, @chartsPanel()
R.hr null
# 新規作成フォームの部品(この部品についての本題ではないので、詳細は省略しています。)
R.h2 null, "Add a new item"
React.createElement NewMovingRecordForm,
handleNewRecord: @addRecord
roomSuggestions: @props.roomSuggestions
categorySuggestions: @props.categorySuggestions
R.hr null
# 表の部品(この部品についての本題ではないので、詳細は省略しています。)
React.createElement Records,
records: @state.records,
handleDeleteRecord: @deleteRecord,
handleUpdateRecord: @updateRecord
...
dataForPieChart: ->
source = @volumeSortedBy("room")
ary = []
colors = ["#FE2E2E", "#FE9A2E", "#FE9A2E", "#9AFE2E", "#2EFE2E", "#2EFE9A",
"#2EFEF7", "#2E9AFE", "#2E2EFE", "#9A2EFE", "#FE2EF7", "#FE2E9A"]
@shuffleArray(colors)
for item, i in source
obj =
value: item.volume
color: colors[i]
highlight: colors[i]
label: item.room
ary.push(obj)
ary
dataForBarChart: ->
source = @volumeSortedBy("category")
labels = source.map (obj) -> obj.category
data = source.map (obj) -> obj.volume
datasets = [
{
fillColor: "rgba(151,187,205,0.5)"
strokeColor: "rgba(151,187,205,0.8)"
highlightFill: "rgba(151,187,205,0.75)"
highlightStroke: "rgba(151,187,205,1)"
data: data
}
]
{ labels: labels, datasets: datasets }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment