-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Add polar.hole
#2977
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add polar.hole
#2977
Changes from 3 commits
39b2ee3
ea7fd2c
f547692
35199c6
8e5833d
ea877ee
a859872
776e292
9c3dcef
1122907
d466146
5a998a2
092006a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -126,9 +126,9 @@ proto.updateLayers = function(fullLayout, polarLayout) { | |
|
||
switch(d) { | ||
case 'frontplot': | ||
sel.append('g').classed('scatterlayer', true); | ||
// TODO add option to place in 'backplot' layer?? | ||
sel.append('g').classed('barlayer', true); | ||
sel.append('g').classed('scatterlayer', true); | ||
break; | ||
case 'backplot': | ||
sel.append('g').classed('maplayer', true); | ||
|
@@ -234,6 +234,8 @@ proto.updateLayout = function(fullLayout, polarLayout) { | |
var yOffset2 = _this.yOffset2 = gs.t + gs.h * (1 - yDomain2[1]); | ||
// circle radius in px | ||
var radius = _this.radius = xLength2 / dxSectorBBox; | ||
// 'inner' radius in px (when polar.hole is set) | ||
var innerRadius = _this.innerRadius = polarLayout.hole * radius; | ||
// circle center position in px | ||
var cx = _this.cx = xOffset2 - radius * sectorBBox[0]; | ||
var cy = _this.cy = yOffset2 + radius * sectorBBox[3]; | ||
|
@@ -252,7 +254,7 @@ proto.updateLayout = function(fullLayout, polarLayout) { | |
clockwise: 'bottom' | ||
}[radialLayout.side], | ||
// spans length 1 radius | ||
domain: [0, radius / gs.w] | ||
domain: [innerRadius / gs.w, radius / gs.w] | ||
}); | ||
|
||
_this.angularAxis = _this.mockAxis(fullLayout, polarLayout, angularLayout, { | ||
|
@@ -282,7 +284,7 @@ proto.updateLayout = function(fullLayout, polarLayout) { | |
domain: yDomain2 | ||
}); | ||
|
||
var dPath = _this.pathSector(); | ||
var dPath = _this.pathSubplot(); | ||
|
||
_this.clipPaths.forTraces.select('path') | ||
.attr('d', dPath) | ||
|
@@ -333,9 +335,11 @@ proto.mockCartesianAxis = function(fullLayout, polarLayout, opts) { | |
|
||
ax.setRange = function() { | ||
var sectorBBox = _this.sectorBBox; | ||
var rl = _this.radialAxis._rl; | ||
var drl = rl[1] - rl[0]; | ||
var ind = bboxIndices[axId]; | ||
var rl = _this.radialAxis._rl; | ||
var radius = _this.radius; | ||
var innerRadius = _this.innerRadius; | ||
var drl = radius * (rl[1] - rl[0]) / (radius - innerRadius); | ||
alexcjohnson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ax.range = [sectorBBox[ind[0]] * drl, sectorBBox[ind[1]] * drl]; | ||
}; | ||
|
||
|
@@ -371,6 +375,7 @@ proto.updateRadialAxis = function(fullLayout, polarLayout) { | |
var gd = _this.gd; | ||
var layers = _this.layers; | ||
var radius = _this.radius; | ||
var innerRadius = _this.innerRadius; | ||
var cx = _this.cx; | ||
var cy = _this.cy; | ||
var radialLayout = polarLayout.radialaxis; | ||
|
@@ -392,12 +397,12 @@ proto.updateRadialAxis = function(fullLayout, polarLayout) { | |
|
||
// easier to set rotate angle with custom translate function | ||
ax._transfn = function(d) { | ||
return 'translate(' + ax.l2p(d.x) + ',0)'; | ||
return 'translate(' + (ax.l2p(d.x) + innerRadius) + ',0)'; | ||
}; | ||
|
||
// set special grid path function | ||
ax._gridpath = function(d) { | ||
return _this.pathArc(ax.r2p(d.x)); | ||
return _this.pathArc(ax.r2p(d.x) + innerRadius); | ||
}; | ||
|
||
var newTickLayout = strTickLayout(radialLayout); | ||
|
@@ -428,7 +433,7 @@ proto.updateRadialAxis = function(fullLayout, polarLayout) { | |
.selectAll('path').attr('transform', null); | ||
|
||
updateElement(layers['radial-line'].select('line'), radialLayout.showline, { | ||
x1: 0, | ||
x1: innerRadius, | ||
y1: 0, | ||
x2: radius, | ||
y2: 0, | ||
|
@@ -479,6 +484,7 @@ proto.updateAngularAxis = function(fullLayout, polarLayout) { | |
var gd = _this.gd; | ||
var layers = _this.layers; | ||
var radius = _this.radius; | ||
var innerRadius = _this.innerRadius; | ||
var cx = _this.cx; | ||
var cy = _this.cy; | ||
var angularLayout = polarLayout.angularaxis; | ||
|
@@ -491,11 +497,6 @@ proto.updateAngularAxis = function(fullLayout, polarLayout) { | |
// 't'ick to 'g'eometric radians is used all over the place here | ||
var t2g = function(d) { return ax.t2g(d.x); }; | ||
|
||
// (x,y) at max radius | ||
function rad2xy(rad) { | ||
return [radius * Math.cos(rad), radius * Math.sin(rad)]; | ||
} | ||
|
||
// run rad2deg on tick0 and ditck for thetaunit: 'radians' axes | ||
if(ax.type === 'linear' && ax.thetaunit === 'radians') { | ||
ax.tick0 = rad2deg(ax.tick0); | ||
|
@@ -512,13 +513,17 @@ proto.updateAngularAxis = function(fullLayout, polarLayout) { | |
} | ||
|
||
ax._transfn = function(d) { | ||
var sel = d3.select(this); | ||
var hasElement = sel && sel.node(); | ||
|
||
// don't translate grid lines | ||
if(hasElement && sel.classed('angularaxisgrid')) return ''; | ||
|
||
var rad = t2g(d); | ||
var xy = rad2xy(rad); | ||
var out = strTranslate(cx + xy[0], cy - xy[1]); | ||
var out = strTranslate(cx + radius * Math.cos(rad), cy - radius * Math.sin(rad)); | ||
|
||
// must also rotate ticks, but don't rotate labels and grid lines | ||
var sel = d3.select(this); | ||
if(sel && sel.node() && sel.classed('ticks')) { | ||
// must also rotate ticks, but don't rotate labels | ||
if(hasElement && sel.classed('ticks')) { | ||
out += strRotate(-rad2deg(rad)); | ||
} | ||
|
||
|
@@ -527,8 +532,10 @@ proto.updateAngularAxis = function(fullLayout, polarLayout) { | |
|
||
ax._gridpath = function(d) { | ||
var rad = t2g(d); | ||
var xy = rad2xy(rad); | ||
return 'M0,0L' + (-xy[0]) + ',' + xy[1]; | ||
var cosRad = Math.cos(rad); | ||
var sinRad = Math.sin(rad); | ||
return 'M' + [cx + innerRadius * cosRad, cy - innerRadius * sinRad] + | ||
'L' + [cx + radius * cosRad, cy - radius * sinRad]; | ||
}; | ||
|
||
var offset4fontsize = (angularLayout.ticks !== 'outside' ? 0.7 : 0.5); | ||
|
@@ -590,8 +597,11 @@ proto.updateAngularAxis = function(fullLayout, polarLayout) { | |
} | ||
_this.vangles = vangles; | ||
|
||
// TODO maybe two arcs is better here? | ||
// maybe split style attributes between inner and outer angular axes? | ||
alexcjohnson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
updateElement(layers['angular-line'].select('path'), angularLayout.showline, { | ||
d: _this.pathSector(), | ||
d: _this.pathSubplot(), | ||
transform: strTranslate(cx, cy) | ||
}) | ||
.attr('stroke-width', angularLayout.linewidth) | ||
|
@@ -614,6 +624,7 @@ proto.updateMainDrag = function(fullLayout) { | |
var MINZOOM = constants.MINZOOM; | ||
var OFFEDGE = constants.OFFEDGE; | ||
var radius = _this.radius; | ||
var innerRadius = _this.innerRadius; | ||
var cx = _this.cx; | ||
var cy = _this.cy; | ||
var cxx = _this.cxx; | ||
|
@@ -629,7 +640,7 @@ proto.updateMainDrag = function(fullLayout) { | |
var mainDrag = dragBox.makeDragger(layers, 'path', 'maindrag', 'crosshair'); | ||
|
||
d3.select(mainDrag) | ||
.attr('d', _this.pathSector()) | ||
.attr('d', _this.pathSubplot()) | ||
.attr('transform', strTranslate(cx, cy)); | ||
|
||
var dragOpts = { | ||
|
@@ -727,7 +738,7 @@ proto.updateMainDrag = function(fullLayout) { | |
function zoomPrep() { | ||
r0 = null; | ||
r1 = null; | ||
path0 = _this.pathSector(); | ||
path0 = _this.pathSubplot(); | ||
dimmed = false; | ||
|
||
var polarLayoutNow = gd._fullLayout[_this.id]; | ||
|
@@ -742,7 +753,7 @@ proto.updateMainDrag = function(fullLayout) { | |
// N.B. this sets scoped 'r0' and 'r1' | ||
// return true if 'valid' zoom distance, false otherwise | ||
function clampAndSetR0R1(rr0, rr1) { | ||
rr1 = Math.min(rr1, radius); | ||
rr1 = Math.max(Math.min(rr1, radius), innerRadius); | ||
|
||
// starting or ending drag near center (outer edge), | ||
// clamps radial distance at origin (at r=radius) | ||
|
@@ -929,6 +940,8 @@ proto.updateRadialDrag = function(fullLayout) { | |
var tx = cx + (radius + bl2) * Math.cos(angle0); | ||
var ty = cy - (radius + bl2) * Math.sin(angle0); | ||
|
||
// TODO add 'inner' drag box when innerRadius > 0 !! | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not quite sure what this means, but if it's something like the clamped inner edge still jumps to be a circle at the center then yeah, we'd better avoid that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This TODO refers to the radial drag box. Currently we have 1 radial drag box per polar subplot out beyond the subplot radius. We don't drag one at the other end of the radial axis as it would conflict with the "main" drag over the subplot. But, when There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh right! Yes, we should add that. Would be confusing if there's room for one but it's not there. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added in d466146 |
||
|
||
d3.select(radialDrag) | ||
.attr('transform', strTranslate(tx, ty)); | ||
|
||
|
@@ -1193,15 +1206,13 @@ proto.isPtInside = function(d) { | |
}; | ||
|
||
proto.pathArc = function(r) { | ||
r = r || this.radius; | ||
var sectorInRad = this.sectorInRad; | ||
var vangles = this.vangles; | ||
var fn = vangles ? helpers.pathPolygon : Lib.pathArc; | ||
return fn(r, sectorInRad[0], sectorInRad[1], vangles); | ||
}; | ||
|
||
proto.pathSector = function(r) { | ||
r = r || this.radius; | ||
var sectorInRad = this.sectorInRad; | ||
var vangles = this.vangles; | ||
var fn = vangles ? helpers.pathPolygon : Lib.pathSector; | ||
|
@@ -1215,6 +1226,12 @@ proto.pathAnnulus = function(r0, r1) { | |
return fn(r0, r1, sectorInRad[0], sectorInRad[1], vangles); | ||
}; | ||
|
||
proto.pathSubplot = function() { | ||
var r0 = this.innerRadius; | ||
var r1 = this.radius; | ||
return r0 ? this.pathAnnulus(r0, r1) : this.pathSector(r1); | ||
}; | ||
|
||
proto.fillViewInitialKey = function(key, val) { | ||
if(!(key in this.viewInitial)) { | ||
this.viewInitial[key] = val; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
{ | ||
"data": [ | ||
{ | ||
"type": "barpolar", | ||
"r": [10, 12, 15] | ||
}, | ||
{ | ||
"type": "scatterpolar", | ||
"r": [10, 12, 15], | ||
"theta0": 90 | ||
}, | ||
|
||
{ | ||
"type": "scatterpolar", | ||
"subplot": "polar2", | ||
"r": [100, 50, 200] | ||
}, | ||
{ | ||
"type": "barpolar", | ||
"subplot": "polar2", | ||
"r": [100, 50, 200] | ||
}, | ||
|
||
{ | ||
"type": "barpolar", | ||
"subplot": "polar3", | ||
"theta": ["a", "b", "c", "d", "b", "f", "a", "a"] | ||
}, | ||
{ | ||
"type": "scatterpolar", | ||
"subplot": "polar3", | ||
"theta": ["a", "b", "c", "d", "b", "f", "a", "a"] | ||
}, | ||
|
||
{ | ||
"type": "barpolar", | ||
"subplot": "polar4", | ||
"r": [10, 12, 15] | ||
}, | ||
{ | ||
"type": "scatterpolar", | ||
"subplot": "polar4", | ||
"r": [10, 12, 15], | ||
"theta0": 90 | ||
} | ||
], | ||
"layout": { | ||
"width": 600, | ||
"height": 600, | ||
"margin": {"l": 40, "r": 40, "b": 40, "t": 40, "pad": 0}, | ||
"grid": { | ||
"rows": 2, | ||
"columns": 2, | ||
"ygap": 0.2 | ||
}, | ||
"polar": { | ||
"hole": 0.1, | ||
"domain": {"row": 0, "column": 0} | ||
}, | ||
"polar2": { | ||
"hole": 0.4, | ||
"domain": {"row": 0, "column": 1}, | ||
"radialaxis": {"type": "log"} | ||
}, | ||
"polar3": { | ||
"hole": 0.2, | ||
"gridshape": "linear", | ||
"angularaxis": {"direction": "clockwise"}, | ||
"domain": {"row": 1, "column": 0} | ||
}, | ||
"polar4": { | ||
"hole": 0.4, | ||
"domain": {"row": 1, "column": 1}, | ||
"sector": [0, 180], | ||
"angularaxis": {"direction": "clockwise"}, | ||
"radialaxis": {"angle": 90, "side": "counterclockwise"} | ||
}, | ||
alexcjohnson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"showlegend": false | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.