| 77 | } |
| 78 | |
| 79 | function drawOne(gd, index) { |
| 80 | // remove the existing shape if there is one. |
| 81 | // because indices can change, we need to look in all shape layers |
| 82 | gd._fullLayout._paperdiv.selectAll('.shapelayer [data-index="' + index + '"]').remove(); |
| 83 | |
| 84 | var o = helpers.makeShapesOptionsAndPlotinfo(gd, index); |
| 85 | var options = o.options; |
| 86 | var plotinfo = o.plotinfo; |
| 87 | |
| 88 | // this shape is gone - quit now after deleting it |
| 89 | // TODO: use d3 idioms instead of deleting and redrawing every time |
| 90 | if (!options._input || options.visible !== true) return; |
| 91 | |
| 92 | const isMultiAxisShape = Array.isArray(options.xref) || Array.isArray(options.yref); |
| 93 | |
| 94 | if (options.layer === 'above') { |
| 95 | drawShape(gd._fullLayout._shapeUpperLayer); |
| 96 | } else if (options.xref.includes('paper') || options.yref.includes('paper')) { |
| 97 | drawShape(gd._fullLayout._shapeLowerLayer); |
| 98 | } else if (options.layer === 'between' && !isMultiAxisShape) { |
| 99 | drawShape(plotinfo.shapelayerBetween); |
| 100 | } else { |
| 101 | if (plotinfo._hadPlotinfo) { |
| 102 | var mainPlot = plotinfo.mainplotinfo || plotinfo; |
| 103 | drawShape(mainPlot.shapelayer); |
| 104 | } else { |
| 105 | // Fall back to _shapeLowerLayer in case the requested subplot doesn't exist. |
| 106 | // This can happen if you reference the shape to an x / y axis combination |
| 107 | // that doesn't have any data on it (and layer is below) |
| 108 | drawShape(gd._fullLayout._shapeLowerLayer); |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | function drawShape(shapeLayer) { |
| 113 | var d = getPathString(gd, options); |
| 114 | var attrs = { |
| 115 | 'data-index': index, |
| 116 | 'fill-rule': options.fillrule, |
| 117 | d: d |
| 118 | }; |
| 119 | |
| 120 | var opacity = options.opacity; |
| 121 | var fillColor = options.fillcolor; |
| 122 | var lineColor = options.line.width ? options.line.color : 'rgba(0,0,0,0)'; |
| 123 | var lineWidth = options.line.width; |
| 124 | var lineDash = options.line.dash; |
| 125 | if (!lineWidth && options.editable === true) { |
| 126 | // ensure invisible border to activate the shape |
| 127 | lineWidth = 5; |
| 128 | lineDash = 'solid'; |
| 129 | } |
| 130 | |
| 131 | var isOpen = d[d.length - 1] !== 'Z'; |
| 132 | |
| 133 | var isActiveShape = couldHaveActiveShape(gd) && options.editable && gd._fullLayout._activeShapeIndex === index; |
| 134 | |
| 135 | if (isActiveShape) { |
| 136 | fillColor = isOpen ? 'rgba(0,0,0,0)' : gd._fullLayout.activeshape.fillcolor; |