Conversation
|
@rreusser can you share a few screenshots here for the design team? |
|
Note for design-oriented eyes: As mentioned above, a big thing that this currently needs is a readout of the current value, as in "Year: 1980". The best place is probably above or below the slider (not next to it!) because variable-length user input is a mess when there's not enough room for it. Thoughts welcome. Here's the slider at full size. It can be translated, but vertical orientation is not currently implemented. The play button is currently drawn next to it, but there is no general relation between the slider and buttons. Here it is at reduced size. The label size is calculated and it drops labels so that they don't overlap. You can also achieve other looks by messing with the constants. They're not currently editable by end-users, but they certainly could be: Ticks too. Just throwing out possibilities here… |
|
@etpinard Added mock. The big shortcoming is that it doesn't hook up to events since mocks don't work with animations. |
|
|
||
| function makeInputProxy(gd, sliderGroup, sliderOpts) { | ||
| sliderOpts.inputProxy = gd._fullLayout._paperdiv.selectAll('input.' + constants.inputProxyClass) | ||
| .data([0]); |
There was a problem hiding this comment.
This is not currently implemented. The idea is that it creates an <input type="range"> that captures focus (can it actually do that programatically?) so that accessibility things like keyboard arrows to change the slider position actually work. Just an idea. Might need to go.
| ].join(' ') | ||
| }, | ||
|
|
||
| transition: { |
There was a problem hiding this comment.
I kept this nested format so that it perfectly mirrors the way you'd define transition config for an animation. Otherwise it would need to be transitionduration: and transitioneasing:, which isn't bad. Open to thoughts here.
There was a problem hiding this comment.
👍 plotly.js is a big fan of nested attributes.
| sliders.exit().remove(); | ||
|
|
||
| // If no more sliders, clear the margisn: | ||
| if(sliders.exit().size()) clearPushMargins(gd); |
There was a problem hiding this comment.
When sliders disappear, it also needs to detach event subscriptions. That's very important! We should think about the proper way for components to do that in general.
| sliderOpts.inputAreaLength = Math.round(sliderOpts.outerLength - sliderOpts.xpad * 2); | ||
| sliderOpts.railInset = Math.round(Math.max(0, constants.gripWidth - constants.railWidth) * 0.5); | ||
| sliderOpts.stepInset = Math.round(Math.max(sliderOpts.railInset, constants.gripWidth * 0.5)); | ||
|
|
There was a problem hiding this comment.
The logic in this area needs to be 30% less fancy and 40% more directly controlled by constants.
src/components/slider/attributes.js
Outdated
| dflt: 'restyle', | ||
| role: 'info', | ||
| description: [ | ||
| 'Sets the Plotly method to be called on click.' |
There was a problem hiding this comment.
s/on click/on slide maybe?
src/components/slider/attributes.js
Outdated
|
|
||
| steps: stepsAttrs, | ||
|
|
||
| updateevent: { |
src/components/slider/attributes.js
Outdated
| 'value when an event of type `updateevent` is received. If', | ||
| 'undefined, the data argument itself is used. If a string,', | ||
| 'that property is used, and if a string with dots, e.g.', | ||
| '`item.0.label`, then `data[\'item\'][0][\'label\']` will', |
There was a problem hiding this comment.
Ok. Plotly.restyle and Plotly.relayout use use [] to delimit array items in an attribute string e.g. item[0].label via Lib.nestedProperty .
I believe the item.0.label is a little more clear. But, maybe we should stick to item[0].label for consistency?
src/components/slider/attributes.js
Outdated
| role: 'info', | ||
| dflt: 'fraction', | ||
| description: [ | ||
| 'Determines whether this color bar\'s length', |
There was a problem hiding this comment.
Haha I see, the descriptions were pasted over from other components.
src/components/slider/draw.js
Outdated
| return function(data) { | ||
| var value = data; | ||
| if(updatevalue) { | ||
| value = Lib.nestedProperty(data, updatevalue).get(); |
There was a problem hiding this comment.
wait does nestedProperty work with items.0.label signature?
There was a problem hiding this comment.
maybe I just didn't know about it.
There was a problem hiding this comment.
Ah, that's a good question… It may well not. I simply assumed (hoped?) it would. Thanks for noticing.
|
|
||
| // find item dimensions (this mutates menuOpts) | ||
| function findDimenstions(gd, menuOpts) { | ||
| function findDimensions(gd, menuOpts) { |
There was a problem hiding this comment.
Haha, I love finding typos and then finding the compensatory typos elsewhere…
src/components/slider/index.js
Outdated
|
|
||
| exports.moduleType = 'component'; | ||
|
|
||
| exports.name = 'slider'; |
There was a problem hiding this comment.
plural (to be consistent with layout.sliders
| }); | ||
| } | ||
|
|
||
| function drawTicks(sliderGroup, sliderOpts) { |
There was a problem hiding this comment.
Good enough for now i.e. no need to make the slider tick options on par with axis tick options (++ axes.js is most fun module to reuse).
There was a problem hiding this comment.
EDIT: (++ axes.js is not the most fun module to reuse)
There was a problem hiding this comment.
I didn't directly use axes.js since the options didn't perfectly map 1-1, but followed the naming conventions.
| item.on('mousedown', function() { | ||
| var grip = sliderGroup.select('.' + constants.gripRectClass); | ||
|
|
||
| d3.event.stopPropagation(); |
There was a problem hiding this comment.
we might want to use a coverSlip in the range slider part II here to avoid selecting other elements on the graph on drag.
There was a problem hiding this comment.
Ah but looks like d3.event.stopPropagation(); d3.event.preventDefault(); does the trick. Nevermind.
There was a problem hiding this comment.
Yeah, I wasn't 100% sure about my ad-hoc drag implementation. I feel like it ended up fairly concise, unsurprising, and reasonably robust, but I'm glad to refactor if there are helpers that manage some of this.
src/components/slider/draw.js
Outdated
|
|
||
| // Lib.setTranslate doesn't work here becasue of the transition duck-typing. | ||
| // It's also not necessary because there are no other transitions to preserve. | ||
| el.attr('transform', 'translate(' + (x - constants.gripWidth * 0.5) + ',' + 0 + ')'); |
|
would mind taking a look at #986 (comment) ? |
|
@etpinard thoughts on decircularizing requires vs. upping the circularity tolerance threshold? |
Every component that calls a That So, go ahead and bump |
|
Thanks @etpinard. Will gladly bump threshold! |
|
Love these sliders. 💃 from me on the design side. |
add streaming maxpoints max and dflt
|
@etpinard I've removed The baseline is now within the range of what can be styled: |
| description: 'Sets the width (in px) of the border enclosing the slider.' | ||
| } | ||
| }, | ||
| ticklen: { |
| Lib.coerceFont(coerce, 'currentvalue.font', layoutOut.font); | ||
|
|
||
| coerce('bgcolor', layoutOut.paper_bgcolor); | ||
| coerce('bgcolor'); |
There was a problem hiding this comment.
I see the default bgcolor isn't inherited from layoutOut.paper_bgcolor anymore. Is this on purpose?
There was a problem hiding this comment.
No good reason except that it didn't actually seem like a desirable default since that would just make the slider transparent-looking instead of filled by default.
There was a problem hiding this comment.
To elaborate slightly, this attribute wasn't used before. Until today it was a hard-coded constant.
There was a problem hiding this comment.
it didn't actually seem like a desirable default
I agree 100%. I just wanted to make sure the above patch was not a typo 👍
|
|
||
| xanchor: { | ||
| valType: 'enumerated', | ||
| values: ['left', 'center', 'right'], |
There was a problem hiding this comment.
yep, nice job dropping the 'auto' value here.
| ].join(' ') | ||
| }, | ||
|
|
||
| prefix: { |
There was a problem hiding this comment.
We should probably add a suffix attribute too.
There was a problem hiding this comment.
Sounds good. Good idea.
src/components/sliders/defaults.js
Outdated
| coerce('currentvalue.visible'); | ||
| coerce('currentvalue.xanchor'); | ||
| coerce('currentvalue.prefix'); | ||
| coerce('currentvalue.offset'); |
There was a problem hiding this comment.
this should be:
var currentValue = coerce('currentvalue.visible');
if(currentValue) {
coerce('currentvalue.xanchor');
coerce('currentvalue.prefix');
coerce('currentvalue.offset');
}so that Plotly.validate can detect e.g.
layout.sliders = [{
currentvalue: {
visible: false,
xanchor: 'left'
}];
// => `xanchor` has no effects
src/components/sliders/defaults.js
Outdated
| coerce('minorticklen'); | ||
|
|
||
| Lib.coerceFont(coerce, 'font', layoutOut.font); | ||
| Lib.coerceFont(coerce, 'currentvalue.font', sliderOut.font); |
There was a problem hiding this comment.
similarly here, Lib.coerceFont(coerce, 'currentvalue.font', sliderOut.font); should only get coerced if currentvalue.visible is true.
| @@ -0,0 +1,172 @@ | |||
| { | |||
| "data": [ | |||
There was a problem hiding this comment.
Goal: hit as many properties as possible to avoid testing styles in jasmine.
| expect(error).toBeUndefined(); | ||
| } | ||
| if(error && error.stack) { | ||
| console.error(error.stack); |
| var destroyGraphDiv = require('../assets/destroy_graph_div'); | ||
| var fail = require('../assets/fail_test'); | ||
|
|
||
| describe('sliders defaults', function() { |
There was a problem hiding this comment.
TODO:
- add one defaults around
currentvalue.visible-> othercurrentvaluenested attributes
| }); | ||
| }); | ||
|
|
||
| describe('update sliders interactions', function() { |
There was a problem hiding this comment.
Have you thought about adding mouse interaction tests?
It should be doable to mock a drag interaction using new MouseEvent - unless there are complications that I can't think about.
| expect(mockCopy.layout.sliders[0].active).toEqual(0); | ||
|
|
||
| done(); | ||
| }, 100); |
There was a problem hiding this comment.
Very nice. That's all I wanted. Thanks for taking the time to do this 🎉
There was a problem hiding this comment.
No prob. Wasn't too bad; just hadn't previously tried mocking mouse events and positions.
I have no strong opinion about this. I'll you decide what's best. |
|
I think it's fine as-is. I thought it would be preferable to completely right-justifying the text it since this cuts down on unneeded movement as you change the slider. |
|
@rreusser I'll attach the gif here for reference: looks like some race condition exist makes the That happen once and I can't replicate it though. So, let's merge this in 💃 whenever you're happy with it. |
|
Because it's particularly evasive (race condition?), @etpinard noted a layout issue that's captured here: I think this was an issue with bounding box computation returning null and the sizes not actually being numbers. The last commit on this PR should fix that, but just adding here for reference in case it pops up again. |










This PR implements a first cut at sliders #742
cc @etpinard
It has most of the necessary features (including hooking into the internal event dispatcher 🎉) and seems reasonably stable. It needs:
Notable features: