|  | 
| 8 | 8 | 
 | 
| 9 | 9 | 'use strict'; | 
| 10 | 10 | 
 | 
| 11 |  | -var Registry = require('../../registry'); | 
| 12 | 11 | var Axes = require('../../plots/cartesian/axes'); | 
| 13 | 12 | var Lib = require('../../lib'); | 
| 14 | 13 | 
 | 
| 15 |  | -module.exports = function setPositions(gd, plotinfo) { | 
| 16 |  | -    var fullLayout = gd._fullLayout; | 
|  | 14 | +var orientations = ['v', 'h']; | 
|  | 15 | + | 
|  | 16 | +function setPositions(gd, plotinfo) { | 
|  | 17 | +    var calcdata = gd.calcdata; | 
| 17 | 18 |     var xa = plotinfo.xaxis; | 
| 18 | 19 |     var ya = plotinfo.yaxis; | 
| 19 |  | -    var orientations = ['v', 'h']; | 
| 20 |  | - | 
| 21 |  | -    // TODO figure this out | 
| 22 |  | -    // should violins and boxes share 'num' fields? | 
| 23 |  | -    var numKey = '_numBoxes'; | 
| 24 |  | - | 
| 25 |  | -    var posAxis, i, j, k; | 
| 26 | 20 | 
 | 
| 27 |  | -    for(i = 0; i < orientations.length; ++i) { | 
| 28 |  | -        var orientation = orientations[i], | 
| 29 |  | -            boxlist = [], | 
| 30 |  | -            boxpointlist = [], | 
| 31 |  | -            minPad = 0, | 
| 32 |  | -            maxPad = 0, | 
| 33 |  | -            cd, | 
| 34 |  | -            t, | 
| 35 |  | -            trace; | 
| 36 |  | - | 
| 37 |  | -        // set axis via orientation | 
| 38 |  | -        if(orientation === 'h') posAxis = ya; | 
| 39 |  | -        else posAxis = xa; | 
|  | 21 | +    for(var i = 0; i < orientations.length; i++) { | 
|  | 22 | +        var orientation = orientations[i]; | 
|  | 23 | +        var posAxis = orientation === 'h' ? ya : xa; | 
|  | 24 | +        var boxList = []; | 
|  | 25 | +        var minPad = 0; | 
|  | 26 | +        var maxPad = 0; | 
| 40 | 27 | 
 | 
| 41 | 28 |         // make list of boxes | 
| 42 |  | -        for(j = 0; j < gd.calcdata.length; ++j) { | 
| 43 |  | -            cd = gd.calcdata[j]; | 
| 44 |  | -            t = cd[0].t; | 
| 45 |  | -            trace = cd[0].trace; | 
|  | 29 | +        for(var j = 0; j < calcdata.length; j++) { | 
|  | 30 | +            var cd = calcdata[j]; | 
|  | 31 | +            var t = cd[0].t; | 
|  | 32 | +            var trace = cd[0].trace; | 
| 46 | 33 | 
 | 
| 47 | 34 |             if(trace.visible === true && trace.type === 'box' && | 
| 48 | 35 |                     !t.empty && | 
| 49 | 36 |                     trace.orientation === orientation && | 
| 50 | 37 |                     trace.xaxis === xa._id && | 
| 51 |  | -                    trace.yaxis === ya._id) { | 
| 52 |  | -                boxlist.push(j); | 
|  | 38 | +                    trace.yaxis === ya._id | 
|  | 39 | +              ) { | 
|  | 40 | +                boxList.push(j); | 
|  | 41 | + | 
| 53 | 42 |                 if(trace.boxpoints !== false) { | 
| 54 | 43 |                     minPad = Math.max(minPad, trace.jitter - trace.pointpos - 1); | 
| 55 | 44 |                     maxPad = Math.max(maxPad, trace.jitter + trace.pointpos - 1); | 
| 56 | 45 |                 } | 
| 57 | 46 |             } | 
| 58 | 47 |         } | 
| 59 | 48 | 
 | 
| 60 |  | -        // make list of box points | 
| 61 |  | -        for(j = 0; j < boxlist.length; j++) { | 
| 62 |  | -            cd = gd.calcdata[boxlist[j]]; | 
| 63 |  | -            for(k = 0; k < cd.length; k++) boxpointlist.push(cd[k].pos); | 
| 64 |  | -        } | 
| 65 |  | -        if(!boxpointlist.length) continue; | 
|  | 49 | +        setPositionOffset('box', gd, boxList, posAxis, [minPad, maxPad]); | 
|  | 50 | +    } | 
|  | 51 | +} | 
| 66 | 52 | 
 | 
| 67 |  | -        // box plots - update dPos based on multiple traces | 
| 68 |  | -        // and then use for posAxis autorange | 
|  | 53 | +function setPositionOffset(traceType, gd, boxList, posAxis, pad) { | 
|  | 54 | +    var calcdata = gd.calcdata; | 
|  | 55 | +    var fullLayout = gd._fullLayout; | 
|  | 56 | +    var pointList = []; | 
|  | 57 | + | 
|  | 58 | +    // N.B. reused in violin | 
|  | 59 | +    var numKey = traceType === 'violin' ? '_numViolins' : '_numBoxes'; | 
| 69 | 60 | 
 | 
| 70 |  | -        var boxdv = Lib.distinctVals(boxpointlist); | 
| 71 |  | -        var dPos = boxdv.minDiff / 2; | 
|  | 61 | +    var i, j, calcTrace; | 
| 72 | 62 | 
 | 
| 73 |  | -        // if there's no duplication of x points, | 
| 74 |  | -        // disable 'group' mode by setting counter to 1 | 
| 75 |  | -        if(boxpointlist.length === boxdv.vals.length) { | 
| 76 |  | -            fullLayout[numKey] = 1; | 
|  | 63 | +    // make list of box points | 
|  | 64 | +    for(i = 0; i < boxList.length; i++) { | 
|  | 65 | +        calcTrace = calcdata[boxList[i]]; | 
|  | 66 | +        for(j = 0; j < calcTrace.length; j++) { | 
|  | 67 | +            pointList.push(calcTrace[j].pos); | 
| 77 | 68 |         } | 
|  | 69 | +    } | 
| 78 | 70 | 
 | 
| 79 |  | -        // check for forced minimum dtick | 
| 80 |  | -        Axes.minDtick(posAxis, boxdv.minDiff, boxdv.vals[0], true); | 
|  | 71 | +    if(!pointList.length) return; | 
| 81 | 72 | 
 | 
| 82 |  | -        // set the width of all boxes | 
| 83 |  | -        for(i = 0; i < boxlist.length; i++) { | 
| 84 |  | -            var boxListIndex = boxlist[i]; | 
| 85 |  | -            gd.calcdata[boxListIndex][0].t.dPos = dPos; | 
| 86 |  | -        } | 
|  | 73 | +    // box plots - update dPos based on multiple traces | 
|  | 74 | +    // and then use for posAxis autorange | 
|  | 75 | +    var boxdv = Lib.distinctVals(pointList); | 
|  | 76 | +    var dPos = boxdv.minDiff / 2; | 
| 87 | 77 | 
 | 
| 88 |  | -        // TODO this won't work when both boxes and violins are present | 
| 89 |  | -        // on same graph | 
| 90 |  | -        var gap = fullLayout.boxgap || fullLayout.violingap; | 
| 91 |  | -        var groupgap = fullLayout.boxgroupgap || fullLayout.violingroupgap; | 
| 92 |  | - | 
| 93 |  | -        // autoscale the x axis - including space for points if they're off the side | 
| 94 |  | -        // TODO: this will overdo it if the outermost boxes don't have | 
| 95 |  | -        // their points as far out as the other boxes | 
| 96 |  | -        var padfactor = (1 - gap) * (1 - groupgap) * dPos / fullLayout[numKey]; | 
| 97 |  | -        Axes.expand(posAxis, boxdv.vals, { | 
| 98 |  | -            vpadminus: dPos + minPad * padfactor, | 
| 99 |  | -            vpadplus: dPos + maxPad * padfactor | 
| 100 |  | -        }); | 
|  | 78 | +    // if there's no duplication of x points, | 
|  | 79 | +    // disable 'group' mode by setting counter to 1 | 
|  | 80 | +    if(pointList.length === boxdv.vals.length) { | 
|  | 81 | +        fullLayout[numKey] = 1; | 
| 101 | 82 |     } | 
|  | 83 | + | 
|  | 84 | +    // check for forced minimum dtick | 
|  | 85 | +    Axes.minDtick(posAxis, boxdv.minDiff, boxdv.vals[0], true); | 
|  | 86 | + | 
|  | 87 | +    // set the width of all boxes | 
|  | 88 | +    for(i = 0; i < boxList.length; i++) { | 
|  | 89 | +        calcTrace = calcdata[boxList[i]]; | 
|  | 90 | +        calcTrace[0].t.dPos = dPos; | 
|  | 91 | +    } | 
|  | 92 | + | 
|  | 93 | +    var gap = fullLayout[traceType + 'gap']; | 
|  | 94 | +    var groupgap = fullLayout[traceType + 'groupgap']; | 
|  | 95 | +    var padfactor = (1 - gap) * (1 - groupgap) * dPos / fullLayout[numKey]; | 
|  | 96 | + | 
|  | 97 | +    // autoscale the x axis - including space for points if they're off the side | 
|  | 98 | +    // TODO: this will overdo it if the outermost boxes don't have | 
|  | 99 | +    // their points as far out as the other boxes | 
|  | 100 | +    Axes.expand(posAxis, boxdv.vals, { | 
|  | 101 | +        vpadminus: dPos + pad[0] * padfactor, | 
|  | 102 | +        vpadplus: dPos + pad[1] * padfactor | 
|  | 103 | +    }); | 
|  | 104 | +} | 
|  | 105 | + | 
|  | 106 | +module.exports = { | 
|  | 107 | +    setPositions: setPositions, | 
|  | 108 | +    setPositionOffset: setPositionOffset | 
| 102 | 109 | }; | 
0 commit comments