Skip to content

Commit fc0af0c

Browse files
committed
add generalUpdatePerTraceModule method in Plots
- so that the same logic can be share for geo and ternary subplots (and maybe cartesian subplots down the road) - fix bug occurring when the first trace on a given subplot had `visible: false` (which yielded an exception)
1 parent a7cca2e commit fc0af0c

File tree

3 files changed

+176
-54
lines changed

3 files changed

+176
-54
lines changed

src/plots/geo/geo.js

Lines changed: 2 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ var d3 = require('d3');
1515

1616
var Color = require('../../components/color');
1717
var Drawing = require('../../components/drawing');
18+
var Plots = require('../plots');
1819
var Axes = require('../cartesian/axes');
1920
var Fx = require('../cartesian/graph_interact');
2021

@@ -170,66 +171,13 @@ proto.plot = function(geoCalcData, fullLayout, promises) {
170171
};
171172

172173
proto.onceTopojsonIsLoaded = function(geoCalcData, geoLayout) {
173-
var i;
174-
175174
this.drawLayout(geoLayout);
176175

177-
var traceHashOld = this.traceHash;
178-
var traceHash = {};
179-
180-
for(i = 0; i < geoCalcData.length; i++) {
181-
var calcData = geoCalcData[i],
182-
trace = calcData[0].trace;
183-
184-
traceHash[trace.type] = traceHash[trace.type] || [];
185-
traceHash[trace.type].push(calcData);
186-
}
187-
188-
var moduleNamesOld = Object.keys(traceHashOld);
189-
var moduleNames = Object.keys(traceHash);
190-
191-
// when a trace gets deleted, make sure that its module's
192-
// plot method is called so that it is properly
193-
// removed from the DOM.
194-
for(i = 0; i < moduleNamesOld.length; i++) {
195-
var moduleName = moduleNamesOld[i];
196-
197-
if(moduleNames.indexOf(moduleName) === -1) {
198-
var fakeCalcTrace = traceHashOld[moduleName][0],
199-
fakeTrace = fakeCalcTrace[0].trace;
200-
201-
fakeTrace.visible = false;
202-
traceHash[moduleName] = [fakeCalcTrace];
203-
}
204-
}
205-
206-
moduleNames = Object.keys(traceHash);
207-
208-
for(i = 0; i < moduleNames.length; i++) {
209-
var moduleCalcData = traceHash[moduleNames[i]],
210-
_module = moduleCalcData[0][0].trace._module;
211-
212-
_module.plot(this, filterVisible(moduleCalcData), geoLayout);
213-
}
214-
215-
this.traceHash = traceHash;
176+
Plots.generalUpdatePerTraceModule(this, geoCalcData, geoLayout);
216177

217178
this.render();
218179
};
219180

220-
function filterVisible(calcDataIn) {
221-
var calcDataOut = [];
222-
223-
for(var i = 0; i < calcDataIn.length; i++) {
224-
var calcTrace = calcDataIn[i],
225-
trace = calcTrace[0].trace;
226-
227-
if(trace.visible === true) calcDataOut.push(calcTrace);
228-
}
229-
230-
return calcDataOut;
231-
}
232-
233181
proto.updateFx = function(hovermode) {
234182
this.showHover = (hovermode !== false);
235183

src/plots/plots.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2052,3 +2052,67 @@ plots.doCalcdata = function(gd, traces) {
20522052
calcdata[i] = cd;
20532053
}
20542054
};
2055+
2056+
plots.generalUpdatePerTraceModule = function(subplot, subplotCalcData, subplotLayout) {
2057+
var traceHashOld = subplot.traceHash,
2058+
traceHash = {},
2059+
i;
2060+
2061+
function filterVisible(calcDataIn) {
2062+
var calcDataOut = [];
2063+
2064+
for(var i = 0; i < calcDataIn.length; i++) {
2065+
var calcTrace = calcDataIn[i],
2066+
trace = calcTrace[0].trace;
2067+
2068+
if(trace.visible === true) calcDataOut.push(calcTrace);
2069+
}
2070+
2071+
return calcDataOut;
2072+
}
2073+
2074+
// build up moduleName -> calcData hash
2075+
for(i = 0; i < subplotCalcData.length; i++) {
2076+
var calcTraces = subplotCalcData[i],
2077+
trace = calcTraces[0].trace;
2078+
2079+
// skip over visible === false traces
2080+
// as they don't have `_module` ref
2081+
if(trace.visible) {
2082+
traceHash[trace.type] = traceHash[trace.type] || [];
2083+
traceHash[trace.type].push(calcTraces);
2084+
}
2085+
}
2086+
2087+
var moduleNamesOld = Object.keys(traceHashOld);
2088+
var moduleNames = Object.keys(traceHash);
2089+
2090+
// when a trace gets deleted, make sure that its module's
2091+
// plot method is called so that it is properly
2092+
// removed from the DOM.
2093+
for(i = 0; i < moduleNamesOld.length; i++) {
2094+
var moduleName = moduleNamesOld[i];
2095+
2096+
if(moduleNames.indexOf(moduleName) === -1) {
2097+
var fakeCalcTrace = traceHashOld[moduleName][0],
2098+
fakeTrace = fakeCalcTrace[0].trace;
2099+
2100+
fakeTrace.visible = false;
2101+
traceHash[moduleName] = [fakeCalcTrace];
2102+
}
2103+
}
2104+
2105+
// update list of module names to include 'fake' traces added above
2106+
moduleNames = Object.keys(traceHash);
2107+
2108+
// call module plot method
2109+
for(i = 0; i < moduleNames.length; i++) {
2110+
var moduleCalcData = traceHash[moduleNames[i]],
2111+
_module = moduleCalcData[0][0].trace._module;
2112+
2113+
_module.plot(subplot, filterVisible(moduleCalcData), subplotLayout);
2114+
}
2115+
2116+
// update moduleName -> calcData hash
2117+
subplot.traceHash = traceHash;
2118+
};

test/jasmine/tests/plots_test.js

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,4 +582,114 @@ describe('Test Plots', function() {
582582
});
583583
});
584584

585+
describe('Plots.generalUpdatePerTraceModule', function() {
586+
587+
function _update(subplotCalcData, traceHashOld) {
588+
var subplot = { traceHash: traceHashOld || {} };
589+
var calcDataPerModule = [];
590+
591+
var plot = function(_, moduleCalcData) {
592+
calcDataPerModule.push(moduleCalcData);
593+
};
594+
595+
subplotCalcData.forEach(function(calcTrace) {
596+
calcTrace[0].trace._module = { plot: plot };
597+
});
598+
599+
Plots.generalUpdatePerTraceModule(subplot, subplotCalcData, {});
600+
601+
return {
602+
traceHash: subplot.traceHash,
603+
calcDataPerModule: calcDataPerModule
604+
};
605+
}
606+
607+
it('should update subplot trace hash and call module plot method with correct calcdata traces', function() {
608+
var out = _update([
609+
[ { trace: { type: 'A', visible: false } } ],
610+
[ { trace: { type: 'A', visible: true } } ],
611+
[ { trace: { type: 'B', visible: false } } ],
612+
[ { trace: { type: 'C', visible: true } } ]
613+
]);
614+
615+
expect(Object.keys(out.traceHash)).toEqual(['A', 'C']);
616+
expect(out.traceHash.A.length).toEqual(1);
617+
expect(out.traceHash.C.length).toEqual(1);
618+
619+
expect(out.calcDataPerModule.length).toEqual(2);
620+
expect(out.calcDataPerModule[0].length).toEqual(1);
621+
expect(out.calcDataPerModule[1].length).toEqual(1);
622+
623+
var out2 = _update([
624+
[ { trace: { type: 'A', visible: false } } ],
625+
[ { trace: { type: 'A', visible: false } } ],
626+
[ { trace: { type: 'B', visible: true } } ],
627+
[ { trace: { type: 'C', visible: false } } ]
628+
], out.traceHash);
629+
630+
expect(Object.keys(out2.traceHash)).toEqual(['B', 'A', 'C']);
631+
expect(out2.traceHash.B.length).toEqual(1);
632+
expect(out2.traceHash.A.length).toEqual(1);
633+
expect(out2.traceHash.A[0][0].trace.visible).toBe(false);
634+
expect(out2.traceHash.C.length).toEqual(1);
635+
expect(out2.traceHash.C[0][0].trace.visible).toBe(false);
636+
637+
expect(out2.calcDataPerModule.length).toEqual(1);
638+
expect(out2.calcDataPerModule[0].length).toEqual(1);
639+
640+
var out3 = _update([
641+
[ { trace: { type: 'A', visible: false } } ],
642+
[ { trace: { type: 'A', visible: false } } ],
643+
[ { trace: { type: 'B', visible: false } } ],
644+
[ { trace: { type: 'C', visible: false } } ]
645+
], out2.traceHash);
646+
647+
expect(Object.keys(out3.traceHash)).toEqual(['B', 'A', 'C']);
648+
expect(out3.traceHash.B.length).toEqual(1);
649+
expect(out3.traceHash.B[0][0].trace.visible).toBe(false);
650+
expect(out3.traceHash.A.length).toEqual(1);
651+
expect(out3.traceHash.A[0][0].trace.visible).toBe(false);
652+
expect(out3.traceHash.C.length).toEqual(1);
653+
expect(out3.traceHash.C[0][0].trace.visible).toBe(false);
654+
655+
expect(out3.calcDataPerModule.length).toEqual(0);
656+
657+
var out4 = _update([
658+
[ { trace: { type: 'A', visible: true } } ],
659+
[ { trace: { type: 'A', visible: true } } ],
660+
[ { trace: { type: 'B', visible: true } } ],
661+
[ { trace: { type: 'C', visible: true } } ]
662+
], out3.traceHash);
663+
664+
expect(Object.keys(out4.traceHash)).toEqual(['A', 'B', 'C']);
665+
expect(out4.traceHash.A.length).toEqual(2);
666+
expect(out4.traceHash.B.length).toEqual(1);
667+
expect(out4.traceHash.C.length).toEqual(1);
668+
669+
expect(out4.calcDataPerModule.length).toEqual(3);
670+
expect(out4.calcDataPerModule[0].length).toEqual(2);
671+
expect(out4.calcDataPerModule[1].length).toEqual(1);
672+
expect(out4.calcDataPerModule[2].length).toEqual(1);
673+
});
674+
675+
it('should handle cases when module plot is not set (geo case)', function(done) {
676+
Plotly.plot(createGraphDiv(), [{
677+
type: 'scattergeo',
678+
visible: false,
679+
lon: [10, 20],
680+
lat: [20, 10]
681+
}, {
682+
type: 'scattergeo',
683+
lon: [10, 20],
684+
lat: [20, 10]
685+
}])
686+
.then(function() {
687+
expect(d3.selectAll('g.trace.scattergeo').size()).toEqual(1);
688+
689+
destroyGraphDiv();
690+
done();
691+
});
692+
});
693+
694+
});
585695
});

0 commit comments

Comments
 (0)