diff --git a/srcjs/output_binding_image.js b/srcjs/output_binding_image.js index 86b91a48d..3e9f31071 100644 --- a/srcjs/output_binding_image.js +++ b/srcjs/output_binding_image.js @@ -182,14 +182,17 @@ imageutils.createCoordMapper = function($el, coordmap) { }; } - function _pxToData(px, domainMin, domainMax, rangeMin, rangeMax, clip) { - var val = px - rangeMin; - var factor = (domainMax - domainMin) / (rangeMax - rangeMin); - var newval = (val * factor) + domainMin; + // Map a value x from a domain to a range. If the domain is in data space and + // range is in px, this is scaling. If the reverse, then this is inverse + // scaling. + function _map(x, domainMin, domainMax, rangeMin, rangeMax, clip) { + var factor = (rangeMax - rangeMin) / (domainMax - domainMin); + var val = x - domainMin; + var newval = (val * factor) + rangeMin; if (clip) { - var max = Math.max(domainMax, domainMin); - var min = Math.min(domainMax, domainMin); + var max = Math.max(rangeMax, rangeMin); + var min = Math.min(rangeMax, rangeMin); if (newval > max) newval = max; else if (newval < min) @@ -223,14 +226,14 @@ imageutils.createCoordMapper = function($el, coordmap) { } // Transform offset coordinates to data space coordinates - function scale(offset, panel, clip) { + function scaleInv(offset, panel, clip) { // By default, clip to plotting region clip = clip || true; var d = panel.domain; var r = panel.range; - var userX = _pxToData(offset.x, d.left, d.right, r.left, r.right, clip); - var userY = _pxToData(offset.y, d.bottom, d.top, r.bottom, r.top, clip); + var userX = _map(offset.x, r.left, r.right, d.left, d.right, clip); + var userY = _map(offset.y, r.bottom, r.top, d.bottom, d.top, clip); if (panel.log) { if (panel.log.x) @@ -245,6 +248,27 @@ imageutils.createCoordMapper = function($el, coordmap) { }; } + // Transform offset coordinates to data space coordinates, for a box + function scaleInvBox(box, panel, clip) { + var min = scaleInv({ x: box.xmin, y: box.ymin }, panel, clip); + var max = scaleInv({ x: box.xmax, y: box.ymax }, panel, clip); + return { + xmin: min.x, + xmax: max.x, + ymin: min.y, + ymax: max.y + }; + } + + // Transform data space coordinates to offset coordinates + function scale(offset, panel, clip) { + // By default, clip to plotting region + clip = clip || true; + + + + } + // Given an offset, return an object representing which panel it's in. function getPanel(offset, expand) { expand = expand || 0; @@ -313,7 +337,7 @@ imageutils.createCoordMapper = function($el, coordmap) { if (clip && !isInPanel(offset)) return; var panel = getPanel(offset); - var coords = scale(offset, panel); + var coords = scaleInv(offset, panel); // Add the panel (facet) variables, if present if (panel.vars) { @@ -333,7 +357,8 @@ imageutils.createCoordMapper = function($el, coordmap) { mouseOffset: mouseOffset, findBox: findBox, shiftToRange: shiftToRange, - scale: scale, + scaleInv: scaleInv, + scaleInvBox: scaleInvBox, getPanel: getPanel, isInPanel: isInPanel, clipToBounds: clipToBounds, @@ -501,7 +526,7 @@ imageutils.createBrushHandler = function(inputId, $el, opts, mapper) { } function sendBrushInfo() { - var bounds = brush.bounds(); + var bounds = brush.boundsPx(); // We're in a new or reset state if (isNaN(bounds.xmin)) { @@ -510,9 +535,10 @@ imageutils.createBrushHandler = function(inputId, $el, opts, mapper) { } // Transform coordinates of brush to data space + // TODO: remove this - use brush API var panel = mapper.getPanel({ x: bounds.xmin, y: bounds.ymin }); - var min = mapper.scale({ x: bounds.xmin, y: bounds.ymin }, panel, opts.brushClip); - var max = mapper.scale({ x: bounds.xmax, y: bounds.ymax }, panel, opts.brushClip); + var min = mapper.scaleInv({ x: bounds.xmin, y: bounds.ymin }, panel, opts.brushClip); + var max = mapper.scaleInv({ x: bounds.xmax, y: bounds.ymax }, panel, opts.brushClip); // Because the x and y directions of the pixel space may differ from // the x and y directions of the data space, we need to recalculate @@ -695,8 +721,16 @@ imageutils.createBrush = function($el, opts, mapper) { state.down = { x: NaN, y: NaN }; state.up = { x: NaN, y: NaN }; - // Bounding rectangle of the brush - state.bounds = { + // Bounding rectangle of the brush, in pixel and data dimensions. We need to + // record data dimensions along with pixel dimensions so that when a new + // plot is sent, we can re-draw the brush div with the appropriate coords. + state.boundsPx = { + xmin: NaN, + xmax: NaN, + ymin: NaN, + ymax: NaN + }; + state.boundsData = { xmin: NaN, xmax: NaN, ymin: NaN, @@ -727,11 +761,25 @@ imageutils.createBrush = function($el, opts, mapper) { var elOffset = $el.offset(); var divOffset = oldDiv.offset(); - state.bounds = { - xmin: divOffset.left - elOffset.left, - xmax: divOffset.left - elOffset.left + oldDiv.width(), - ymin: divOffset.top - elOffset.top, - ymax: divOffset.top - elOffset.top + oldDiv.height() + var min = { + x: divOffset.left - elOffset.left, + y: divOffset.top - elOffset.top + }; + var max = { + x: divOffset.left - elOffset.left + oldDiv.width(), + y: divOffset.top - elOffset.top + oldDiv.height() + }; + + // Check that the min and max are in the same panel. This is needed because + // then panel dimensions could change. + // minPanel mapper.getPanel(min); + // mapper + + state.boundsPx = { + xmin: min.x, + xmax: max.x, + ymin: min.y, + ymax: max.y }; $div = oldDiv; @@ -739,7 +787,7 @@ imageutils.createBrush = function($el, opts, mapper) { // Return true if the offset is inside min/max coords function isInsideBrush(offset) { - var bounds = state.bounds; + var bounds = state.boundsPx; return offset.x <= bounds.xmax && offset.x >= bounds.xmin && offset.y <= bounds.ymax && offset.y >= bounds.ymin; } @@ -749,9 +797,9 @@ imageutils.createBrush = function($el, opts, mapper) { // This knows whether we're brushing in the x, y, or xy directions, and sets // bounds accordingly. // If no box is passed in, return current bounds. - function bounds(box) { + function boundsPx(box) { if (box === undefined) - return state.bounds; + return state.boundsPx; var min = { x: box.xmin, y: box.ymin }; var max = { x: box.xmax, y: box.ymax }; @@ -776,7 +824,7 @@ imageutils.createBrush = function($el, opts, mapper) { max.x = panelBounds.right; } - state.bounds = { + state.boundsPx = { xmin: min.x, xmax: max.x, ymin: min.y, @@ -784,6 +832,15 @@ imageutils.createBrush = function($el, opts, mapper) { }; } + // Get or set the bounds of the brush using coordinates in the data space. + function boundsScaled(box) { + if (box === undefined) { + mapper.scaleInvBox(boundsPx()); + } + + mapper.scaleInvBox(boundsPx()); + } + // Add a new div representing the brush. function addDiv() { if ($div) $div.remove(); @@ -815,7 +872,7 @@ imageutils.createBrush = function($el, opts, mapper) { } $el.append($div); - $div.offset({x:0, y:0}).width(0).height(0).show(); + $div.offset({x:0, y:0}).width(0).outerHeight(0).show(); } // Update the brush div to reflect the current brush bounds. @@ -823,7 +880,7 @@ imageutils.createBrush = function($el, opts, mapper) { // Need parent offset relative to page to calculate mouse offset // relative to page. var imgOffset = $el.offset(); - var b = state.bounds; + var b = state.boundsPx; $div.offset({ top: imgOffset.top + b.ymin, left: imgOffset.left + b.xmin @@ -856,12 +913,12 @@ imageutils.createBrush = function($el, opts, mapper) { addDiv(); state.panel = mapper.getPanel(state.down); - bounds(mapper.findBox(state.down, state.down)); + boundsPx(mapper.findBox(state.down, state.down)); updateDiv(); } function brushTo(offset) { - bounds(mapper.findBox(state.down, offset)); + boundsPx(mapper.findBox(state.down, offset)); updateDiv(); } @@ -869,7 +926,7 @@ imageutils.createBrush = function($el, opts, mapper) { state.brushing = false; // Save the final bounding box of the brush - bounds(mapper.findBox(state.down, state.up)); + boundsPx(mapper.findBox(state.down, state.up)); } function isDragging() { @@ -878,7 +935,7 @@ imageutils.createBrush = function($el, opts, mapper) { function startDragging() { state.dragging = true; - state.dragStartBounds = $.extend({}, state.bounds); + state.dragStartBounds = $.extend({}, state.boundsPx); } function dragTo(offset) { @@ -916,7 +973,7 @@ imageutils.createBrush = function($el, opts, mapper) { }; } - bounds(newBounds); + boundsPx(newBounds); updateDiv(); } @@ -930,7 +987,7 @@ imageutils.createBrush = function($el, opts, mapper) { importOldBrush: importOldBrush, isInsideBrush: isInsideBrush, - bounds: bounds, + boundsPx: boundsPx, down: down, up: up,