@@ -438,6 +438,8 @@ plots.supplyDefaults = function(gd) {
438438 } ;
439439 newFullLayout . _traceWord = _ ( gd , 'trace' ) ;
440440
441+ var formatObj = getD3FormatObj ( gd ) ;
442+
441443 // first fill in what we can of layout without looking at data
442444 // because fullData needs a few things from layout
443445
@@ -447,15 +449,15 @@ plots.supplyDefaults = function(gd) {
447449 var oldWidth = oldFullLayout . width ,
448450 oldHeight = oldFullLayout . height ;
449451
450- plots . supplyLayoutGlobalDefaults ( newLayout , newFullLayout ) ;
452+ plots . supplyLayoutGlobalDefaults ( newLayout , newFullLayout , formatObj ) ;
451453
452454 if ( ! newLayout . width ) newFullLayout . width = oldWidth ;
453455 if ( ! newLayout . height ) newFullLayout . height = oldHeight ;
454456 }
455457 else {
456458
457459 // coerce the updated layout and autosize if needed
458- plots . supplyLayoutGlobalDefaults ( newLayout , newFullLayout ) ;
460+ plots . supplyLayoutGlobalDefaults ( newLayout , newFullLayout , formatObj ) ;
459461
460462 var missingWidthOrHeight = ( ! newLayout . width || ! newLayout . height ) ,
461463 autosize = newFullLayout . autosize ,
@@ -472,6 +474,8 @@ plots.supplyDefaults = function(gd) {
472474 }
473475 }
474476
477+ newFullLayout . _d3locale = getFormatter ( formatObj , newFullLayout . separators ) ;
478+
475479 newFullLayout . _initialAutoSizeIsDone = true ;
476480
477481 // keep track of how many traces are inputted
@@ -563,6 +567,83 @@ function remapTransformedArrays(cd0, newTrace) {
563567 }
564568}
565569
570+ var formatKeys = [
571+ 'days' , 'shortDays' , 'months' , 'shortMonths' , 'periods' ,
572+ 'dateTime' , 'date' , 'time' ,
573+ 'decimal' , 'thousands' , 'grouping' , 'currency'
574+ ] ;
575+
576+ /**
577+ * getD3FormatObj: use _context to get the d3.locale argument object.
578+ * decimal and thousands can be overridden later by layout.separators
579+ * grouping and currency are not presently used by our automatic number
580+ * formatting system but can be used by custom formats.
581+ *
582+ * @returns {object } d3.locale format object
583+ */
584+ function getD3FormatObj ( gd ) {
585+ var locale = gd . _context . locale ;
586+ if ( ! locale ) locale === 'en-US' ;
587+
588+ var formatDone = false ;
589+ var formatObj = { } ;
590+
591+ function includeFormat ( newFormat ) {
592+ var formatFinished = true ;
593+ for ( var i = 0 ; i < formatKeys . length ; i ++ ) {
594+ var formatKey = formatKeys [ i ] ;
595+ if ( ! formatObj [ formatKey ] ) {
596+ if ( newFormat [ formatKey ] ) {
597+ formatObj [ formatKey ] = newFormat [ formatKey ] ;
598+ }
599+ else formatFinished = false ;
600+ }
601+ }
602+ if ( formatFinished ) formatDone = true ;
603+ }
604+
605+ // same as localize, look for format parts in each format spec in the chain
606+ for ( var i = 0 ; i < 2 ; i ++ ) {
607+ var formats = gd . _context . formats ;
608+ for ( var j = 0 ; j < 2 ; j ++ ) {
609+ var formatj = formats [ locale ] ;
610+ if ( formatj ) {
611+ includeFormat ( formatj ) ;
612+ if ( formatDone ) break ;
613+ }
614+ formats = Registry . formatRegistry ;
615+ }
616+
617+ var baseLocale = locale . split ( '-' ) [ 0 ] ;
618+ if ( formatDone || baseLocale === locale ) break ;
619+ locale = baseLocale ;
620+ }
621+
622+ // lastly pick out defaults from english (non-US, as DMY is so much more common)
623+ if ( ! formatDone ) includeFormat ( Registry . formatRegistry . en ) ;
624+
625+ return formatObj ;
626+ }
627+
628+ /**
629+ * getFormatter: combine the final separators with the locale formatting object
630+ * we pulled earlier to generate number and time formatters
631+ * TODO: remove separators in v2, only use locale, so we don't need this step?
632+ *
633+ * @param {object } formatObj: d3.locale format object
634+ * @param {string } separators: length-2 string to override decimal and thousands
635+ * separators in number formatting
636+ *
637+ * @returns {object } {numberFormat, timeFormat} d3 formatter factory functions
638+ * for numbers and time
639+ */
640+ function getFormatter ( formatObj , separators ) {
641+ formatObj . decimal = separators . charAt ( 0 ) ;
642+ formatObj . thousands = separators . charAt ( 1 ) ;
643+
644+ return d3 . locale ( formatObj ) ;
645+ }
646+
566647// Create storage for all of the data related to frames and transitions:
567648plots . createTransitionData = function ( gd ) {
568649 // Set up the default keyframe if it doesn't exist:
@@ -1144,7 +1225,7 @@ function applyTransforms(fullTrace, fullData, layout, fullLayout) {
11441225 return dataOut ;
11451226}
11461227
1147- plots . supplyLayoutGlobalDefaults = function ( layoutIn , layoutOut ) {
1228+ plots . supplyLayoutGlobalDefaults = function ( layoutIn , layoutOut , formatObj ) {
11481229 function coerce ( attr , dflt ) {
11491230 return Lib . coerce ( layoutIn , layoutOut , plots . layoutAttributes , attr , dflt ) ;
11501231 }
@@ -1183,7 +1264,7 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut) {
11831264
11841265 coerce ( 'paper_bgcolor' ) ;
11851266
1186- coerce ( 'separators' ) ;
1267+ coerce ( 'separators' , formatObj . decimal + formatObj . thousands ) ;
11871268 coerce ( 'hidesources' ) ;
11881269
11891270 coerce ( 'colorway' ) ;
0 commit comments