diff --git a/src/components/rangeslider/constants.js b/src/components/rangeslider/constants.js index b43e7f89df1..b7cabcccac2 100644 --- a/src/components/rangeslider/constants.js +++ b/src/components/rangeslider/constants.js @@ -41,13 +41,10 @@ module.exports = { grabAreaFill: 'transparent', grabAreaCursor: 'col-resize', grabAreaWidth: 10, - grabAreaMinOffset: -6, - grabAreaMaxOffset: -2, - handleWidth: 2, + handleWidth: 4, handleRadius: 1, - handleFill: '#fff', - handleStroke: '#666', + handleStrokeWidth: 1, extraPad: 15 }; diff --git a/src/components/rangeslider/draw.js b/src/components/rangeslider/draw.js index 731edd0b313..970832da15b 100644 --- a/src/components/rangeslider/draw.js +++ b/src/components/rangeslider/draw.js @@ -95,9 +95,9 @@ module.exports = function(gd) { opts._height = (fullLayout.height - margin.b - margin.t) * opts.thickness; opts._offsetShift = Math.floor(opts.borderwidth / 2); - var x = margin.l + (graphSize.w * domain[0]); + var x = Math.round(margin.l + (graphSize.w * domain[0])); - var y = ( + var y = Math.round( margin.t + graphSize.h * (1 - oppDomain[0]) + tickHeight + opts._offsetShift + constants.extraPad @@ -252,11 +252,16 @@ function setDataRange(rangeSlider, gd, axisOpts, opts) { } function setPixelRange(rangeSlider, gd, axisOpts, opts) { + var hw2 = constants.handleWidth / 2; function clamp(v) { return Lib.constrain(v, 0, opts._width); } + function clampHandle(v) { + return Lib.constrain(v, -hw2, opts._width + hw2); + } + var pixelMin = clamp(opts.d2p(axisOpts._rl[0])), pixelMax = clamp(opts.d2p(axisOpts._rl[1])); @@ -271,11 +276,17 @@ function setPixelRange(rangeSlider, gd, axisOpts, opts) { .attr('x', pixelMax) .attr('width', opts._width - pixelMax); + // .. + var offset = 0.5; + + var xMin = Math.round(clampHandle(pixelMin - hw2)) - offset, + xMax = Math.round(clampHandle(pixelMax - hw2)) + offset; + rangeSlider.select('g.' + constants.grabberMinClassName) - .attr('transform', 'translate(' + (pixelMin - constants.handleWidth - 1) + ',0)'); + .attr('transform', 'translate(' + xMin + ',' + offset + ')'); rangeSlider.select('g.' + constants.grabberMaxClassName) - .attr('transform', 'translate(' + pixelMax + ',0)'); + .attr('transform', 'translate(' + xMax + ',' + offset + ')'); } function drawBg(rangeSlider, gd, axisOpts, opts) { @@ -295,6 +306,7 @@ function drawBg(rangeSlider, gd, axisOpts, opts) { opts.borderwidth - 1; var offsetShift = -opts._offsetShift; + var lw = Drawing.crispRound(gd, opts.borderwidth); bg.attr({ width: opts._width + borderCorrect, @@ -302,7 +314,7 @@ function drawBg(rangeSlider, gd, axisOpts, opts) { transform: 'translate(' + offsetShift + ',' + offsetShift + ')', fill: opts.bgcolor, stroke: opts.bordercolor, - 'stroke-width': opts.borderwidth, + 'stroke-width': lw }); } @@ -415,7 +427,8 @@ function drawMasks(rangeSlider, gd, axisOpts, opts) { maskMin.enter().append('rect') .classed(constants.maskMinClassName, true) - .attr({ x: 0, y: 0 }); + .attr({ x: 0, y: 0 }) + .attr('shape-rendering', 'crispEdges'); maskMin .attr('height', opts._height) @@ -426,7 +439,8 @@ function drawMasks(rangeSlider, gd, axisOpts, opts) { maskMax.enter().append('rect') .classed(constants.maskMaxClassName, true) - .attr('y', 0); + .attr('y', 0) + .attr('shape-rendering', 'crispEdges'); maskMax .attr('height', opts._height) @@ -442,7 +456,8 @@ function drawSlideBox(rangeSlider, gd, axisOpts, opts) { slideBox.enter().append('rect') .classed(constants.slideBoxClassName, true) .attr('y', 0) - .attr('cursor', constants.slideBoxCursor); + .attr('cursor', constants.slideBoxCursor) + .attr('shape-rendering', 'crispEdges'); slideBox.attr({ height: opts._height, @@ -470,14 +485,15 @@ function drawGrabbers(rangeSlider, gd, axisOpts, opts) { x: 0, width: constants.handleWidth, rx: constants.handleRadius, - fill: constants.handleFill, - stroke: constants.handleStroke, + fill: Color.background, + stroke: Color.defaultLine, + 'stroke-width': constants.handleStrokeWidth, 'shape-rendering': 'crispEdges' }; var handleDynamicAttrs = { - y: opts._height / 4, - height: opts._height / 2, + y: Math.round(opts._height / 4), + height: Math.round(opts._height / 2), }; var handleMin = grabberMin.selectAll('rect.' + constants.handleMinClassName) @@ -500,6 +516,7 @@ function drawGrabbers(rangeSlider, gd, axisOpts, opts) { var grabAreaFixAttrs = { width: constants.grabAreaWidth, + x: 0, y: 0, fill: constants.grabAreaFill, cursor: constants.grabAreaCursor @@ -510,20 +527,14 @@ function drawGrabbers(rangeSlider, gd, axisOpts, opts) { grabAreaMin.enter().append('rect') .classed(constants.grabAreaMinClassName, true) .attr(grabAreaFixAttrs); - grabAreaMin.attr({ - x: constants.grabAreaMinOffset, - height: opts._height - }); + grabAreaMin.attr('height', opts._height); var grabAreaMax = grabberMax.selectAll('rect.' + constants.grabAreaMaxClassName) .data([0]); grabAreaMax.enter().append('rect') .classed(constants.grabAreaMaxClassName, true) .attr(grabAreaFixAttrs); - grabAreaMax.attr({ - x: constants.grabAreaMaxOffset, - height: opts._height - }); + grabAreaMax.attr('height', opts._height); } function clearPushMargins(gd) { diff --git a/test/image/baselines/candlestick_double-y-axis.png b/test/image/baselines/candlestick_double-y-axis.png index 8c6c223bc13..9f96621d952 100644 Binary files a/test/image/baselines/candlestick_double-y-axis.png and b/test/image/baselines/candlestick_double-y-axis.png differ diff --git a/test/image/baselines/candlestick_rangeslider_thai.png b/test/image/baselines/candlestick_rangeslider_thai.png index 60880772a07..48682b25459 100644 Binary files a/test/image/baselines/candlestick_rangeslider_thai.png and b/test/image/baselines/candlestick_rangeslider_thai.png differ diff --git a/test/image/baselines/ohlc_first.png b/test/image/baselines/ohlc_first.png index 6d70e5176a3..1324765b138 100644 Binary files a/test/image/baselines/ohlc_first.png and b/test/image/baselines/ohlc_first.png differ diff --git a/test/image/baselines/range_slider.png b/test/image/baselines/range_slider.png index 2cdcd506c72..705a1a03e29 100644 Binary files a/test/image/baselines/range_slider.png and b/test/image/baselines/range_slider.png differ diff --git a/test/image/baselines/range_slider_axes_double.png b/test/image/baselines/range_slider_axes_double.png index e2d04a225cc..a944a7ad35c 100644 Binary files a/test/image/baselines/range_slider_axes_double.png and b/test/image/baselines/range_slider_axes_double.png differ diff --git a/test/image/baselines/range_slider_box.png b/test/image/baselines/range_slider_box.png index 983d97aa3e0..ad5a4aef193 100644 Binary files a/test/image/baselines/range_slider_box.png and b/test/image/baselines/range_slider_box.png differ diff --git a/test/image/baselines/range_slider_initial_expanded.png b/test/image/baselines/range_slider_initial_expanded.png index 9c42a69d37f..1f01352b5da 100644 Binary files a/test/image/baselines/range_slider_initial_expanded.png and b/test/image/baselines/range_slider_initial_expanded.png differ diff --git a/test/image/baselines/range_slider_initial_valid.png b/test/image/baselines/range_slider_initial_valid.png index c3e56c912af..1dc3f03000d 100644 Binary files a/test/image/baselines/range_slider_initial_valid.png and b/test/image/baselines/range_slider_initial_valid.png differ diff --git a/test/image/baselines/range_slider_multiple.png b/test/image/baselines/range_slider_multiple.png index cccb721de9a..49e835105b4 100644 Binary files a/test/image/baselines/range_slider_multiple.png and b/test/image/baselines/range_slider_multiple.png differ diff --git a/test/jasmine/tests/range_slider_test.js b/test/jasmine/tests/range_slider_test.js index bda4ec70f34..170f464e2e5 100644 --- a/test/jasmine/tests/range_slider_test.js +++ b/test/jasmine/tests/range_slider_test.js @@ -39,7 +39,7 @@ describe('the range slider', function() { var transformParts = node.getAttribute('transform').split('('); expect(transformParts[0]).toEqual('translate'); - expect(+transformParts[1].split(',0)')[0]).toBeWithin(val, TOL); + expect(+transformParts[1].split(',0.5)')[0]).toBeWithin(val, TOL); } describe('when specified as visible', function() { @@ -99,7 +99,7 @@ describe('the range slider', function() { expect(gd.layout.xaxis.range).toBeCloseToArray([4, 49], -0.5); expect(maskMin.getAttribute('width')).toEqual(String(diff)); - expect(handleMin.getAttribute('transform')).toBe('translate(' + (diff - 3) + ',0)'); + expect(handleMin.getAttribute('transform')).toBe('translate(' + (diff - 2.5) + ',0.5)'); }).then(done); }); @@ -204,7 +204,7 @@ describe('the range slider', function() { expect(+maskMin.getAttribute('width')).toBeWithin(126, TOL); expect(+maskMax.getAttribute('width')).toEqual(0); testTranslate1D(handleMin, 123.32); - testTranslate1D(handleMax, 619); + testTranslate1D(handleMax, 617); }) .then(done); });