mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-03-14 07:00:01 -04:00
Graphs with D3!
This commit is contained in:
parent
943bcf3162
commit
3aa31c7246
6 changed files with 89 additions and 24 deletions
13
app/styles/play/ladder/my_matches_tab.sass
Normal file
13
app/styles/play/ladder/my_matches_tab.sass
Normal file
|
@ -0,0 +1,13 @@
|
|||
#my-matches-tab-view
|
||||
.axis path, .axis line
|
||||
fill: none
|
||||
stroke: #000
|
||||
shape-rendering: crispEdges
|
||||
.x.axis.path
|
||||
display: none
|
||||
|
||||
.line
|
||||
fill: none
|
||||
stroke: steelblue
|
||||
stroke-width: 1.5px
|
||||
|
|
@ -11,14 +11,14 @@ div#columns.row
|
|||
|
||||
tr
|
||||
th(colspan=4, style="color: #{team.primaryColor}")
|
||||
span(data-i18n="ladder.summary_your") Your
|
||||
span(data-i18n="ladder.summary_your") Your
|
||||
|#{team.name}
|
||||
|
|
||||
span(data-i18n="ladder.summary_matches") Matches -
|
||||
span(data-i18n="ladder.summary_matches") Matches -
|
||||
|#{team.wins}
|
||||
span(data-i18n="ladder.summary_wins") Wins,
|
||||
span(data-i18n="ladder.summary_wins") Wins,
|
||||
|#{team.losses}
|
||||
span(data-i18n="ladder.summary_losses") Losses
|
||||
span(data-i18n="ladder.summary_losses") Losses
|
||||
|
||||
if team.session
|
||||
tr
|
||||
|
@ -34,7 +34,9 @@ div#columns.row
|
|||
if team.chartData
|
||||
tr
|
||||
th(colspan=4, style="color: #{team.primaryColor}")
|
||||
img(src="https://chart.googleapis.com/chart?chs=450x125&cht=lxy&chco=#{team.chartColor}&chtt=Score%3A+#{team.currentScore}&chts=#{team.chartColor},16,r&chf=a,s,000000FF&chls=2&chm=o,#{team.chartColor},0,4&chd=t:#{team.chartData}&chxt=y&chxr=0,#{team.minScore},#{team.maxScore}")
|
||||
div(class="score-chart-wrapper", data-team-name=team.name, id="score-chart-#{team.name}")
|
||||
|
||||
|
||||
|
||||
tr
|
||||
th(data-i18n="general.result") Result
|
||||
|
|
|
@ -48,6 +48,8 @@ module.exports = class MyMatchesTabView extends CocoView
|
|||
@startsLoading = false
|
||||
@render()
|
||||
|
||||
|
||||
|
||||
getRenderData: ->
|
||||
ctx = super()
|
||||
ctx.level = @level
|
||||
|
@ -80,7 +82,9 @@ module.exports = class MyMatchesTabView extends CocoView
|
|||
team.losses = _.filter(team.matches, {state: 'loss'}).length
|
||||
scoreHistory = team.session?.get('scoreHistory')
|
||||
if scoreHistory?.length > 1
|
||||
team.scoreHistory = scoreHistory
|
||||
scoreHistory = _.last scoreHistory, 100 # Chart URL needs to be under 2048 characters for GET
|
||||
|
||||
team.currentScore = Math.round scoreHistory[scoreHistory.length - 1][1] * 100
|
||||
team.chartColor = team.primaryColor.replace '#', ''
|
||||
#times = (s[0] for s in scoreHistory)
|
||||
|
@ -109,7 +113,69 @@ module.exports = class MyMatchesTabView extends CocoView
|
|||
else if session.get 'isRanking'
|
||||
rankingState = 'ranking'
|
||||
@setRankingButtonText button, rankingState
|
||||
|
||||
@$el.find('.score-chart-wrapper').each (i, el) =>
|
||||
scoreWrapper = $(el)
|
||||
team = _.find @teams, name: scoreWrapper.data('team-name')
|
||||
@generateScoreLineChart(scoreWrapper.attr('id'), team.scoreHistory)
|
||||
|
||||
|
||||
generateScoreLineChart: (wrapperID, scoreHistory) =>
|
||||
|
||||
|
||||
margin =
|
||||
top: 20
|
||||
right: 20
|
||||
bottom: 30
|
||||
left: 50
|
||||
|
||||
width = 450 - margin.left - margin.right
|
||||
height = 125
|
||||
x = d3.time.scale().range([0,width])
|
||||
y = d3.scale.linear().range([height,0])
|
||||
|
||||
xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(4).outerTickSize(0)
|
||||
yAxis = d3.svg.axis().scale(y).orient("left").ticks(4).outerTickSize(0)
|
||||
|
||||
line = d3.svg.line().x(((d) -> x(d.date))).y((d) -> y(d.close))
|
||||
selector = "#" + wrapperID
|
||||
|
||||
svg = d3.select(selector).append("svg")
|
||||
.attr("width", width + margin.left + margin.right)
|
||||
.attr("height", height + margin.top + margin.bottom)
|
||||
.append("g")
|
||||
.attr("transform","translate(#{margin.left},#{margin.top})")
|
||||
time = 0
|
||||
data = scoreHistory.map (d) ->
|
||||
time +=1
|
||||
return {
|
||||
date: time
|
||||
close: d[1] * 100
|
||||
}
|
||||
|
||||
x.domain(d3.extent(data, (d) -> d.date))
|
||||
y.domain(d3.extent(data, (d) -> d.close))
|
||||
|
||||
|
||||
|
||||
svg.append("g")
|
||||
.attr("class", "y axis")
|
||||
.call(yAxis)
|
||||
.append("text")
|
||||
.attr("transform", "rotate(-90)")
|
||||
.attr("y",4)
|
||||
.attr("dy", ".75em")
|
||||
.style("text-anchor","end")
|
||||
.text("Score")
|
||||
|
||||
svg.append("path")
|
||||
.datum(data)
|
||||
.attr("class","line")
|
||||
.attr("d",line)
|
||||
|
||||
|
||||
|
||||
|
||||
readyToRank: (session) ->
|
||||
return false unless session?.get('levelID') # If it hasn't been denormalized, then it's not ready.
|
||||
return false unless c1 = session.get('code')
|
||||
|
|
|
@ -35,7 +35,8 @@
|
|||
"aether": "~0.1.18",
|
||||
"underscore.string": "~2.3.3",
|
||||
"firebase": "~1.0.2",
|
||||
"catiline": "~2.9.3"
|
||||
"catiline": "~2.9.3",
|
||||
"d3": "~3.4.4"
|
||||
},
|
||||
"overrides": {
|
||||
"backbone": {
|
||||
|
|
|
@ -65,6 +65,7 @@ exports.config =
|
|||
|
||||
# Aether before box2d for some strange Object.defineProperty thing
|
||||
'bower_components/aether/build/aether.js'
|
||||
'bower_components/d3/d3.min.js'
|
||||
]
|
||||
stylesheets:
|
||||
defaultExtension: 'sass'
|
||||
|
|
|
@ -100,8 +100,6 @@ resimulateSession = (originalLevelID, levelMajorVersion, session, cb) =>
|
|||
cb null
|
||||
|
||||
|
||||
|
||||
|
||||
module.exports.createNewTask = (req, res) ->
|
||||
requestSessionID = req.body.session
|
||||
originalLevelID = req.body.originalLevelID
|
||||
|
@ -514,8 +512,6 @@ findNearestBetterSessionID = (cb) ->
|
|||
opponentSessionTotalScore = @newScoresObject[opponentSessionID].totalScore
|
||||
opposingTeam = calculateOpposingTeam(@clientResponseObject.originalSessionTeam)
|
||||
|
||||
|
||||
|
||||
retrieveAllOpponentSessionIDs sessionID, (err, opponentSessionIDs) ->
|
||||
if err? then return cb err, null
|
||||
|
||||
|
@ -577,18 +573,10 @@ addNewSessionsToQueue = (sessionID, callback) ->
|
|||
sessions = [@clientResponseObject.originalSessionID, sessionID]
|
||||
addPairwiseTaskToQueue sessions, callback
|
||||
|
||||
|
||||
|
||||
|
||||
messageIsInvalid = (message) -> (not message?) or message.isEmpty()
|
||||
|
||||
sendEachTaskPairToTheQueue = (taskPairs, callback) -> async.each taskPairs, sendTaskPairToQueue, callback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
generateTaskPairs = (submittedSessions, sessionToScore) ->
|
||||
taskPairs = []
|
||||
for session in submittedSessions
|
||||
|
@ -609,10 +597,6 @@ isUserAnonymous = (req) -> if req.user? then return req.user.get('anonymous') el
|
|||
|
||||
isUserAdmin = (req) -> return Boolean(req.user?.isAdmin())
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
sendResponseObject = (req,res,object) ->
|
||||
res.setHeader('Content-Type', 'application/json')
|
||||
res.send(object)
|
||||
|
@ -622,8 +606,6 @@ hasTaskTimedOut = (taskSentTimestamp) -> taskSentTimestamp + scoringTaskTimeoutI
|
|||
|
||||
handleTimedOutTask = (req, res, taskBody) -> errors.clientTimeout res, "The results weren't provided within the timeout"
|
||||
|
||||
|
||||
|
||||
putRankingFromMetricsIntoScoreObject = (taskObject,scoreObject) ->
|
||||
scoreObject = _.indexBy scoreObject, 'id'
|
||||
scoreObject[session.sessionID].gameRanking = session.metrics.rank for session in taskObject.sessions
|
||||
|
|
Loading…
Reference in a new issue