diff --git a/src/components/annotations/draw.js b/src/components/annotations/draw.js index 478a12141d0..eeeaa560fc5 100644 --- a/src/components/annotations/draw.js +++ b/src/components/annotations/draw.js @@ -13,6 +13,7 @@ var d3 = require('d3'); var Registry = require('../../registry'); var Plots = require('../../plots/plots'); var Lib = require('../../lib'); +var strTranslate = Lib.strTranslate; var Axes = require('../../plots/cartesian/axes'); var Color = require('../color'); var Drawing = require('../drawing'); @@ -583,7 +584,7 @@ function drawRaw(gd, options, index, subplotId, xa, ya) { .classed('cursor-move', true) .attr({ d: 'M3,3H-3V-3H3ZM0,0L' + (tailX - arrowDragHeadX) + ',' + (tailY - arrowDragHeadY), - transform: 'translate(' + arrowDragHeadX + ',' + arrowDragHeadY + ')' + transform: strTranslate(arrowDragHeadX, arrowDragHeadY) }) .style('stroke-width', (strokewidth + 6) + 'px') .call(Color.stroke, 'rgba(0,0,0,0)') @@ -630,7 +631,7 @@ function drawRaw(gd, options, index, subplotId, xa, ya) { modifyItem('ay', shiftPosition(ya, dy, 'ay', gs, options)); } - arrowGroup.attr('transform', 'translate(' + dx + ',' + dy + ')'); + arrowGroup.attr('transform', strTranslate(dx, dy)); annTextGroup.attr({ transform: 'rotate(' + textangle + ',' + xcenter + ',' + ycenter + ')' @@ -715,7 +716,7 @@ function drawRaw(gd, options, index, subplotId, xa, ya) { } else return; annTextGroup.attr({ - transform: 'translate(' + dx + ',' + dy + ')' + baseTextTransform + transform: strTranslate(dx, dy) + baseTextTransform }); setCursor(annTextGroupInner, csr); diff --git a/src/components/annotations/draw_arrow_head.js b/src/components/annotations/draw_arrow_head.js index 846faa8587b..99eafdc91d3 100644 --- a/src/components/annotations/draw_arrow_head.js +++ b/src/components/annotations/draw_arrow_head.js @@ -15,6 +15,11 @@ var Color = require('../color'); var ARROWPATHS = require('./arrow_paths'); +var Lib = require('../../lib'); +var strScale = Lib.strScale; +var strRotate = Lib.strRotate; +var strTranslate = Lib.strTranslate; + /** * Add arrowhead(s) to a path or line element * @@ -134,9 +139,9 @@ module.exports = function drawArrowHead(el3, ends, options) { 'class': el3.attr('class'), d: arrowHeadStyle.path, transform: - 'translate(' + p.x + ',' + p.y + ')' + - (rot ? 'rotate(' + (rot * 180 / Math.PI) + ')' : '') + - 'scale(' + arrowScale + ')' + strTranslate(p.x, p.y) + + strRotate(rot * 180 / Math.PI) + + strScale(arrowScale) }) .style({ fill: Color.rgb(options.arrowcolor), diff --git a/src/components/colorbar/draw.js b/src/components/colorbar/draw.js index 81de94620f3..85883755a2f 100644 --- a/src/components/colorbar/draw.js +++ b/src/components/colorbar/draw.js @@ -16,6 +16,7 @@ var Registry = require('../../registry'); var Axes = require('../../plots/cartesian/axes'); var dragElement = require('../dragelement'); var Lib = require('../../lib'); +var strTranslate = Lib.strTranslate; var extendFlat = require('../../lib/extend').extendFlat; var setCursor = require('../../lib/setcursor'); var Drawing = require('../drawing'); @@ -270,10 +271,10 @@ function drawColorBar(g, opts, gd) { ax.setScale(); - g.attr('transform', 'translate(' + Math.round(gs.l) + ',' + Math.round(gs.t) + ')'); + g.attr('transform', strTranslate(Math.round(gs.l), Math.round(gs.t))); var titleCont = g.select('.' + cn.cbtitleunshift) - .attr('transform', 'translate(-' + Math.round(gs.l) + ',-' + Math.round(gs.t) + ')'); + .attr('transform', strTranslate(-Math.round(gs.l), -Math.round(gs.t))); var axLayer = g.select('.' + cn.cbaxis); var titleEl; @@ -385,15 +386,15 @@ function drawColorBar(g, opts, gd) { titleTrans[1] += (1 - nlines) * lineSize; } - titleGroup.attr('transform', 'translate(' + titleTrans + ')'); + titleGroup.attr('transform', strTranslate(titleTrans[0], titleTrans[1])); ax.setScale(); } } g.selectAll('.' + cn.cbfills + ',.' + cn.cblines) - .attr('transform', 'translate(0,' + Math.round(gs.h * (1 - ax.domain[1])) + ')'); + .attr('transform', strTranslate(0, Math.round(gs.h * (1 - ax.domain[1])))); - axLayer.attr('transform', 'translate(0,' + Math.round(-gs.t) + ')'); + axLayer.attr('transform', strTranslate(0, Math.round(-gs.t))); var fills = g.select('.' + cn.cbfills) .selectAll('rect.' + cn.cbfill) @@ -529,7 +530,7 @@ function drawColorBar(g, opts, gd) { // fix positioning for xanchor!='left' var xoffset = ({center: 0.5, right: 1}[opts.xanchor] || 0) * outerwidth; - g.attr('transform', 'translate(' + (gs.l - xoffset) + ',' + gs.t + ')'); + g.attr('transform', strTranslate(gs.l - xoffset, gs.t)); // auto margin adjustment var marginOpts = {}; @@ -585,7 +586,7 @@ function makeEditable(g, opts, gd) { setCursor(g); }, moveFn: function(dx, dy) { - g.attr('transform', t0 + ' ' + 'translate(' + dx + ',' + dy + ')'); + g.attr('transform', t0 + strTranslate(dx, dy)); xf = dragElement.align(opts._xLeftFrac + (dx / gs.w), opts._thickFrac, 0, 1, opts.xanchor); diff --git a/src/components/drawing/index.js b/src/components/drawing/index.js index 66da24e32e0..1307e9ca2a9 100644 --- a/src/components/drawing/index.js +++ b/src/components/drawing/index.js @@ -17,6 +17,7 @@ var Registry = require('../../registry'); var Color = require('../color'); var Colorscale = require('../colorscale'); var Lib = require('../../lib'); +var strTranslate = Lib.strTranslate; var svgTextUtils = require('../../lib/svg_text_utils'); var xmlnsNamespaces = require('../../constants/xmlns_namespaces'); @@ -78,7 +79,7 @@ drawing.translatePoint = function(d, sel, xa, ya) { if(sel.node().nodeName === 'text') { sel.attr('x', x).attr('y', y); } else { - sel.attr('transform', 'translate(' + x + ',' + y + ')'); + sel.attr('transform', strTranslate(x, y)); } } else { return false; @@ -704,7 +705,7 @@ function textPointPosition(s, textPosition, fontSize, markerRadius) { // fix the overall text group position s.attr('text-anchor', h); - group.attr('transform', 'translate(' + dx + ',' + dy + ')'); + group.attr('transform', strTranslate(dx, dy)); } function extracTextFontSize(d, trace) { @@ -1095,7 +1096,7 @@ drawing.setTranslate = function(element, x, y) { y = y || 0; transform = transform.replace(re, '').trim(); - transform += ' translate(' + x + ', ' + y + ')'; + transform += strTranslate(x, y); transform = transform.trim(); element[setter]('transform', transform); @@ -1129,7 +1130,7 @@ drawing.setScale = function(element, x, y) { y = y || 1; transform = transform.replace(re, '').trim(); - transform += ' scale(' + x + ', ' + y + ')'; + transform += 'scale(' + x + ',' + y + ')'; transform = transform.trim(); element[setter]('transform', transform); @@ -1148,7 +1149,7 @@ drawing.setPointGroupScale = function(selection, xScale, yScale) { // The same scale transform for every point: var scale = (xScale === 1 && yScale === 1) ? '' : - ' scale(' + xScale + ',' + yScale + ')'; + 'scale(' + xScale + ',' + yScale + ')'; selection.each(function() { var t = (this.getAttribute('transform') || '').replace(SCALE_RE, ''); @@ -1179,9 +1180,9 @@ drawing.setTextPointsScale = function(selection, xScale, yScale) { transforms = []; } else { transforms = [ - 'translate(' + x + ',' + y + ')', + strTranslate(x, y), 'scale(' + xScale + ',' + yScale + ')', - 'translate(' + (-x) + ',' + (-y) + ')', + strTranslate(-x, -y), ]; } @@ -1189,6 +1190,6 @@ drawing.setTextPointsScale = function(selection, xScale, yScale) { transforms.push(existingTransform); } - el.attr('transform', transforms.join(' ')); + el.attr('transform', transforms.join('')); }); }; diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index 3b43a069bc3..bc4f821d389 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -13,6 +13,8 @@ var isNumeric = require('fast-isnumeric'); var tinycolor = require('tinycolor2'); var Lib = require('../../lib'); +var strTranslate = Lib.strTranslate; +var strRotate = Lib.strRotate; var Events = require('../../lib/events'); var svgTextUtils = require('../../lib/svg_text_utils'); var overrideCursor = require('../../lib/override_cursor'); @@ -960,7 +962,7 @@ function createHoverText(hoverData, opts, gd) { Drawing.setClipUrl(ltext, clipPath ? clipId : null, gd); } - label.attr('transform', 'translate(' + lx + ',' + ly + ')'); + label.attr('transform', strTranslate(lx, ly)); // remove the "close but not quite" points // because of error bars, only take up to a space @@ -1068,7 +1070,7 @@ function createHoverText(hoverData, opts, gd) { ly = outerHeight - txHeight; } } - legendContainer.attr('transform', 'translate(' + lx + ',' + ly + ')'); + legendContainer.attr('transform', strTranslate(lx, ly)); return legendContainer; } @@ -1217,8 +1219,8 @@ function createHoverText(hoverData, opts, gd) { tx.attr('text-anchor', d.anchor); if(tx2width) tx2.attr('text-anchor', d.anchor); - g.attr('transform', 'translate(' + htx + ',' + hty + ')' + - (rotateLabels ? 'rotate(' + YANGLE + ')' : '')); + g.attr('transform', strTranslate(htx, hty) + + (rotateLabels ? strRotate(YANGLE) : '')); }); return hoverLabels; diff --git a/src/components/legend/style.js b/src/components/legend/style.js index e34143cafe9..3dbf2bfc09b 100644 --- a/src/components/legend/style.js +++ b/src/components/legend/style.js @@ -12,6 +12,7 @@ var d3 = require('d3'); var Registry = require('../../registry'); var Lib = require('../../lib'); +var strTranslate = Lib.strTranslate; var Drawing = require('../drawing'); var Color = require('../color'); var extractOpts = require('../colorscale/helpers').extractOpts; @@ -34,7 +35,7 @@ module.exports = function style(s, gd, legend) { var constantItemSizing = legend.itemsizing === 'constant'; var itemWidth = legend.itemwidth; var centerPos = (itemWidth + constants.itemGap * 2) / 2; - var centerTransform = 'translate(' + centerPos + ',0)'; + var centerTransform = strTranslate(centerPos, 0); var boundLineWidth = function(mlw, cont, max, cst) { var v; @@ -63,7 +64,7 @@ module.exports = function style(s, gd, legend) { } else { var factor = {top: 1, bottom: -1}[valign]; var markerOffsetY = factor * (0.5 * (lineHeight - height + 3)); - layers.attr('transform', 'translate(0,' + markerOffsetY + ')'); + layers.attr('transform', strTranslate(0, markerOffsetY)); } var fill = layers diff --git a/src/components/rangeselector/draw.js b/src/components/rangeselector/draw.js index 8cad51424be..ec82c49228e 100644 --- a/src/components/rangeselector/draw.js +++ b/src/components/rangeselector/draw.js @@ -15,6 +15,7 @@ var Plots = require('../../plots/plots'); var Color = require('../color'); var Drawing = require('../drawing'); var Lib = require('../../lib'); +var strTranslate = Lib.strTranslate; var svgTextUtils = require('../../lib/svg_text_utils'); var axisIds = require('../../plots/cartesian/axis_ids'); @@ -195,9 +196,7 @@ function reposition(gd, buttons, opts, axName, selector) { // TODO add buttongap attribute - button.attr('transform', 'translate(' + - (borderWidth + width) + ',' + borderWidth + - ')'); + button.attr('transform', strTranslate(borderWidth + width, borderWidth)); rect.attr({ x: 0, @@ -250,5 +249,5 @@ function reposition(gd, buttons, opts, axName, selector) { t: height * FROM_TL[yanchor] }); - selector.attr('transform', 'translate(' + lx + ',' + ly + ')'); + selector.attr('transform', strTranslate(lx, ly)); } diff --git a/src/components/rangeslider/draw.js b/src/components/rangeslider/draw.js index e47f0474f97..7f8e5bf5586 100644 --- a/src/components/rangeslider/draw.js +++ b/src/components/rangeslider/draw.js @@ -14,6 +14,7 @@ var Registry = require('../../registry'); var Plots = require('../../plots/plots'); var Lib = require('../../lib'); +var strTranslate = Lib.strTranslate; var Drawing = require('../drawing'); var Color = require('../color'); var Titles = require('../titles'); @@ -119,7 +120,7 @@ module.exports = function(gd) { opts._offsetShift + constants.extraPad ); - rangeSlider.attr('transform', 'translate(' + x + ',' + y + ')'); + rangeSlider.attr('transform', strTranslate(x, y)); // update data <--> pixel coordinate conversion methods @@ -380,10 +381,10 @@ function setPixelRange(rangeSlider, gd, axisOpts, opts, oppAxisOpts, oppAxisRang var xMax = Math.round(clampHandle(pixelMax - hw2)) + offset; rangeSlider.select('g.' + constants.grabberMinClassName) - .attr('transform', 'translate(' + xMin + ',' + offset + ')'); + .attr('transform', strTranslate(xMin, offset)); rangeSlider.select('g.' + constants.grabberMaxClassName) - .attr('transform', 'translate(' + xMax + ',' + offset + ')'); + .attr('transform', strTranslate(xMax, offset)); } function drawBg(rangeSlider, gd, axisOpts, opts) { @@ -405,7 +406,7 @@ function drawBg(rangeSlider, gd, axisOpts, opts) { bg.attr({ width: opts._width + borderCorrect, height: opts._height + borderCorrect, - transform: 'translate(' + offsetShift + ',' + offsetShift + ')', + transform: strTranslate(offsetShift, offsetShift), fill: opts.bgcolor, stroke: opts.bordercolor, 'stroke-width': lw diff --git a/src/components/sliders/draw.js b/src/components/sliders/draw.js index b6c1c25f5bd..e0496fb7746 100644 --- a/src/components/sliders/draw.js +++ b/src/components/sliders/draw.js @@ -14,6 +14,7 @@ var Plots = require('../../plots/plots'); var Color = require('../color'); var Drawing = require('../drawing'); var Lib = require('../../lib'); +var strTranslate = Lib.strTranslate; var svgTextUtils = require('../../lib/svg_text_utils'); var arrayEditor = require('../../plot_api/plot_template').arrayEditor; @@ -572,7 +573,7 @@ function setGripPosition(sliderGroup, sliderOpts, doTransition) { // Drawing.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) + ',' + (sliderOpts._dims.currentValueTotalHeight) + ')'); + el.attr('transform', strTranslate(x - constants.gripWidth * 0.5, sliderOpts._dims.currentValueTotalHeight)); } // Convert a number from [0-1] to a pixel position relative to the slider group container: diff --git a/src/components/titles/index.js b/src/components/titles/index.js index a1cdddaf21a..830d27e7beb 100644 --- a/src/components/titles/index.js +++ b/src/components/titles/index.js @@ -15,6 +15,7 @@ var isNumeric = require('fast-isnumeric'); var Plots = require('../../plots/plots'); var Registry = require('../../registry'); var Lib = require('../../lib'); +var strTranslate = Lib.strTranslate; var Drawing = require('../drawing'); var Color = require('../color'); var svgTextUtils = require('../../lib/svg_text_utils'); @@ -135,7 +136,7 @@ function draw(gd, titleClass, options) { transformVal += 'rotate(' + [transform.rotate, attributes.x, attributes.y] + ')'; } if(transform.offset) { - transformVal += 'translate(0, ' + transform.offset + ')'; + transformVal += strTranslate(0, transform.offset); } } else { transformVal = null; @@ -213,7 +214,7 @@ function draw(gd, titleClass, options) { top: [0, -shift], bottom: [0, shift] }[avoid.side]; - titleGroup.attr('transform', 'translate(' + shiftTemplate + ')'); + titleGroup.attr('transform', strTranslate(shiftTemplate[0], shiftTemplate[1])); } } } diff --git a/src/lib/index.js b/src/lib/index.js index 17342b1a649..a2b2118be4a 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -1195,6 +1195,18 @@ lib.isHidden = function(gd) { return !display || display === 'none'; }; +lib.strTranslate = function(x, y) { + return (x || y) ? 'translate(' + x + ',' + y + ')' : ''; +}; + +lib.strRotate = function(a) { + return a ? 'rotate(' + a + ')' : ''; +}; + +lib.strScale = function(s) { + return s !== 1 ? 'scale(' + s + ')' : ''; +}; + /** Return transform text for bar bar-like rectangles and pie-like slices * @param {object} transform * - targetX: desired position on the x-axis @@ -1221,13 +1233,11 @@ lib.getTextTransform = function(transform) { else if(scale > 1) scale = 1; return ( - 'translate(' + - (targetX - scale * (textX + anchorX)) + ',' + - (targetY - scale * (textY + anchorY)) + - ')' + - (scale < 1 ? - 'scale(' + scale + ')' : '' + lib.strTranslate( + targetX - scale * (textX + anchorX), + targetY - scale * (textY + anchorY) ) + + lib.strScale(scale) + (rotate ? 'rotate(' + rotate + (noCenter ? '' : ' ' + textX + ' ' + textY) + diff --git a/src/lib/svg_text_utils.js b/src/lib/svg_text_utils.js index 93194a14145..d34c539a1ab 100644 --- a/src/lib/svg_text_utils.js +++ b/src/lib/svg_text_utils.js @@ -14,6 +14,7 @@ var d3 = require('d3'); var Lib = require('../lib'); +var strTranslate = Lib.strTranslate; var xmlnsNamespaces = require('../constants/xmlns_namespaces'); var LINE_SPACING = require('../constants/alignment').LINE_SPACING; @@ -128,7 +129,7 @@ exports.convertToTspans = function(_context, gd, _callback) { if(svgClass[0] === 'y') { mathjaxGroup.attr({ transform: 'rotate(' + [-90, +_context.attr('x'), +_context.attr('y')] + - ') translate(' + [-newSvgW / 2, dy - newSvgH / 2] + ')' + ')' + strTranslate(-newSvgW / 2, dy - newSvgH / 2) }); newSvg.attr({x: +_context.attr('x'), y: +_context.attr('y')}); } else if(svgClass[0] === 'l') { diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 91e0f1c2f64..d4be6f51640 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -14,6 +14,7 @@ var Plots = require('../../plots/plots'); var Registry = require('../../registry'); var Lib = require('../../lib'); +var strTranslate = Lib.strTranslate; var svgTextUtils = require('../../lib/svg_text_utils'); var Titles = require('../../components/titles'); var Color = require('../../components/color'); @@ -2470,18 +2471,32 @@ axes.makeTransFn = function(ax) { var axLetter = ax._id.charAt(0); var offset = ax._offset; return axLetter === 'x' ? - function(d) { return 'translate(' + (offset + ax.l2p(d.x)) + ',0)'; } : - function(d) { return 'translate(0,' + (offset + ax.l2p(d.x)) + ')'; }; + function(d) { return strTranslate(offset + ax.l2p(d.x), 0); } : + function(d) { return strTranslate(0, offset + ax.l2p(d.x)); }; }; axes.makeTransPeriodFn = function(ax) { var axLetter = ax._id.charAt(0); var offset = ax._offset; return axLetter === 'x' ? - function(d) { return 'translate(' + (offset + ax.l2p(d.periodX !== undefined ? d.periodX : d.x)) + ',0)'; } : - function(d) { return 'translate(0,' + (offset + ax.l2p(d.periodX !== undefined ? d.periodX : d.x)) + ')'; }; + function(d) { + return strTranslate( + offset + ax.l2p(getPeriodX(d)), + 0 + ); + } : + function(d) { + return strTranslate( + 0, + offset + ax.l2p(getPeriodX(d)) + ); + }; }; +function getPeriodX(d) { + return d.periodX !== undefined ? d.periodX : d.x; +} + /** * Make axis tick path string * @@ -2856,7 +2871,7 @@ axes.drawLabels = function(gd, ax, opts) { var anchorHeight = labelFns.heightFn(d, isNumeric(angle) ? +angle : 0, (nLines - 1) * lineHeight); if(anchorHeight) { - transform += ' translate(0, ' + anchorHeight + ')'; + transform += strTranslate(0, anchorHeight); } if(mathjaxGroup.empty()) { @@ -2867,7 +2882,7 @@ axes.drawLabels = function(gd, ax, opts) { } else { var mjWidth = Drawing.bBox(mathjaxGroup.node()).width; var mjShift = mjWidth * {end: -0.5, start: 0.5}[anchor]; - mathjaxGroup.attr('transform', transform + (mjShift ? 'translate(' + mjShift + ',0)' : '')); + mathjaxGroup.attr('transform', transform + strTranslate(mjShift, 0)); } }); } diff --git a/src/plots/cartesian/dragbox.js b/src/plots/cartesian/dragbox.js index 573362f0047..e81ff1d5aa0 100644 --- a/src/plots/cartesian/dragbox.js +++ b/src/plots/cartesian/dragbox.js @@ -14,6 +14,7 @@ var supportsPassive = require('has-passive-events'); var Registry = require('../../registry'); var Lib = require('../../lib'); +var strTranslate = Lib.strTranslate; var svgTextUtils = require('../../lib/svg_text_utils'); var Color = require('../../components/color'); var Drawing = require('../../components/drawing'); @@ -1072,7 +1073,7 @@ function makeZoombox(zoomlayer, lum, xs, ys, path0) { 'fill': lum > 0.2 ? 'rgba(0,0,0,0)' : 'rgba(255,255,255,0)', 'stroke-width': 0 }) - .attr('transform', 'translate(' + xs + ', ' + ys + ')') + .attr('transform', strTranslate(xs, ys)) .attr('d', path0 + 'Z'); } @@ -1085,7 +1086,7 @@ function makeCorners(zoomlayer, xs, ys) { 'stroke-width': 1, opacity: 0 }) - .attr('transform', 'translate(' + xs + ', ' + ys + ')') + .attr('transform', strTranslate(xs, ys)) .attr('d', 'M0,0Z'); } diff --git a/src/plots/cartesian/helpers.js b/src/plots/cartesian/helpers.js index b07c36f0703..30129f19a3b 100644 --- a/src/plots/cartesian/helpers.js +++ b/src/plots/cartesian/helpers.js @@ -9,6 +9,8 @@ 'use strict'; +var strTranslate = require('../../lib').strTranslate; + // in v2 (once log ranges are fixed), // we'll be able to p2r here for all axis types function p2r(ax, v) { @@ -39,9 +41,10 @@ function axValue(ax) { } function getTransform(plotinfo) { - return 'translate(' + - plotinfo.xaxis._offset + ',' + - plotinfo.yaxis._offset + ')'; + return strTranslate( + plotinfo.xaxis._offset, + plotinfo.yaxis._offset + ); } module.exports = { diff --git a/src/plots/geo/geo.js b/src/plots/geo/geo.js index 96e33c664d9..ea7a89bc8d4 100644 --- a/src/plots/geo/geo.js +++ b/src/plots/geo/geo.js @@ -14,6 +14,7 @@ var d3 = require('d3'); var Registry = require('../../registry'); var Lib = require('../../lib'); +var strTranslate = Lib.strTranslate; var Color = require('../../components/color'); var Drawing = require('../../components/drawing'); var Fx = require('../../components/fx'); @@ -632,7 +633,7 @@ proto.render = function() { function translatePoints(d) { var lonlatPx = projection(d.lonlat); return lonlatPx ? - 'translate(' + lonlatPx[0] + ',' + lonlatPx[1] + ')' : + strTranslate(lonlatPx[0], lonlatPx[1]) : null; } diff --git a/src/plots/mapbox/index.js b/src/plots/mapbox/index.js index c9e93b61d6f..4c6b4717ae5 100644 --- a/src/plots/mapbox/index.js +++ b/src/plots/mapbox/index.js @@ -11,6 +11,8 @@ var mapboxgl = require('mapbox-gl'); var Lib = require('../../lib'); +var strTranslate = Lib.strTranslate; +var strScale = Lib.strScale; var getSubplotCalcData = require('../../plots/get_data').getSubplotCalcData; var xmlnsNamespaces = require('../../constants/xmlns_namespaces'); var d3 = require('d3'); @@ -127,7 +129,7 @@ exports.toSVG = function(gd) { var hidden = subplotDiv.select('.mapboxgl-ctrl-logo').node().offsetParent === null; if(!hidden) { var logo = fullLayout._glimages.append('g'); - logo.attr('transform', 'translate(' + (size.l + size.w * domain.x[0] + 10) + ', ' + (size.t + size.h * (1 - domain.y[0]) - 31) + ')'); + logo.attr('transform', strTranslate(size.l + size.w * domain.x[0] + 10, size.t + size.h * (1 - domain.y[0]) - 31)); logo.append('path') .attr('d', constants.mapboxLogo.path0) .style({ @@ -187,7 +189,7 @@ exports.toSVG = function(gd) { bBox = Drawing.bBox(attributionText.node()); } - attributionText.attr('transform', 'translate(-3, ' + (-bBox.height + 8) + ')'); + attributionText.attr('transform', strTranslate(-3, -bBox.height + 8)); // Draw white rectangle behind text attributionGroup @@ -205,7 +207,7 @@ exports.toSVG = function(gd) { if((bBox.width + 6) > maxWidth) scaleRatio = maxWidth / (bBox.width + 6); var offset = [(size.l + size.w * domain.x[1]), (size.t + size.h * (1 - domain.y[0]))]; - attributionGroup.attr('transform', 'translate(' + offset[0] + ',' + offset[1] + ') scale(' + scaleRatio + ')'); + attributionGroup.attr('transform', strTranslate(offset[0], offset[1]) + strScale(scaleRatio)); } }; diff --git a/src/plots/polar/polar.js b/src/plots/polar/polar.js index ebeed62ab25..deb91d646fb 100644 --- a/src/plots/polar/polar.js +++ b/src/plots/polar/polar.js @@ -13,6 +13,8 @@ var tinycolor = require('tinycolor2'); var Registry = require('../../registry'); var Lib = require('../../lib'); +var strRotate = Lib.strRotate; +var strTranslate = Lib.strTranslate; var Color = require('../../components/color'); var Drawing = require('../../components/drawing'); var Plots = require('../plots'); @@ -379,7 +381,7 @@ proto.updateRadialAxis = function(fullLayout, polarLayout) { // easier to set rotate angle with custom translate function var transFn = function(d) { - return 'translate(' + (ax.l2p(d.x) + innerRadius) + ',0)'; + return strTranslate(ax.l2p(d.x) + innerRadius, 0); }; // set special grid path function @@ -1419,11 +1421,3 @@ function updateElement(sel, showAttr, attrs) { } return sel; } - -function strTranslate(x, y) { - return 'translate(' + x + ',' + y + ')'; -} - -function strRotate(angle) { - return 'rotate(' + angle + ')'; -} diff --git a/src/plots/ternary/ternary.js b/src/plots/ternary/ternary.js index 5610ceff51e..c4514cdcde0 100644 --- a/src/plots/ternary/ternary.js +++ b/src/plots/ternary/ternary.js @@ -14,6 +14,7 @@ var tinycolor = require('tinycolor2'); var Registry = require('../../registry'); var Lib = require('../../lib'); +var strTranslate = Lib.strTranslate; var _ = Lib._; var Color = require('../../components/color'); var Drawing = require('../../components/drawing'); @@ -301,7 +302,7 @@ proto.adjustLayout = function(ternaryLayout, graphSize) { var triangleClipRelative = 'M0,' + h + 'h' + w + 'l-' + (w / 2) + ',-' + h + 'Z'; _this.clipDefRelative.select('path').attr('d', triangleClipRelative); - var plotTransform = 'translate(' + x0 + ',' + y0 + ')'; + var plotTransform = strTranslate(x0, y0); _this.plotContainer.selectAll('.scatterlayer,.maplayer') .attr('transform', plotTransform); @@ -310,18 +311,18 @@ proto.adjustLayout = function(ternaryLayout, graphSize) { // TODO: shift axes to accommodate linewidth*sin(30) tick mark angle // TODO: there's probably an easier way to handle these translations/offsets now... - var bTransform = 'translate(' + (x0 - baxis._offset) + ',' + (y0 + h) + ')'; + var bTransform = strTranslate(x0 - baxis._offset, y0 + h); _this.layers.baxis.attr('transform', bTransform); _this.layers.bgrid.attr('transform', bTransform); - var aTransform = 'translate(' + (x0 + w / 2) + ',' + y0 + - ')rotate(30)translate(0,' + -aaxis._offset + ')'; + var aTransform = strTranslate(x0 + w / 2, y0) + + 'rotate(30)' + strTranslate(0, -aaxis._offset); _this.layers.aaxis.attr('transform', aTransform); _this.layers.agrid.attr('transform', aTransform); - var cTransform = 'translate(' + (x0 + w / 2) + ',' + y0 + - ')rotate(-30)translate(0,' + -caxis._offset + ')'; + var cTransform = strTranslate(x0 + w / 2, y0) + + 'rotate(-30)' + strTranslate(0, -caxis._offset); _this.layers.caxis.attr('transform', cTransform); _this.layers.cgrid.attr('transform', cTransform); @@ -588,7 +589,7 @@ proto.initInteractions = function() { zb = zoomLayer.append('path') .attr('class', 'zoombox') - .attr('transform', 'translate(' + _this.x0 + ', ' + _this.y0 + ')') + .attr('transform', strTranslate(_this.x0, _this.y0)) .style({ 'fill': lum > 0.2 ? 'rgba(0,0,0,0)' : 'rgba(255,255,255,0)', 'stroke-width': 0 @@ -597,7 +598,7 @@ proto.initInteractions = function() { corners = zoomLayer.append('path') .attr('class', 'zoombox-corners') - .attr('transform', 'translate(' + _this.x0 + ', ' + _this.y0 + ')') + .attr('transform', strTranslate(_this.x0, _this.y0)) .style({ fill: Color.background, stroke: Color.defaultLine, @@ -714,11 +715,11 @@ proto.initInteractions = function() { } // move the data (translate, don't redraw) - var plotTransform = 'translate(' + (_this.x0 + dx) + ',' + (_this.y0 + dy) + ')'; + var plotTransform = strTranslate(_this.x0 + dx, _this.y0 + dy); _this.plotContainer.selectAll('.scatterlayer,.maplayer') .attr('transform', plotTransform); - var plotTransform2 = 'translate(' + -dx + ',' + -dy + ')'; + var plotTransform2 = strTranslate(-dx, -dy); _this.clipDefRelative.select('path').attr('transform', plotTransform2); // move the ticks diff --git a/src/traces/carpet/plot.js b/src/traces/carpet/plot.js index 7d45bddcbb2..8d630b90578 100644 --- a/src/traces/carpet/plot.js +++ b/src/traces/carpet/plot.js @@ -16,6 +16,8 @@ var makepath = require('./makepath'); var orientText = require('./orient_text'); var svgTextUtils = require('../../lib/svg_text_utils'); var Lib = require('../../lib'); +var strRotate = Lib.strRotate; +var strTranslate = Lib.strTranslate; var alignmentConstants = require('../../constants/alignment'); module.exports = function plot(gd, plotinfo, cdcarpet, carpetLayer) { @@ -154,11 +156,11 @@ function drawAxisLabels(gd, xaxis, yaxis, trace, t, layer, labels, labelClass) { labelEl.attr('transform', // Translate to the correct point: - 'translate(' + orientation.p[0] + ',' + orientation.p[1] + ') ' + + strTranslate(orientation.p[0], orientation.p[1]) + // Rotate to line up with grid line tangent: - 'rotate(' + orientation.angle + ')' + + strRotate(orientation.angle) + // Adjust the baseline and indentation: - 'translate(' + label.axis.labelpadding * direction + ',' + bbox.height * 0.3 + ')' + strTranslate(label.axis.labelpadding * direction, bbox.height * 0.3) ); maxExtent = Math.max(maxExtent, bbox.width + label.axis.labelpadding); @@ -235,9 +237,9 @@ function drawAxisTitle(gd, layer, trace, t, xy, dxy, axis, xa, ya, labelOrientat } el.attr('transform', - 'translate(' + orientation.p[0] + ',' + orientation.p[1] + ') ' + - 'rotate(' + orientation.angle + ') ' + - 'translate(0,' + offset + ')' + strTranslate(orientation.p[0], orientation.p[1]) + + strRotate(orientation.angle) + + strTranslate(0, offset) ) .attr('text-anchor', 'middle') .call(Drawing.font, axis.title.font); diff --git a/src/traces/funnelarea/plot.js b/src/traces/funnelarea/plot.js index 672835bc456..0e683d9bdb8 100644 --- a/src/traces/funnelarea/plot.js +++ b/src/traces/funnelarea/plot.js @@ -12,6 +12,8 @@ var d3 = require('d3'); var Drawing = require('../../components/drawing'); var Lib = require('../../lib'); +var strScale = Lib.strScale; +var strTranslate = Lib.strTranslate; var svgTextUtils = require('../../lib/svg_text_utils'); var barPlot = require('../bar/plot'); @@ -167,9 +169,9 @@ module.exports = function plot(gd, cdModule) { var transform = positionTitleOutside(cd0, fullLayout._size); titleText.attr('transform', - 'translate(' + transform.x + ',' + transform.y + ')' + - (transform.scale < 1 ? ('scale(' + transform.scale + ')') : '') + - 'translate(' + transform.tx + ',' + transform.ty + ')'); + strTranslate(transform.x, transform.y) + + strScale(Math.min(1, transform.scale)) + + strTranslate(transform.tx, transform.ty)); }); }); }); diff --git a/src/traces/indicator/plot.js b/src/traces/indicator/plot.js index 96ef6de708b..5c2925652d2 100644 --- a/src/traces/indicator/plot.js +++ b/src/traces/indicator/plot.js @@ -11,6 +11,8 @@ var d3 = require('d3'); var Lib = require('../../lib'); +var strScale = Lib.strScale; +var strTranslate = Lib.strTranslate; var rad2deg = Lib.rad2deg; var MID_SHIFT = require('../../constants/alignment').MID_SHIFT; var Drawing = require('../../components/drawing'); @@ -243,7 +245,7 @@ function drawBulletGauge(gd, plotGroup, cd, opts) { // Enter bullet, axis bullet.enter().append('g').classed('bullet', true); - bullet.attr('transform', 'translate(' + size.l + ', ' + size.t + ')'); + bullet.attr('transform', strTranslate(size.l, size.t)); axisLayer.enter().append('g') .classed('bulletaxis', true) @@ -780,7 +782,7 @@ function drawNumbers(gd, plotGroup, cd, opts) { // Stash translateX translateX = cache(trace, 'numbersTranslate', 0, translateX, key, Math.max); - return strTranslate(translateX, translateY) + ' scale(' + scaleRatio + ')'; + return strTranslate(translateX, translateY) + strScale(scaleRatio); }); } } @@ -837,10 +839,6 @@ function mockAxis(gd, opts, zrange) { return axisOut; } -function strTranslate(x, y) { - return 'translate(' + x + ',' + y + ')'; -} - function fitTextInsideBox(textBB, width, height) { // compute scaling ratio to have text fit within specified width and height var ratio = Math.min(width / textBB.width, height / textBB.height); diff --git a/src/traces/parcats/parcats.js b/src/traces/parcats/parcats.js index a5fc1a60659..57568acbaee 100644 --- a/src/traces/parcats/parcats.js +++ b/src/traces/parcats/parcats.js @@ -12,6 +12,7 @@ var d3 = require('d3'); var Plotly = require('../../plot_api/plot_api'); var Fx = require('../../components/fx'); var Lib = require('../../lib'); +var strTranslate = Lib.strTranslate; var Drawing = require('../../components/drawing'); var tinycolor = require('tinycolor2'); var svgTextUtils = require('../../lib/svg_text_utils'); @@ -41,7 +42,7 @@ function performPlot(parcatsModels, graphDiv, layout, svg) { // Update properties for each trace traceSelection .attr('transform', function(d) { - return 'translate(' + d.x + ', ' + d.y + ')'; + return strTranslate(d.x, d.y); }); // Initialize paths group @@ -122,7 +123,7 @@ function performPlot(parcatsModels, graphDiv, layout, svg) { // Update dimension group transforms dimensionSelection.attr('transform', function(d) { - return 'translate(' + d.x + ', 0)'; + return strTranslate(d.x, 0); }); // Remove any old dimensions @@ -144,7 +145,7 @@ function performPlot(parcatsModels, graphDiv, layout, svg) { // Update category transforms categorySelection .attr('transform', function(d) { - return 'translate(0, ' + d.y + ')'; + return strTranslate(0, d.y); }); @@ -1401,13 +1402,13 @@ function updateSvgCategories(parcatsViewModel, hasTransition) { // Update dimension position transition(parcatsViewModel.dimensionSelection) .attr('transform', function(d) { - return 'translate(' + d.x + ', 0)'; + return strTranslate(d.x, 0); }); // Update category position transition(categorySelection) .attr('transform', function(d) { - return 'translate(0, ' + d.y + ')'; + return strTranslate(0, d.y); }); var dimLabelSelection = categorySelection.select('.dimlabel'); diff --git a/src/traces/parcoords/axisbrush.js b/src/traces/parcoords/axisbrush.js index 09578b6a517..0c7c45d8f63 100644 --- a/src/traces/parcoords/axisbrush.js +++ b/src/traces/parcoords/axisbrush.js @@ -13,6 +13,7 @@ var d3 = require('d3'); var keyFun = require('../../lib/gup').keyFun; var repeat = require('../../lib/gup').repeat; var sortAsc = require('../../lib').sorterAsc; +var strTranslate = require('../../lib').strTranslate; var snapRatio = c.bar.snapRatio; function snapOvershoot(v, vAdjacent) { return v * (1 - snapRatio) + vAdjacent * snapRatio; } @@ -370,7 +371,7 @@ function renderAxisBrush(axisBrush) { .call(barHorizontalSetup) .call(backgroundBarHorizontalSetup) .style('pointer-events', 'auto') // parent pointer events are disabled; we must have it to register events - .attr('transform', 'translate(0 ' + c.verticalPadding + ')'); + .attr('transform', strTranslate(0, c.verticalPadding)); background .call(attachDragBehavior) diff --git a/src/traces/parcoords/parcoords.js b/src/traces/parcoords/parcoords.js index 9a20e792043..f31b0e7dbfb 100644 --- a/src/traces/parcoords/parcoords.js +++ b/src/traces/parcoords/parcoords.js @@ -13,6 +13,8 @@ var rgba = require('color-rgba'); var Axes = require('../../plots/cartesian/axes'); var Lib = require('../../lib'); +var strRotate = Lib.strRotate; +var strTranslate = Lib.strTranslate; var svgTextUtils = require('../../lib/svg_text_utils'); var Drawing = require('../../components/drawing'); var Colorscale = require('../../components/colorscale'); @@ -518,7 +520,7 @@ module.exports = function parcoords(gd, cdModule, layout, callbacks) { .style('pointer-events', 'none'); controlOverlay.attr('transform', function(d) { - return 'translate(' + d.model.translateX + ',' + d.model.translateY + ')'; + return strTranslate(d.model.translateX, d.model.translateY); }); var parcoordsControlView = controlOverlay.selectAll('.' + c.cn.parcoordsControlView) @@ -529,7 +531,7 @@ module.exports = function parcoords(gd, cdModule, layout, callbacks) { .classed(c.cn.parcoordsControlView, true); parcoordsControlView.attr('transform', function(d) { - return 'translate(' + d.model.pad.l + ',' + d.model.pad.t + ')'; + return strTranslate(d.model.pad.l, d.model.pad.t); }); var yAxis = parcoordsControlView.selectAll('.' + c.cn.yAxis) @@ -560,7 +562,7 @@ module.exports = function parcoords(gd, cdModule, layout, callbacks) { }); yAxis.attr('transform', function(d) { - return 'translate(' + d.xScale(d.xIndex) + ', 0)'; + return strTranslate(d.xScale(d.xIndex), 0); }); // drag column for reordering columns @@ -582,8 +584,8 @@ module.exports = function parcoords(gd, cdModule, layout, callbacks) { updatePanelLayout(yAxis, p); yAxis.filter(function(e) { return Math.abs(d.xIndex - e.xIndex) !== 0; }) - .attr('transform', function(d) { return 'translate(' + d.xScale(d.xIndex) + ', 0)'; }); - d3.select(this).attr('transform', 'translate(' + d.x + ', 0)'); + .attr('transform', function(d) { return strTranslate(d.xScale(d.xIndex), 0); }); + d3.select(this).attr('transform', strTranslate(d.x, 0)); yAxis.each(function(e, i0, i1) { if(i1 === d.parent.key) p.dimensions[i0] = e; }); p.contextLayer && p.contextLayer.render(p.panels, false, !someFiltersActive(p)); p.focusLayer.render && p.focusLayer.render(p.panels); @@ -594,7 +596,7 @@ module.exports = function parcoords(gd, cdModule, layout, callbacks) { d.canvasX = d.x * d.model.canvasPixelRatio; updatePanelLayout(yAxis, p); d3.select(this) - .attr('transform', function(d) { return 'translate(' + d.x + ', 0)'; }); + .attr('transform', function(d) { return strTranslate(d.x, 0); }); p.contextLayer && p.contextLayer.render(p.panels, false, !someFiltersActive(p)); p.focusLayer && p.focusLayer.render(p.panels); p.pickLayer && p.pickLayer.render(p.panels, true); @@ -684,9 +686,9 @@ module.exports = function parcoords(gd, cdModule, layout, callbacks) { var tilt = calcTilt(d.model.labelAngle, d.model.labelSide); var r = c.axisTitleOffset; return ( - (tilt.dir > 0 ? '' : 'translate(0,' + (2 * r + d.model.height) + ')') + - 'rotate(' + tilt.degrees + ')' + - 'translate(' + (-r * tilt.dx) + ',' + (-r * tilt.dy) + ')' + (tilt.dir > 0 ? '' : strTranslate(0, 2 * r + d.model.height)) + + strRotate(tilt.degrees) + + strTranslate(-r * tilt.dx, -r * tilt.dy) ); }) .attr('text-anchor', function(d) { @@ -716,7 +718,7 @@ module.exports = function parcoords(gd, cdModule, layout, callbacks) { .classed(c.cn.axisExtentTop, true); axisExtentTop - .attr('transform', 'translate(' + 0 + ',' + -c.axisExtentOffset + ')'); + .attr('transform', strTranslate(0, -c.axisExtentOffset)); var axisExtentTopText = axisExtentTop.selectAll('.' + c.cn.axisExtentTopText) .data(repeat, keyFun); @@ -739,7 +741,7 @@ module.exports = function parcoords(gd, cdModule, layout, callbacks) { axisExtentBottom .attr('transform', function(d) { - return 'translate(' + 0 + ',' + (d.model.height + c.axisExtentOffset) + ')'; + return strTranslate(0, d.model.height + c.axisExtentOffset); }); var axisExtentBottomText = axisExtentBottom.selectAll('.' + c.cn.axisExtentBottomText) diff --git a/src/traces/pie/plot.js b/src/traces/pie/plot.js index 3a1acc76749..a38b69f8d49 100644 --- a/src/traces/pie/plot.js +++ b/src/traces/pie/plot.js @@ -15,6 +15,8 @@ var Fx = require('../../components/fx'); var Color = require('../../components/color'); var Drawing = require('../../components/drawing'); var Lib = require('../../lib'); +var strScale = Lib.strScale; +var strTranslate = Lib.strTranslate; var svgTextUtils = require('../../lib/svg_text_utils'); var uniformText = require('../bar/uniform_text'); var recordMinTextSize = uniformText.recordMinTextSize; @@ -244,9 +246,9 @@ function plot(gd, cdModule) { } titleText.attr('transform', - 'translate(' + transform.x + ',' + transform.y + ')' + - (transform.scale < 1 ? ('scale(' + transform.scale + ')') : '') + - 'translate(' + transform.tx + ',' + transform.ty + ')'); + strTranslate(transform.x, transform.y) + + strScale(Math.min(1, transform.scale)) + + strTranslate(transform.tx, transform.ty)); }); // now make sure no labels overlap (at least within one pie) diff --git a/src/traces/sankey/render.js b/src/traces/sankey/render.js index 3bd24ebc205..b9e570a5849 100644 --- a/src/traces/sankey/render.js +++ b/src/traces/sankey/render.js @@ -17,6 +17,7 @@ var d3Sankey = require('@plotly/d3-sankey'); var d3SankeyCircular = require('@plotly/d3-sankey-circular'); var d3Force = require('d3-force'); var Lib = require('../../lib'); +var strTranslate = Lib.strTranslate; var gup = require('../../lib/gup'); var keyFun = gup.keyFun; var repeat = gup.repeat; @@ -527,7 +528,7 @@ function nodeModel(d, n) { function updateNodePositions(sankeyNode) { sankeyNode .attr('transform', function(d) { - return 'translate(' + d.node.x0.toFixed(3) + ', ' + (d.node.y0).toFixed(3) + ')'; + return strTranslate(d.node.x0.toFixed(3), (d.node.y0).toFixed(3)); }); } @@ -549,12 +550,12 @@ function sizeNode(rect) { function salientEnough(d) {return (d.link.width > 1 || d.linkLineWidth > 0);} function sankeyTransform(d) { - var offset = 'translate(' + d.translateX + ',' + d.translateY + ')'; + var offset = strTranslate(d.translateX, d.translateY); return offset + (d.horizontal ? 'matrix(1 0 0 1 0 0)' : 'matrix(0 1 1 0 0 0)'); } function nodeCentering(d) { - return 'translate(' + (d.horizontal ? 0 : d.labelY) + ' ' + (d.horizontal ? d.labelY : 0) + ')'; + return strTranslate(d.horizontal ? 0 : d.labelY, d.horizontal ? d.labelY : 0); } function textGuidePath(d) { diff --git a/src/traces/table/plot.js b/src/traces/table/plot.js index aed2f799cf7..cf5dfde68ff 100644 --- a/src/traces/table/plot.js +++ b/src/traces/table/plot.js @@ -14,6 +14,7 @@ var gup = require('../../lib/gup'); var Drawing = require('../../components/drawing'); var svgUtil = require('../../lib/svg_text_utils'); var raiseToTop = require('../../lib').raiseToTop; +var strTranslate = require('../../lib').strTranslate; var cancelEeaseColumn = require('../../lib').cancelTransition; var prepareData = require('./data_preparation_helper'); var splitData = require('./data_split_helpers'); @@ -46,7 +47,7 @@ module.exports = function plot(gd, wrappedTraceHolders) { .attr('width', function(d) {return d.width + d.size.l + d.size.r;}) .attr('height', function(d) {return d.height + d.size.t + d.size.b;}) .attr('transform', function(d) { - return 'translate(' + d.translateX + ',' + d.translateY + ')'; + return strTranslate(d.translateX, d.translateY); }); var tableControlView = table.selectAll('.' + c.cn.tableControlView) @@ -79,7 +80,7 @@ module.exports = function plot(gd, wrappedTraceHolders) { } tableControlView - .attr('transform', function(d) {return 'translate(' + d.size.l + ' ' + d.size.t + ')';}); + .attr('transform', function(d) {return strTranslate(d.size.l, d.size.t);}); // scrollBackground merely ensures that mouse events are captured even on crazy fast scrollwheeling // otherwise rendering glitches may occur @@ -108,7 +109,7 @@ module.exports = function plot(gd, wrappedTraceHolders) { yColumn.exit().remove(); - yColumn.attr('transform', function(d) {return 'translate(' + d.x + ' 0)';}); + yColumn.attr('transform', function(d) {return strTranslate(d.x, 0);}); if(dynamic) { yColumn.call(d3.behavior.drag() @@ -136,10 +137,10 @@ module.exports = function plot(gd, wrappedTraceHolders) { .transition() .ease(c.transitionEase) .duration(c.transitionDuration) - .attr('transform', function(d) {return 'translate(' + d.x + ' 0)';}); + .attr('transform', function(d) {return strTranslate(d.x, 0);}); movedColumn .call(cancelEeaseColumn) - .attr('transform', 'translate(' + d.x + ' -' + c.uplift + ' )'); + .attr('transform', strTranslate(d.x, -c.uplift)); }) .on('dragend', function(d) { var movedColumn = d3.select(this); @@ -294,7 +295,7 @@ function renderScrollbarKit(tableControlView, gd, bypassVisibleBar) { }) .attr('transform', function(d) { var xPosition = d.width + c.scrollbarWidth / 2 + c.scrollbarOffset; - return 'translate(' + xPosition + ' ' + headerHeight(d) + ')'; + return strTranslate(xPosition, headerHeight(d)); }); var scrollbar = scrollbarKit.selectAll('.' + c.cn.scrollbar) @@ -313,7 +314,7 @@ function renderScrollbarKit(tableControlView, gd, bypassVisibleBar) { scrollbarSlider .attr('transform', function(d) { - return 'translate(0 ' + (d.scrollbarState.topY || 0) + ')'; + return strTranslate(0, d.scrollbarState.topY || 0); }); var scrollbarGlyph = scrollbarSlider.selectAll('.' + c.cn.scrollbarGlyph) @@ -572,7 +573,7 @@ function populateCellText(cellText, tableControlView, allColumnBlock, gd) { } else { d3.select(element.parentNode) // basic cell adjustment - compliance with `cellPad` - .attr('transform', function(d) {return 'translate(' + xPosition(d) + ' ' + c.cellPad + ')';}) + .attr('transform', function(d) {return strTranslate(xPosition(d), c.cellPad);}) .attr('text-anchor', function(d) { return ({ left: 'start', @@ -622,7 +623,7 @@ function easeColumn(selection, d, y) { .transition() .ease(c.releaseTransitionEase) .duration(c.releaseTransitionDuration) - .attr('transform', 'translate(' + d.x + ' ' + y + ')'); + .attr('transform', strTranslate(d.x, y)); } function cellsBlock(d) {return d.type === 'cells';} @@ -703,7 +704,7 @@ function updateBlockYPosition(gd, cellsColumnBlock, tableControlView) { cellsColumnBlock .attr('transform', function(d) { var yTranslate = firstRowAnchor(d.rowBlocks, d.page) - d.scrollY; - return 'translate(0 ' + yTranslate + ')'; + return strTranslate(0, yTranslate); }); // conditionally rerendering panel 0 and 1 @@ -829,7 +830,7 @@ function updateYPositionMaker(columnBlock, element, tableControlView, gd, d) { var rectBox = d3.select(element.parentNode).select('.' + c.cn.cellRect).node().getBoundingClientRect(); var currentTransform = element.transform.baseVal.consolidate(); var yPosition = rectBox.top - box.top + (currentTransform ? currentTransform.matrix.f : c.cellPad); - return 'translate(' + xPosition(d, d3.select(element.parentNode).select('.' + c.cn.cellTextHolder).node().getBoundingClientRect().width) + ' ' + yPosition + ')'; + return strTranslate(xPosition(d, d3.select(element.parentNode).select('.' + c.cn.cellTextHolder).node().getBoundingClientRect().width), yPosition); }); d.settledY = true; @@ -852,7 +853,7 @@ function setCellHeightAndPositionY(columnCell) { var l = getBlock(d); var rowAnchor = rowsHeight(l, d.key); var yOffset = rowAnchor + headerHeight; - return 'translate(0 ' + yOffset + ')'; + return strTranslate(0, yOffset); }) .selectAll('.' + c.cn.cellRect) .attr('height', function(d) {return getRow(getBlock(d), d.key).rowHeight;}); diff --git a/test/jasmine/tests/click_test.js b/test/jasmine/tests/click_test.js index 6c87ab00055..500ab236cc1 100644 --- a/test/jasmine/tests/click_test.js +++ b/test/jasmine/tests/click_test.js @@ -1083,7 +1083,7 @@ describe('Test click interactions:', function() { var fns = drag.makeFns({pos0: [start, start], posN: [end, end]}); fns.start().then(function() { - expect(plot.attr('transform')).toBe('translate(250, 280) scale(1, 1)'); + expect(plot.attr('transform')).toBe('translate(250,280)scale(1,1)'); }) .then(fns.end) .catch(failTest) diff --git a/test/jasmine/tests/colorbar_test.js b/test/jasmine/tests/colorbar_test.js index fca097ee5fa..e67eb841d21 100644 --- a/test/jasmine/tests/colorbar_test.js +++ b/test/jasmine/tests/colorbar_test.js @@ -338,8 +338,8 @@ describe('Test colorbar:', function() { var yAxes = d3.select(gd).selectAll('.parcoords .y-axis'); expect(yAxes.size()).toBe(2); var transform = yAxes[0][1].getAttribute('transform'); - if(expandedMargin) expect(transform).not.toBe('translate(400, 0)'); - else expect(transform).toBe('translate(400, 0)'); + if(expandedMargin) expect(transform).not.toBe('translate(400,0)'); + else expect(transform).toBe('translate(400,0)'); var cbfills = colorbars.selectAll('.cbfill'); expect(cbfills.size()).toBe(present ? 1 : 0); diff --git a/test/jasmine/tests/drawing_test.js b/test/jasmine/tests/drawing_test.js index 556a30c5762..b5c3c0100ec 100644 --- a/test/jasmine/tests/drawing_test.js +++ b/test/jasmine/tests/drawing_test.js @@ -79,19 +79,19 @@ describe('Drawing', function() { expect(Drawing.getTranslate(el)).toEqual({ x: 0, y: 0 }); - el.setAttribute('transform', 'translate(123.45px, 67)'); + el.setAttribute('transform', 'translate(123.45px,67)'); expect(Drawing.getTranslate(el)).toEqual({ x: 123.45, y: 67 }); el.setAttribute('transform', 'translate(123.45)'); expect(Drawing.getTranslate(el)).toEqual({ x: 123.45, y: 0 }); - el.setAttribute('transform', 'translate(1 2)'); + el.setAttribute('transform', 'translate(1,2)'); expect(Drawing.getTranslate(el)).toEqual({ x: 1, y: 2 }); - el.setAttribute('transform', 'translate(1 2); rotate(20deg)'); + el.setAttribute('transform', 'translate(1,2); rotate(20deg)'); expect(Drawing.getTranslate(el)).toEqual({ x: 1, y: 2 }); - el.setAttribute('transform', 'rotate(20deg) translate(1 2);'); + el.setAttribute('transform', 'rotate(20deg)translate(1,2);'); expect(Drawing.getTranslate(el)).toEqual({ x: 1, y: 2 }); el.setAttribute('transform', 'rotate(20deg)'); @@ -101,16 +101,16 @@ describe('Drawing', function() { it('should work with d3 elements', function() { var el = d3.select(document.createElement('div')); - el.attr('transform', 'translate(123.45px, 67)'); + el.attr('transform', 'translate(123.45px,67)'); expect(Drawing.getTranslate(el)).toEqual({ x: 123.45, y: 67 }); el.attr('transform', 'translate(123.45)'); expect(Drawing.getTranslate(el)).toEqual({ x: 123.45, y: 0 }); - el.attr('transform', 'translate(1 2)'); + el.attr('transform', 'translate(1,2)'); expect(Drawing.getTranslate(el)).toEqual({ x: 1, y: 2 }); - el.attr('transform', 'translate(1 2); rotate(20)'); + el.attr('transform', 'translate(1,2); rotate(20)'); expect(Drawing.getTranslate(el)).toEqual({ x: 1, y: 2 }); el.attr('transform', 'rotate(20)'); @@ -124,19 +124,19 @@ describe('Drawing', function() { expect(Drawing.getTranslate(el)).toEqual({ x: 0, y: 0 }); var testCases = [ - { transform: 'translate(-123.45px, -67)', x: -123.45, y: -67 }, - { transform: 'translate(-123.45px, 67)', x: -123.45, y: 67 }, - { transform: 'translate(123.45px, -67)', x: 123.45, y: -67 }, + { transform: 'translate(-123.45px,-67)', x: -123.45, y: -67 }, + { transform: 'translate(-123.45px,67)', x: -123.45, y: 67 }, + { transform: 'translate(123.45px,-67)', x: 123.45, y: -67 }, { transform: 'translate(-123.45)', x: -123.45, y: 0 }, - { transform: 'translate(-1 -2)', x: -1, y: -2 }, - { transform: 'translate(-1 2)', x: -1, y: 2 }, - { transform: 'translate(1 -2)', x: 1, y: -2 }, - { transform: 'translate(-1 -2); rotate(20deg)', x: -1, y: -2 }, - { transform: 'translate(-1 2); rotate(20deg)', x: -1, y: 2 }, - { transform: 'translate(1 -2); rotate(20deg)', x: 1, y: -2 }, - { transform: 'rotate(20deg) translate(-1 -2);', x: -1, y: -2 }, - { transform: 'rotate(20deg) translate(-1 2);', x: -1, y: 2 }, - { transform: 'rotate(20deg) translate(1 -2);', x: 1, y: -2 } + { transform: 'translate(-1,-2)', x: -1, y: -2 }, + { transform: 'translate(-1,2)', x: -1, y: 2 }, + { transform: 'translate(1,-2)', x: 1, y: -2 }, + { transform: 'translate(-1,-2); rotate(20deg)', x: -1, y: -2 }, + { transform: 'translate(-1,2); rotate(20deg)', x: -1, y: 2 }, + { transform: 'translate(1,-2); rotate(20deg)', x: 1, y: -2 }, + { transform: 'rotate(20deg)translate(-1,-2);', x: -1, y: -2 }, + { transform: 'rotate(20deg)translate(-1,2);', x: -1, y: 2 }, + { transform: 'rotate(20deg)translate(1,-2);', x: 1, y: -2 } ]; for(var i = 0; i < testCases.length; i++) { @@ -159,34 +159,34 @@ describe('Drawing', function() { var el = document.createElement('div'); Drawing.setTranslate(el, 5); - expect(el.getAttribute('transform')).toBe('translate(5, 0)'); + expect(el.getAttribute('transform')).toBe('translate(5,0)'); Drawing.setTranslate(el, 10, 20); - expect(el.getAttribute('transform')).toBe('translate(10, 20)'); + expect(el.getAttribute('transform')).toBe('translate(10,20)'); Drawing.setTranslate(el); - expect(el.getAttribute('transform')).toBe('translate(0, 0)'); + expect(el.getAttribute('transform')).toBe(''); - el.setAttribute('transform', 'translate(0, 0); rotate(30)'); + el.setAttribute('transform', 'rotate(30)'); Drawing.setTranslate(el, 30, 40); - expect(el.getAttribute('transform')).toBe('rotate(30) translate(30, 40)'); + expect(el.getAttribute('transform')).toBe('rotate(30)translate(30,40)'); }); it('should work with d3 elements', function() { var el = d3.select(document.createElement('div')); Drawing.setTranslate(el, 5); - expect(el.attr('transform')).toBe('translate(5, 0)'); + expect(el.attr('transform')).toBe('translate(5,0)'); Drawing.setTranslate(el, 30, 40); - expect(el.attr('transform')).toBe('translate(30, 40)'); + expect(el.attr('transform')).toBe('translate(30,40)'); Drawing.setTranslate(el); - expect(el.attr('transform')).toBe('translate(0, 0)'); + expect(el.attr('transform')).toBe(''); - el.attr('transform', 'translate(0, 0); rotate(30)'); + el.attr('transform', 'rotate(30)'); Drawing.setTranslate(el, 30, 40); - expect(el.attr('transform')).toBe('rotate(30) translate(30, 40)'); + expect(el.attr('transform')).toBe('rotate(30)translate(30,40)'); }); }); @@ -202,13 +202,13 @@ describe('Drawing', function() { el.setAttribute('transform', 'scale(123.45)'); expect(Drawing.getScale(el)).toEqual({ x: 123.45, y: 1 }); - el.setAttribute('transform', 'scale(0.1 2)'); + el.setAttribute('transform', 'scale(0.1,2)'); expect(Drawing.getScale(el)).toEqual({ x: 0.1, y: 2 }); - el.setAttribute('transform', 'scale(0.1 2); rotate(20deg)'); + el.setAttribute('transform', 'scale(0.1,2); rotate(20deg)'); expect(Drawing.getScale(el)).toEqual({ x: 0.1, y: 2 }); - el.setAttribute('transform', 'rotate(20deg) scale(0.1 2);'); + el.setAttribute('transform', 'rotate(20deg)scale(0.1,2);'); expect(Drawing.getScale(el)).toEqual({ x: 0.1, y: 2 }); el.setAttribute('transform', 'rotate(20deg)'); @@ -218,16 +218,16 @@ describe('Drawing', function() { it('should work with d3 elements', function() { var el = d3.select(document.createElement('div')); - el.attr('transform', 'scale(1.23, 45)'); + el.attr('transform', 'scale(1.23,45)'); expect(Drawing.getScale(el)).toEqual({ x: 1.23, y: 45 }); el.attr('transform', 'scale(123.45)'); expect(Drawing.getScale(el)).toEqual({ x: 123.45, y: 1 }); - el.attr('transform', 'scale(0.1 2)'); + el.attr('transform', 'scale(0.1,2)'); expect(Drawing.getScale(el)).toEqual({ x: 0.1, y: 2 }); - el.attr('transform', 'scale(0.1 2); rotate(20)'); + el.attr('transform', 'scale(0.1,2); rotate(20)'); expect(Drawing.getScale(el)).toEqual({ x: 0.1, y: 2 }); el.attr('transform', 'rotate(20)'); @@ -240,34 +240,34 @@ describe('Drawing', function() { var el = document.createElement('div'); Drawing.setScale(el, 5); - expect(el.getAttribute('transform')).toBe('scale(5, 1)'); + expect(el.getAttribute('transform')).toBe('scale(5,1)'); Drawing.setScale(el, 30, 40); - expect(el.getAttribute('transform')).toBe('scale(30, 40)'); + expect(el.getAttribute('transform')).toBe('scale(30,40)'); Drawing.setScale(el); - expect(el.getAttribute('transform')).toBe('scale(1, 1)'); + expect(el.getAttribute('transform')).toBe('scale(1,1)'); - el.setAttribute('transform', 'scale(1, 1); rotate(30)'); + el.setAttribute('transform', 'scale(1,1); rotate(30)'); Drawing.setScale(el, 30, 40); - expect(el.getAttribute('transform')).toBe('rotate(30) scale(30, 40)'); + expect(el.getAttribute('transform')).toBe('rotate(30)scale(30,40)'); }); it('should work with d3 elements', function() { var el = d3.select(document.createElement('div')); Drawing.setScale(el, 5); - expect(el.attr('transform')).toBe('scale(5, 1)'); + expect(el.attr('transform')).toBe('scale(5,1)'); Drawing.setScale(el, 30, 40); - expect(el.attr('transform')).toBe('scale(30, 40)'); + expect(el.attr('transform')).toBe('scale(30,40)'); Drawing.setScale(el); - expect(el.attr('transform')).toBe('scale(1, 1)'); + expect(el.attr('transform')).toBe('scale(1,1)'); - el.attr('transform', 'scale(0, 0); rotate(30)'); + el.attr('transform', 'scale(0,0); rotate(30)'); Drawing.setScale(el, 30, 40); - expect(el.attr('transform')).toBe('rotate(30) scale(30, 40)'); + expect(el.attr('transform')).toBe('rotate(30)scale(30,40)'); }); }); @@ -287,23 +287,23 @@ describe('Drawing', function() { it('appends the scale of a point', function() { el.setAttribute('transform', 'translate(1,2)'); Drawing.setPointGroupScale(sel, 2, 2); - expect(el.getAttribute('transform')).toBe('translate(1,2) scale(2,2)'); + expect(el.getAttribute('transform')).toBe('translate(1,2)scale(2,2)'); }); it('modifies the scale of a point', function() { - el.setAttribute('transform', 'translate(1,2) scale(3,4)'); + el.setAttribute('transform', 'translate(1,2)scale(3,4)'); Drawing.setPointGroupScale(sel, 2, 2); - expect(el.getAttribute('transform')).toBe('translate(1,2) scale(2,2)'); + expect(el.getAttribute('transform')).toBe('translate(1,2)scale(2,2)'); }); - it('does not apply the scale of a point if scale (1, 1)', function() { + it('does not apply the scale of a point if scale (1,1)', function() { el.setAttribute('transform', 'translate(1,2)'); Drawing.setPointGroupScale(sel, 1, 1); expect(el.getAttribute('transform')).toBe('translate(1,2)'); }); - it('removes the scale of a point if scale (1, 1)', function() { - el.setAttribute('transform', 'translate(1,2) scale(3,4)'); + it('removes the scale of a point if scale (1,1)', function() { + el.setAttribute('transform', 'translate(1,2)scale(3,4)'); Drawing.setPointGroupScale(sel, 1, 1); expect(el.getAttribute('transform')).toBe('translate(1,2)'); }); @@ -320,7 +320,7 @@ describe('Drawing', function() { it('sets the transform on an empty element', function() { Drawing.setTextPointsScale(g, 2, 3); - expect(g.attr('transform')).toEqual('translate(0,0) scale(2,3) translate(0,0)'); + expect(g.attr('transform')).toEqual('scale(2,3)'); }); it('unsets the transform', function() { @@ -330,16 +330,16 @@ describe('Drawing', function() { it('preserves a leading translate', function() { Drawing.setTextPointsScale(g, 1, 1); - g.attr('transform', 'translate(1, 2)'); - expect(g.attr('transform')).toEqual('translate(1, 2)'); + g.attr('transform', 'translate(1,2)'); + expect(g.attr('transform')).toEqual('translate(1,2)'); }); it('preserves transforms', function() { text.attr('x', 8); text.attr('y', 9); - g.attr('transform', 'translate(1, 2)'); + g.attr('transform', 'translate(1,2)'); Drawing.setTextPointsScale(g, 4, 5); - expect(g.attr('transform')).toEqual('translate(8,9) scale(4,5) translate(-8,-9) translate(1, 2)'); + expect(g.attr('transform')).toEqual('translate(8,9)scale(4,5)translate(-8,-9)translate(1,2)'); }); it('should not break when is not present', function() { diff --git a/test/jasmine/tests/indicator_test.js b/test/jasmine/tests/indicator_test.js index 69f247d31b5..fb987c4b284 100644 --- a/test/jasmine/tests/indicator_test.js +++ b/test/jasmine/tests/indicator_test.js @@ -154,8 +154,7 @@ describe('Indicator plot', function() { expect(numbers.length).toBe(1); var transform = numbers.attr('transform'); - expect(transform.match('scale')).toBeTruthy('cannot find scale attribute on text.numbers[0]'); - var scale = transform.match(/.*scale\((.*)\)/)[1]; + var scale = transform.match('scale') ? transform.match(/.*scale\((.*)\)/)[1] : 1; expect(scale).toBeCloseTo(value, 1, msg); } diff --git a/test/jasmine/tests/legend_scroll_test.js b/test/jasmine/tests/legend_scroll_test.js index e1e31f7c3e7..80eba3f4400 100644 --- a/test/jasmine/tests/legend_scroll_test.js +++ b/test/jasmine/tests/legend_scroll_test.js @@ -109,7 +109,7 @@ describe('The legend', function() { expect(getScroll(gd)).toBe(finalDataScroll); expect(scrollBox.getAttribute('transform')).toBe( - 'translate(0, ' + -finalDataScroll + ')'); + 'translate(0,' + -finalDataScroll + ')'); }); function dragScroll(element, rightClick, mainClick) { @@ -158,7 +158,7 @@ describe('The legend', function() { var dataScroll = getScroll(gd); expect(dataScroll).toBeCloseTo(finalDataScroll, 3); expect(scrollBox.getAttribute('transform')).toBe( - 'translate(0, ' + -dataScroll + ')'); + 'translate(0,' + -dataScroll + ')'); }); it('should not scroll on dragging the scrollbox with a mouse', function() { @@ -167,8 +167,7 @@ describe('The legend', function() { var dataScroll = getScroll(gd); expect(dataScroll).not.toBeCloseTo(finalDataScroll, 3); - expect(scrollBox.getAttribute('transform')).toBe( - 'translate(0, ' + -dataScroll + ')'); + expect(scrollBox.getAttribute('transform')).toBe(''); }); it('should handle touch events on scrollbox', function(done) { @@ -227,8 +226,7 @@ describe('The legend', function() { var dataScroll = getScroll(gd); expect(dataScroll).not.toBeCloseTo(finalDataScroll, 3); - expect(scrollBox.getAttribute('transform')).toBe( - 'translate(0, ' + -dataScroll + ')'); + expect(scrollBox.getAttribute('transform')).toBe(''); }); it('removes scroll bar and handlers when switching to horizontal', function(done) { @@ -307,7 +305,7 @@ describe('The legend', function() { expect(+toggle.parentNode.style.opacity).toBeLessThan(1); expect(getScroll(gd)).toBe(dataScroll); expect(scrollBox.getAttribute('transform')).toBe( - 'translate(0, ' + -dataScroll + ')'); + 'translate(0,' + -dataScroll + ')'); done(); }, DBLCLICKDELAY * 2); }); @@ -345,7 +343,7 @@ describe('The legend', function() { expect(+toggle.parentNode.style.opacity).toBeLessThan(1); expect(getScroll(gd)).toBe(dataScroll); expect(scrollBox.getAttribute('transform')).toBe( - 'translate(0, ' + -dataScroll + ')'); + 'translate(0,' + -dataScroll + ')'); expect(scrollBar.getAttribute('width')).toBeGreaterThan(0); expect(scrollBar.getAttribute('height')).toBeGreaterThan(0); done(); @@ -357,10 +355,10 @@ describe('The legend', function() { var scrollBox = getScrollBox(); legend.dispatchEvent(scrollTo(-100)); - expect(scrollBox.getAttribute('transform')).toBe('translate(0, 0)'); + expect(scrollBox.getAttribute('transform')).toBe(''); legend.dispatchEvent(scrollTo(100000)); - expect(scrollBox.getAttribute('transform')).toBe('translate(0, -179)'); + expect(scrollBox.getAttribute('transform')).toBe('translate(0,-179)'); }); it('should scale the scrollbar movement from top to bottom', function() { diff --git a/test/jasmine/tests/parcats_test.js b/test/jasmine/tests/parcats_test.js index eb5828ef87b..1ab3cbd8a48 100644 --- a/test/jasmine/tests/parcats_test.js +++ b/test/jasmine/tests/parcats_test.js @@ -1,5 +1,6 @@ var Plotly = require('@lib/index'); var Lib = require('@src/lib'); +var strTranslate = Lib.strTranslate; var d3 = require('d3'); var createGraphDiv = require('../assets/create_graph_div'); @@ -104,7 +105,7 @@ function checkParcatsSvg(gd) { var parcatsTraceSelection = d3.select('g.trace.parcats'); expect(parcatsTraceSelection.attr('transform')).toEqual( - makeTranslate( + strTranslate( size.w * domain.x[0] + margin.r, size.h * domain.y[0] + margin.t)); @@ -116,7 +117,7 @@ function checkParcatsSvg(gd) { dimensionSelection.each(function(dimension, dimInd) { var expectedX = categoryLabelPad + dimInd * dimDx; var expectedY = 0; - var expectedTransform = makeTranslate(expectedX, expectedY); + var expectedTransform = strTranslate(expectedX, expectedY); expect(d3.select(this).attr('transform')).toEqual(expectedTransform); }); @@ -130,7 +131,7 @@ function checkParcatsSvg(gd) { var catWidth = catSel.datum().width; var catHeight = catSel.datum().height; - var expectedTransform = 'translate(0, ' + nextY + ')'; + var expectedTransform = strTranslate(0, nextY); expect(catSel.attr('transform')).toEqual(expectedTransform); nextY += category.height + catSpacing; @@ -151,10 +152,6 @@ function checkParcatsSvg(gd) { }); } -function makeTranslate(x, y) { - return 'translate(' + x + ', ' + y + ')'; -} - // Test cases // ==========