Skip to content

Commit 138d6c3

Browse files
committed
added "half selection", improved drag behavior...
... and real-time query updates during dragging.
1 parent 5a819fc commit 138d6c3

File tree

7 files changed

+89
-15
lines changed

7 files changed

+89
-15
lines changed

src/minicharts/d3fns/few.js

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ var minicharts_d3fns_few = function() {
1212
var width = 400;
1313
var height = 100;
1414
var barHeight = 25;
15+
var brushHeight = 80;
1516
var options = {
1617
view: null
1718
};
@@ -43,8 +44,21 @@ var minicharts_d3fns_few = function() {
4344
options.view.trigger('querybuilder', evt);
4445
}
4546

47+
function brushstart(clickedBar) {
48+
// remove selections and half selections
49+
var bars = d3.selectAll(options.view.queryAll('rect.selectable'));
50+
bars.classed('half', false);
51+
bars.classed('selected', function() {
52+
return this === clickedBar;
53+
});
54+
bars.classed('unselected', function() {
55+
return this !== clickedBar;
56+
});
57+
}
58+
4659
function brushed() {
4760
var bars = d3.selectAll(options.view.queryAll('rect.selectable'));
61+
var numSelected = options.view.queryAll('rect.selectable.selected').length;
4862
var s = brush.extent();
4963

5064
bars.classed('selected', function(d) {
@@ -57,6 +71,16 @@ var minicharts_d3fns_few = function() {
5771
var right = left + d.count;
5872
return s[0] > right || left > s[1];
5973
});
74+
75+
if (!options.view) return;
76+
if (numSelected !== options.view.queryAll('rect.selectable.selected').length) {
77+
// number of selected items has changed, trigger querybuilder event
78+
var evt = {
79+
type: 'drag',
80+
source: 'many'
81+
};
82+
options.view.trigger('querybuilder', evt);
83+
}
6084
}
6185

6286
function brushend() {
@@ -77,10 +101,12 @@ var minicharts_d3fns_few = function() {
77101

78102
function handleMouseDown() {
79103
var bar = this;
104+
var rect = $(this).find('rect.selectable')[0];
80105
var parent = $(this).closest('.minichart');
81106
var background = parent.find('g.brush > rect.background')[0];
82107
var brushNode = parent.find('g.brush')[0];
83108
var start = xScale.invert(d3.mouse(background)[0]);
109+
brushstart.call(brushNode, rect);
84110

85111
var w = d3.select(window)
86112
.on('mousemove', mousemove)
@@ -135,8 +161,8 @@ var minicharts_d3fns_few = function() {
135161
.attr('class', 'brush')
136162
.call(brush)
137163
.selectAll('rect')
138-
.attr('y', 0)
139-
.attr('height', height);
164+
.attr('y', (height - brushHeight) / 2)
165+
.attr('height', brushHeight);
140166

141167
// select all g.bar elements
142168
var bar = el.selectAll('g.bar')
@@ -160,8 +186,8 @@ var minicharts_d3fns_few = function() {
160186
);
161187
d.xpos = xpos;
162188
return 'translate(' + xScale(xpos) + ', ' + (height - barHeight) / 2 + ')';
163-
});
164-
189+
})
190+
.on('mousedown', handleMouseDown);
165191

166192
barEnter.append('rect')
167193
.attr('class', function(d, i) {
@@ -184,8 +210,7 @@ var minicharts_d3fns_few = function() {
184210
.attr('x', 0)
185211
.attr('height', barHeight)
186212
.on('mouseover', tip.show)
187-
.on('mouseout', tip.hide)
188-
.on('mousedown', handleMouseDown);
213+
.on('mouseout', tip.hide);
189214

190215
bar.select('rect.selectable')
191216
.transition()

src/minicharts/d3fns/many.js

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ var $ = require('jquery');
33
var _ = require('lodash');
44
var tooltipHtml = require('./tooltip.jade');
55
var shared = require('./shared');
6-
// var debug = require('debug')('scout:minicharts:many');
6+
var debug = require('debug')('scout:minicharts:many');
77

88
require('../d3-tip')(d3);
99

@@ -31,6 +31,7 @@ var minicharts_d3fns_many = function() {
3131

3232
var brush = d3.svg.brush()
3333
.x(xScale)
34+
.on('brushstart', brushstart)
3435
.on('brush', brushed)
3536
.on('brushend', brushend);
3637
// --- end chart setup ---
@@ -47,8 +48,21 @@ var minicharts_d3fns_many = function() {
4748
options.view.trigger('querybuilder', evt);
4849
}
4950

51+
function brushstart(clickedBar) {
52+
// remove selections and half selections
53+
var bars = d3.selectAll(options.view.queryAll('rect.selectable'));
54+
bars.classed('half', false);
55+
bars.classed('selected', function() {
56+
return this === clickedBar;
57+
});
58+
bars.classed('unselected', function() {
59+
return this !== clickedBar;
60+
});
61+
}
62+
5063
function brushed() {
5164
var bars = d3.selectAll(options.view.queryAll('rect.selectable'));
65+
var numSelected = options.view.queryAll('rect.selectable.selected').length;
5266
var s = brush.extent();
5367

5468
bars.classed('selected', function(d) {
@@ -61,6 +75,16 @@ var minicharts_d3fns_many = function() {
6175
var right = left + xScale.rangeBand();
6276
return s[0] > right || left > s[1];
6377
});
78+
79+
if (!options.view) return;
80+
if (numSelected !== options.view.queryAll('rect.selectable.selected').length) {
81+
// number of selected items has changed, trigger querybuilder event
82+
var evt = {
83+
type: 'drag',
84+
source: 'many'
85+
};
86+
options.view.trigger('querybuilder', evt);
87+
}
6488
}
6589

6690
function brushend() {
@@ -86,6 +110,7 @@ var minicharts_d3fns_many = function() {
86110
var background = parent.find('g.brush > rect.background')[0];
87111
var brushNode = parent.find('g.brush')[0];
88112
var start = d3.mouse(background)[0];
113+
brushstart.call(brushNode, bar);
89114

90115
var w = d3.select(window)
91116
.on('mousemove', mousemove)
@@ -265,12 +290,12 @@ var minicharts_d3fns_many = function() {
265290
// .on('mousedown', handleMouseDown)
266291
} else {
267292
// ... or attach tooltips directly to foreground bars if we don't use background bars
268-
bar.selectAll('.fg')
293+
barEnter.selectAll('.fg')
269294
.on('mouseover', tip.show)
270295
.on('mouseout', tip.hide);
271296

272297
if (options.selectable) {
273-
bar.on('mousedown', handleMouseDown);
298+
barEnter.selectAll('.selectable').on('mousedown', handleMouseDown);
274299
}
275300
}
276301

src/minicharts/index.less

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88

99
@mc-bg: @gray8;
1010
@mc-fg: @mc-blue0;
11-
@mc-fg-selected: @chart0; // darken(@mc-blue0, 10%);
11+
@mc-fg-selected: @chart0;
12+
@mc-fg-halfselected: lighten(@chart0, 20%);
1213
@mc-fg-unselected: @gray6;
1314

1415
div.minichart.unique {
@@ -108,10 +109,11 @@ svg.minichart {
108109

109110
&.selected {
110111
fill: @mc-fg-selected;
111-
// stroke: @pw;
112-
// stroke-width: 1;
113-
// stroke-dasharray: 1,1;
112+
&.half {
113+
mask: url(#mask-stripe);
114+
}
114115
}
116+
115117
&.unselected {
116118
fill: @mc-fg-unselected;
117119
}

src/minicharts/querybuilder.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ module.exports = {
6868
this['buildQuery_' + queryType]();
6969
this['updateUI_' + queryType]();
7070
}
71+
72+
// setTimeout(function() {
73+
// this.selectedValues = [13, 39];
74+
// this.buildQuery_range();
75+
// this.updateUI_range();
76+
// }.bind(this), 2000);
7177
},
7278

7379
/**
@@ -209,6 +215,7 @@ module.exports = {
209215
var uiElements = this.queryAll('.selectable');
210216
_.each(uiElements, function(el) {
211217
el.classList.remove('selected');
218+
el.classList.remove('half');
212219
if (!firstSelected) {
213220
el.classList.remove('unselected');
214221
} else {
@@ -232,6 +239,15 @@ module.exports = {
232239
el.classList.remove('unselected');
233240
}
234241
});
242+
243+
// if last bar is not fully included in range, mark it as "half selected"
244+
if (res.isBinned) {
245+
var last = _.last(this.queryAll('.selectable.selected'));
246+
var lastData = d3.select(last).data()[0];
247+
if (lastData.value + lastData.dx > res.upper) {
248+
last.classList.add('half');
249+
}
250+
}
235251
}
236252
},
237253

src/minicharts/svg-template.jade

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
svg(data-hook='viz-container')
2+
defs
3+
pattern(id='diagonal-stripes', width='4', height='4', patternUnits='userSpaceOnUse', patternTransform='rotate(45)')
4+
rect(width='2.5', height='4', transform='translate(0,0)', fill='white')
5+
mask(id='mask-stripe')
6+
rect(x='0', y='0', width='100%', height='100%', fill='url(#diagonal-stripes)')

src/minicharts/viz.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ var VizView = AmpersandView.extend({
9393
this.template = '<canvas data-hook="viz-container" id="canvas"></canvas>';
9494
break;
9595
case 'svg':
96-
this.template = '<svg data-hook="viz-container"></svg>';
96+
this.template = require('./svg-template.jade');
9797
break;
9898
case 'html':
9999
default:

src/refine-view/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ module.exports = AmpersandView.extend({
101101
submit: function(evt) {
102102
evt.preventDefault();
103103
if (this.valid) {
104-
this.buttonClicked();
104+
this.refineClicked();
105105
}
106106
}
107107
});

0 commit comments

Comments
 (0)