@@ -365,8 +365,6 @@ nv.addGraph(function() {
365365// x-axis is contest time
366366// y axis is # of submissions
367367
368- var max_submissions_per_minute = 0 ;
369-
370368var submission_stats = [
371369 {% for result in [' correct' , ' wrong-answer' , ' timelimit' , ' run-error' , ' compiler-error' , ' no-output' ] %}
372370 {
@@ -377,20 +375,44 @@ var submission_stats = [
377375 {% endfor %}
378376];
379377
380- var submissions = [
378+ const contest_start_time = {{ current_contest .starttime }};
379+ const submissions = [
381380 {% for submission in submissions %}
382381 {
383382 result: " {{ submission.result }}" ,
384383 submittime: {{ submission .submittime }},
385- starttime: {{ current_contest .starttime }}
386384 }{{ loop .last ? ' ' : ' ,' }}
387385 {% endfor %}
388386];
389387
390- var contest_duration_minutes = Math .ceil (({{ current_contest .endtime }} - {{ current_contest .starttime }}) / 60 );
388+ const min_bucket_count = 30 ;
389+ const max_bucket_count = 301 ;
390+ const units = [
391+ {' name' : ' seconds' , ' convert' : 1 , ' step' : 60 },
392+ {' name' : ' minutes' , ' convert' : 60 , ' step' : 15 },
393+ {' name' : ' hours' , ' convert' : 60 * 60 , ' step' : 6 },
394+ {' name' : ' days' , ' convert' : 60 * 60 * 24 , ' step' : 7 },
395+ {' name' : ' weeks' , ' convert' : 60 * 60 * 24 * 7 , ' step' : 1 },
396+ {' name' : ' years' , ' convert' : 60 * 60 * 24 * 365 , ' step' : 1 }
397+ ];
398+ let unit = units[0 ];
399+
400+ let contest_duration = {{ (current_contest .endtime - current_contest .starttime ) | round(0 , ' ceil' ) }};
401+ for (let u of units) {
402+ const new_duration = Math .ceil (contest_duration / u .convert );
403+ if (new_duration > min_bucket_count) {
404+ unit = u;
405+ } else {
406+ break ;
407+ }
408+ }
409+ contest_duration = Math .ceil (contest_duration / unit .convert );
410+ const bucket_count = Math .min (contest_duration + 1 , max_bucket_count);
411+ // Make sure buckets have whole unit
412+ const seconds_per_bucket = Math .ceil (contest_duration / (bucket_count - 1 )) * unit .convert ;
391413
392414submission_stats .forEach (stat => {
393- stat .values = Array .from ({ length: contest_duration_minutes + 1 }, (_ , i ) => [i, 0 ]);
415+ stat .values = Array .from ({ length: bucket_count }, (_ , i ) => [i * seconds_per_bucket / unit . convert , 0 ]);
394416});
395417
396418const statMap = submission_stats .reduce ((map , stat ) => {
@@ -399,27 +421,30 @@ const statMap = submission_stats.reduce((map, stat) => {
399421}, {});
400422
401423submissions .forEach (submission => {
402- let submission_minute = Math .floor ((submission .submittime - submission . starttime ) / 60 );
403- let stat = statMap[submission .result ];
404- if (stat && submission_minute >= 0 && submission_minute < contest_duration_minutes ) {
405- stat .values [submission_minute ][1 ]++ ;
424+ const submission_bucket = Math .floor ((submission .submittime - contest_start_time ) / seconds_per_bucket );
425+ const stat = statMap[submission .result ];
426+ if (stat && submission_bucket >= 0 && submission_bucket < bucket_count ) {
427+ stat .values [submission_bucket ][1 ]++ ;
406428 }
407429});
408430
409- for (let minute = 0 ; minute <= contest_duration_minutes; minute++ ) {
410- let this_minute_submission_nums = 0 ;
431+ let max_submissions_per_bucket = 1
432+ for (let bucket = 0 ; bucket < bucket_count; bucket++ ) {
433+ let sum = 0 ;
411434 submission_stats .forEach (stat => {
412- this_minute_submission_nums += stat .values [minute ][1 ];
435+ sum += stat .values [bucket ][1 ];
413436 });
414- max_submissions_per_minute = Math .max (max_submissions_per_minute, this_minute_submission_nums );
437+ max_submissions_per_bucket = Math .max (max_submissions_per_bucket, sum );
415438}
416439
417- // Pick a nice round tickDelta and tickValues
418- var tickDelta = 15 ;
419- while (contest_duration_minutes / tickDelta > 15 ) {
420- tickDelta *= 2 ;
421- }
422- var tickValues = Array .from ({ length: Math .ceil (contest_duration_minutes / tickDelta) + 1 }, (_ , i ) => i * tickDelta);
440+ // Pick a nice round tickDelta and tickValues based on the step size of units.
441+ // We want whole values in the unit, and the ticks MUST match a corresponding bucket otherwise the resulting
442+ // coordinate will be NaN.
443+ const convert_factor = seconds_per_bucket / unit .convert ;
444+ const maxTicks = Math .min (bucket_count, contest_duration / unit .step , min_bucket_count)
445+ const tickDelta = convert_factor * Math .ceil (contest_duration / (maxTicks * convert_factor));
446+ const ticks = Math .floor (contest_duration / tickDelta) + 1 ;
447+ const tickValues = Array .from ({ length: ticks }, (_ , i ) => i * tickDelta);
423448
424449nv .addGraph (function () {
425450 var chart = nv .models .multiBarChart ()
@@ -436,7 +461,7 @@ nv.addGraph(function() {
436461 .reduceXTicks (false )
437462 ;
438463 chart .xAxis // Chart x-axis settings
439- .axisLabel (' Contest Time(minutes) ' )
464+ .axisLabel (` Contest Time ( ${ unit . name } ) ` )
440465 .ticks (tickValues .length )
441466 .tickValues (tickValues)
442467 .tickFormat (d3 .format (' d' ));
0 commit comments