diff --git a/app/templates/teachers/teacher-student-view.jade b/app/templates/teachers/teacher-student-view.jade index e6d646974..69c48092f 100644 --- a/app/templates/teachers/teacher-student-view.jade +++ b/app/templates/teachers/teacher-student-view.jade @@ -12,44 +12,44 @@ block content +breadcrumbs if !me.isAnonymous() && me.isTeacher() - var isOwner = view.classroom ? view.classroom.get('ownerID') === me.id : false; - // - var validStudent = ... - // load all students in this class - // check if this student is in the class if isOwner - // also check if validStudent - h3(class="m-t-2") - span(data-i18n="teacher.student_profile") - span.spr : - span= view.user.get('name') - // this user object doesn't have an email property - h4(class="student-details" data-i18n="teacher.student_overview") - if (view.user.get('email')) - div(class="small-details") - span(data-i18n="teacher.student_email") + h3(class="m-t-2") + span(data-i18n="teacher.student_profile") span.spr : - span= view.user.get('email') - else - div(class="small-details") - i(data-i18n="teacher.no_email") - div(class="small-details") - span(data-i18n="user.last_played") - span.spr : - span= view.lastPlayedString - - div(class="small-details") - - var status = view.user.prepaidStatus() - span(data-i18n='view.user.status') - span.spr - span(data-i18n="teacher.license_status") - span.spr : - strong(class= status === 'expired' ? 'text-danger' : '')= view.studentStatusString() - //- - //- svg#visualisation(width="1000", height="520") - //- + span= view.user.get('name') + .classroom-info-row.container-fluid.row + .overview.col-md-4 + h4(class="student-details" data-i18n="teacher.student_overview") + if (view.user.get('email')) + div(class="small-details") + span(data-i18n="teacher.student_email") + span.spr : + span= view.user.get('email') + else + div(class="small-details") + i(data-i18n="teacher.no_email") + div(class="small-details") + span(data-i18n="user.last_played") + span.spr : + span= view.lastPlayedString + + div(class="small-details") + - var status = view.user.prepaidStatus() + span(data-i18n='view.user.status') + span.spr + span(data-i18n="teacher.license_status") + span.spr : + strong(class= status === 'expired' ? 'text-danger' : '')= view.studentStatusString() + + + .performance.col-md-8 + h4.student-details + span Recommendation + div.small-details + span Performance: - div.playtime-charts - // i18n needed + .playtime-charts h4(data-i18n="teacher.playtime_detail") .graphsSelector @@ -64,6 +64,7 @@ block content - var instance = view.courseInstances.findWhere({ courseID: course.id, classroomID: view.classroom.id }) - if ((instance && instance.hasMember(view.user))) option(value=course.id)=course.get('name') + div.legend svg(width=15, height=15, style="margin: 0 5px 0 0") rect(width=15, height=15,fill="rgb(32, 87, 43)") @@ -82,6 +83,10 @@ block content - var course = _.find(view.courses.models, function(c) {return c.id === versionedCourse._id;}); if !course - continue; + //- - var rate = _.find(view.courseComparisonMap, function(c) {return c.id === versionedCourse._id;}); + //- - console.log (rate); + //- - console.log (rate.rate); + //- span= _.find(view.courseComparisonMap) - var instance = view.courseInstances.findWhere({ courseID: course.id, classroomID: view.classroom.id }) - if ((instance && instance.hasMember(view.user))) svg(id='visualisation-'+versionedCourse._id, width="1142", height="600") diff --git a/app/views/teachers/TeacherStudentView.coffee b/app/views/teachers/TeacherStudentView.coffee index 1298589b4..4ce703c28 100644 --- a/app/views/teachers/TeacherStudentView.coffee +++ b/app/views/teachers/TeacherStudentView.coffee @@ -9,12 +9,6 @@ User = require 'models/User' Users = require 'collections/Users' CourseInstances = require 'collections/CourseInstances' require 'vendor/d3' -# Users = require 'collections/Users' -# helper = require 'lib/coursesHelper' -# popoverTemplate = require 'templates/courses/classroom-level-popover' -# Prepaids = require 'collections/Prepaids' -# utils = require 'core/utils' -# CocoCollection = require 'collections/CocoCollection' @@ -37,24 +31,13 @@ module.exports = class TeacherStudentView extends RootView @supermodel.trackRequest(@classroom.fetch()) @courses = new Courses() - # @courses.comparator = '_id' - # @courseInstances = new CocoCollection([], { url: "/db/course_instance", model: CourseInstance}) - # @courseInstances.comparator = 'courseID' - # @supermodel.loadCollection(@courseInstances, { data: { classroomID: classroomID } }) - # @listenToOnce @courses, 'sync', @onCourseInstancesSync @supermodel.trackRequest(@courses.fetch({data: { project: 'name' }})) @courseInstances = new CourseInstances() @supermodel.trackRequest @courseInstances.fetchForClassroom(classroomID) @levels = new Levels() - # @levels.fetchForClassroom(classroomID, {data: {project: 'name,original,practice,slug'}}) - # @levels.on 'add', (model) -> @_byId[model.get('original')] = model # so you can 'get' them @supermodel.trackRequest(@levels.fetchForClassroom(classroomID, {data: {project: 'name,original'}})) - # - # @user = new User({_id: studentID}) - # @supermodel.trackRequest(@user.fetch()) - @urls = require('core/urls') @@ -69,6 +52,7 @@ module.exports = class TeacherStudentView extends RootView @updateLastPlayedString() @updateLevelProgressMap() @updateLevelDataMap() + @calculateStandardDev() @render() super() @@ -95,11 +79,122 @@ module.exports = class TeacherStudentView extends RootView $("[id|='visualisation']").hide() $(selected).show() + calculateStandardDev: -> + return unless @courses.loaded and @levels.loaded and @sessions?.loaded and @levelData + + @courseComparisonMap = [] + for versionedCourse in @classroom.get('courses') ? [] + course = _.find @courses.models, (c) => c.id is versionedCourse._id + numbers = [] + studentRate = 0 + members = 0 #this is the COUNT for our standard deviation + for member in @classroom.get('members') + NUMBER = 0 + memberBit = 0 + for versionedLevel in versionedCourse.levels + for session in @sessions.models + if session.get('level').original == versionedLevel.original and session.get('creator') == member + # TODO IMPORTANT: only add number if @studentID in levelProgressMap has complete or started for the corresponding level + # in @levelData there's a levelProgress. If for this levelID, levelProgress = complete or started, go ahead. + temp = _.findWhere(@levelData, {levelID: session.get('level').original}) + if temp.levelProgress == 'complete' or temp.levelProgress == 'started' + NUMBER += session.get('playtime') or 0 + memberBit += 1 + if session.get('creator') is @studentID + studentRate += session.get('playtime') or 0 + if memberBit > 0 then members += 1 + numbers.push NUMBER + + # add all numbers[] + SUM = 0 + for num in numbers + SUM += num + + # divide by members to get MEAN, remember MEAN is only an average of the members' performance on levels THIS student has done. + MEAN = SUM/members + + # make new list diffSquared[] + diffSquared = [] + + # for each number in numbers[], subtract MEAN then SQUARE, put new number in diffSquared + for num in numbers + diffSquared.push ((num-MEAN)*(num-MEAN)) + + # add all diffSquared[] then divide by COUNT to get VARIANCE + diffSum = 0 + for num in diffSquared + diffSum += num + VARIANCE = (diffSum / members) + + # square root of VARIANCE is standardDev + StandardDev = Math.sqrt(VARIANCE) + + perf = 0 + if studentRate > MEAN + perf -=1 + if studentRate > (MEAN + StandardDev) + perf -= 1 + if studentRate > (MEAN + (StandardDev*2)) + perf -=1 + else if studentRate < MEAN + perf += 1 + if studentRate < (MEAN - StandardDev) + perf +=1 + if studentRate < (MEAN - (StandardDev*2)) + perf +=1 + # perf 1 and -1 are within 1 std, perf 2 is AMAZING, perf -2 needs some help + # can consider doing half of standard dev to capture more granularity + + @courseComparisonMap.push { + courseID: course.get('_id') + student: studentRate + standardDev: StandardDev + mean: MEAN + performance: perf + } + console.log (@courseComparisonMap) + + # calculateStandardDev: -> + # return unless @courses.loaded and @levels.loaded and @sessions?.loaded + # + # @courseComparisonMap = [] + # for versionedCourse in @classroom.get('courses') ? [] + # course = _.find @courses.models, (c) => c.id is versionedCourse._id + # # @courseTotal = 0 + # @studentLevelsPlayed = 0 # count for standard deviation + # for versionedLevel in versionedCourse.levels + # @playTime = 0 # this should probably only count when the levels are completed + # # @timesPlayed = 0 + # @studentTime = 0 + # # @levelProgress = 'not started' + # for session in @sessions.models + # if session.get('level').original == versionedLevel.original + # # if @levelProgressMap[versionedLevel.original] == 'complete' # ideally, don't log sessions that aren't completed in the class + # @playTime += session.get('playtime') or 0 + # # @timesPlayed += 1 + # if session.get('creator') is @studentID + # @studentLevelsPlayed += 1 + # @studentTime = session.get('playtime') or 0 # this can be null, apparently. + # # if @levelProgressMap[versionedLevel.original] == 'complete' + # # @levelProgress = 'complete' + # # else if @levelProgressMap[versionedLevel.original] == 'started' + # # @levelProgress = 'started' + # classAvg = if @timesPlayed and @timesPlayed > 0 then Math.round(@playTime / @timesPlayed) else 0 # only when someone other than the user has played + # # console.log (@timesPlayed) + # # @performance = if classAvg isnt 0 and @levelProgress isnt 'not started' then ((classAvg - @studentTime)/classAvg)*100 else 0 + # # @courseTotal += @performance + # + # @courseComparisonMap.push { + # courseID: course.get('_id') + # # rate: if @studentLevelsPlayed isnt 0 then (@courseTotal / @studentLevelsPlayed) else null + # studentRate: null + # standardDev: null + # } + # console.log (@courseComparisonMap) - # hide() all the others drawBarGraph: -> - return unless @courses.loaded and @levels.loaded and @sessions?.loaded and @levelData + return unless @courses.loaded and @levels.loaded and @sessions?.loaded and @levelData and @courseComparisonMap WIDTH = 1142 HEIGHT = 600 @@ -110,7 +205,6 @@ module.exports = class TeacherStudentView extends RootView left: 70 } - # console.log (@classroom) for versionedCourse in @classroom.get('courses') ? [] # this does all of the courses, logic for whether student was assigned is in corresponding jade file @@ -119,8 +213,13 @@ module.exports = class TeacherStudentView extends RootView for level in @levelData when level.courseID is versionedCourse._id courseLevelData.push level - course = _.find @courses.models, (c) => c.id is versionedCourse._id + # rate = null + # for course in @courseComparisonMap when course.courseID is versionedCourse._id + # if course.rate isnt null + # rate = (course.rate).toFixed(2) + # console.log (rate) + course = _.find @courses.models, (c) => c.id is versionedCourse._id levels = @classroom.getLevels({courseID: course.id}).models @@ -179,6 +278,15 @@ module.exports = class TeacherStudentView extends RootView .text("Levels in " + (course.get('name'))) .style("text-anchor", "middle") + # if rate isnt 0 and rate isnt null + # if rate > 0 then rate = "+" + rate + # labels.append("text") + # .attr("x", WIDTH - 50) + # .attr("y", HEIGHT - 10) + # .text("Student Course Speed: " + rate + "%") + # .style("text-anchor", "end") + # .style("fill", (d) -> if rate > 0 then "green" else "red") + onClassroomSync: -> # Now that we have the classroom from db, can request all level sessions for this classroom @@ -305,7 +413,7 @@ module.exports = class TeacherStudentView extends RootView else if @levelProgressMap[versionedLevel.original] == 'started' @levelProgress = 'started' classAvg = if @timesPlayed and @timesPlayed > 0 then Math.round(@playTime / @timesPlayed) else 0 # only when someone other than the user has played - console.log (@timesPlayed) + # console.log (@timesPlayed) @levelData.push { levelID: versionedLevel.original levelIndex: @classroom.getLevelNumber(versionedLevel.original)