'use strict'; var dragHelpers = require('../../dragelement/helpers'); var drawMode = dragHelpers.drawMode; var openMode = dragHelpers.openMode; var constants = require('./constants'); var i000 = constants.i000; var i090 = constants.i090; var i180 = constants.i180; var i270 = constants.i270; var cos45 = constants.cos45; var sin45 = constants.sin45; var cartesianHelpers = require('../../selections/helpers'); var p2r = cartesianHelpers.p2r; var r2p = cartesianHelpers.r2p; var handleOutline = require('.././handle_outline'); var clearOutline = handleOutline.clearOutline; var helpers = require('./helpers'); var readPaths = helpers.readPaths; var writePaths = helpers.writePaths; var ellipseOver = helpers.ellipseOver; var fixDatesForPaths = helpers.fixDatesForPaths; function newShapes(outlines, dragOptions) { if(!outlines.length) return; var e = outlines[0][0]; // pick first if(!e) return; var gd = dragOptions.gd; var isActiveShape = dragOptions.isActiveShape; var dragmode = dragOptions.dragmode; var shapes = (gd.layout || {}).shapes || []; if(!drawMode(dragmode) && isActiveShape !== undefined) { var id = gd._fullLayout._activeShapeIndex; if(id < shapes.length) { switch(gd._fullLayout.shapes[id].type) { case 'rect': dragmode = 'drawrect'; break; case 'circle': dragmode = 'drawcircle'; break; case 'line': dragmode = 'drawline'; break; case 'path': var path = shapes[id].path || ''; if(path[path.length - 1] === 'Z') { dragmode = 'drawclosedpath'; } else { dragmode = 'drawopenpath'; } break; } } } var newShape = createShapeObj(outlines, dragOptions, dragmode); clearOutline(gd); var editHelpers = dragOptions.editHelpers; var modifyItem = (editHelpers || {}).modifyItem; var allShapes = []; for(var q = 0; q < shapes.length; q++) { var beforeEdit = gd._fullLayout.shapes[q]; allShapes[q] = beforeEdit._input; if( isActiveShape !== undefined && q === gd._fullLayout._activeShapeIndex ) { var afterEdit = newShape; switch(beforeEdit.type) { case 'line': case 'rect': case 'circle': modifyItem('x0', afterEdit.x0 - (beforeEdit.x0shift || 0)); modifyItem('x1', afterEdit.x1 - (beforeEdit.x1shift || 0)); modifyItem('y0', afterEdit.y0 - (beforeEdit.y0shift || 0)); modifyItem('y1', afterEdit.y1 - (beforeEdit.y1shift || 0)); break; case 'path': modifyItem('path', afterEdit.path); break; } } } if(isActiveShape === undefined) { allShapes.push(newShape); // add new shape return allShapes; } return editHelpers ? editHelpers.getUpdateObj() : {}; } function createShapeObj(outlines, dragOptions, dragmode) { var e = outlines[0][0]; // pick first outline var gd = dragOptions.gd; var d = e.getAttribute('d'); var newStyle = gd._fullLayout.newshape; var plotinfo = dragOptions.plotinfo; var isActiveShape = dragOptions.isActiveShape; var xaxis = plotinfo.xaxis; var yaxis = plotinfo.yaxis; var xPaper = !!plotinfo.domain || !plotinfo.xaxis; var yPaper = !!plotinfo.domain || !plotinfo.yaxis; var isOpenMode = openMode(dragmode); var polygons = readPaths(d, gd, plotinfo, isActiveShape); var newShape = { editable: true, visible: newStyle.visible, name: newStyle.name, showlegend: newStyle.showlegend, legend: newStyle.legend, legendwidth: newStyle.legendwidth, legendgroup: newStyle.legendgroup, legendgrouptitle: { text: newStyle.legendgrouptitle.text, font: newStyle.legendgrouptitle.font }, legendrank: newStyle.legendrank, label: newStyle.label, xref: xPaper ? 'paper' : xaxis._id, yref: yPaper ? 'paper' : yaxis._id, layer: newStyle.layer, opacity: newStyle.opacity, line: { color: newStyle.line.color, width: newStyle.line.width, dash: newStyle.line.dash } }; if(!isOpenMode) { newShape.fillcolor = newStyle.fillcolor; newShape.fillrule = newStyle.fillrule; } var cell; // line, rect and circle can be in one cell // only define cell if there is single cell if(polygons.length === 1) cell = polygons[0]; if( cell && cell.length === 5 && // ensure we only have 4 corners for a rect dragmode === 'drawrect' ) { newShape.type = 'rect'; newShape.x0 = cell[0][1]; newShape.y0 = cell[0][2]; newShape.x1 = cell[2][1]; newShape.y1 = cell[2][2]; } else if( cell && dragmode === 'drawline' ) { newShape.type = 'line'; newShape.x0 = cell[0][1]; newShape.y0 = cell[0][2]; newShape.x1 = cell[1][1]; newShape.y1 = cell[1][2]; } else if( cell && dragmode === 'drawcircle' ) { newShape.type = 'circle'; // an ellipse! var xA = cell[i000][1]; var xB = cell[i090][1]; var xC = cell[i180][1]; var xD = cell[i270][1]; var yA = cell[i000][2]; var yB = cell[i090][2]; var yC = cell[i180][2]; var yD = cell[i270][2]; var xDateOrLog = plotinfo.xaxis && ( plotinfo.xaxis.type === 'date' || plotinfo.xaxis.type === 'log' ); var yDateOrLog = plotinfo.yaxis && ( plotinfo.yaxis.type === 'date' || plotinfo.yaxis.type === 'log' ); if(xDateOrLog) { xA = r2p(plotinfo.xaxis, xA); xB = r2p(plotinfo.xaxis, xB); xC = r2p(plotinfo.xaxis, xC); xD = r2p(plotinfo.xaxis, xD); } if(yDateOrLog) { yA = r2p(plotinfo.yaxis, yA); yB = r2p(plotinfo.yaxis, yB); yC = r2p(plotinfo.yaxis, yC); yD = r2p(plotinfo.yaxis, yD); } var x0 = (xB + xD) / 2; var y0 = (yA + yC) / 2; var rx = (xD - xB + xC - xA) / 2; var ry = (yD - yB + yC - yA) / 2; var pos = ellipseOver({ x0: x0, y0: y0, x1: x0 + rx * cos45, y1: y0 + ry * sin45 }); if(xDateOrLog) { pos.x0 = p2r(plotinfo.xaxis, pos.x0); pos.x1 = p2r(plotinfo.xaxis, pos.x1); } if(yDateOrLog) { pos.y0 = p2r(plotinfo.yaxis, pos.y0); pos.y1 = p2r(plotinfo.yaxis, pos.y1); } newShape.x0 = pos.x0; newShape.y0 = pos.y0; newShape.x1 = pos.x1; newShape.y1 = pos.y1; } else { newShape.type = 'path'; if(xaxis && yaxis) fixDatesForPaths(polygons, xaxis, yaxis); newShape.path = writePaths(polygons); cell = null; } return newShape; } module.exports = { newShapes: newShapes, createShapeObj: createShapeObj, };