Commit 053bf118 authored by Fintan McGee's avatar Fintan McGee
Browse files

added fisheye zoom functionality per users request. Below each axis there is...

added fisheye zoom functionality per users request. Below each axis there is an eye icon. CLicking on this results in the applciation of a fishe eye lens focuses on the midpoint of the brush(es)  on the axis
parent 24a084d8
......@@ -10,6 +10,12 @@
cursor: default;
}
.parcoords text.staticlabel {
cursor: default;
font-family: FontAwesome;
}
.parcoords rect.background {
fill: transparent;
}
......
......@@ -255,7 +255,78 @@ pc.flip = function(d) {
return this;
};
// add by fintan.mcgee@list.lu
// adds zoom funcitonality, , applies a log scale to axis and data
// centred around the current brush on the axis
pc.zoomScale = function(d, extents) {
var lensHeight = 0;
var lensFocus = 0;
var currentRange = yscale[d].range();
var lens = null, newScaleFunc;
if (!yscale[d].isZoomed) {
yscale[d].initialScale = yscale[d];
}
var previousAxisScale, preZoomScale;
if (__.types[d] =="string") {
// for the string axes the extents are in the ranges coordinate system
// we can take the numbers directly
lensHeight = (extents[1] - extents[0]) / 2;
lensFocus = extents[0] + lensHeight;
previousAxisScale = yscale[d];
lens = d3.fisheye.scale(d3.scale.linear).distortion(4).focus(lensFocus).domain(previousAxisScale.range()).range(previousAxisScale.range()) ;
newScaleFunc = function(val){
// do original transform
var intermediateVal = previousAxisScale(val)
// then apply fish eye to it
return lens(intermediateVal)
}
newScaleFunc.domain = previousAxisScale.domain;
newScaleFunc.range = previousAxisScale.range;
newScaleFunc.initialScale = previousAxisScale.initialScale;
newScaleFunc.isZoomed = true;
newScaleFunc.copy = function() {
var newScaleFunc2 = newScaleFunc;
newScaleFunc2.domain = newScaleFunc.domain;
newScaleFunc2.range = newScaleFunc.range;
newScaleFunc2.copy = newScaleFunc.copy ;
newScaleFunc2.initialScale = newScaleFunc.initialScale;
newScaleFunc2.isZoomed = newScaleFunc.isZoomed
return newScaleFunc2;
};
yscale[d] = newScaleFunc;
} else if (__.types[d] =="number") {
// for the number axes the extents and in the domains coordinate system
// we need to map them the the original range
previousAxisScale = yscale[d];
lensHeight = (previousAxisScale(extents[1]) - previousAxisScale(extents[0])) / 2;
lensFocus = previousAxisScale(extents[0]) + lensHeight;
yscale[d] = d3.fisheye.scale(d3.scale.linear).distortion(4).focus(lensFocus).domain(previousAxisScale.domain()).range(previousAxisScale.range());
yscale[d].initialScale = previousAxisScale.initialScale;
}
yscale[d].isZoomed = true;
}
pc.checkZoomScale = function(dimension) {
// return true if zoomed in
if (yscale[dimension].isZoomed) {
return true;
}
return false;
}
pc.clearZoomScale = function(dimension) {
if (yscale[dimension].isZoomed) {
yscale[dimension] = yscale[dimension].initialScale;
yscale[dimension].isZoomed = false;
}
}
pc.commonScale = function(global, type) {
var t = type || "number";
if (typeof global === 'undefined') {
......@@ -588,6 +659,58 @@ pc.clear = function(layer) {
};
d3.rebind(pc, axis, "ticks", "orient", "tickValues", "tickSubdivide", "tickSize", "tickPadding", "tickFormat");
// zoomAxis
// Functionality added by fintan.mcgee@list.lu
// when the user dbl click on the eye icon below and axis
// a linear fisheye lens effect, focused on the centre of the current brush, rescales the axis
// if there are multiple brushes overall max and min are used
// if click without brushes axis the effect is removed
function zoomAxis(dimension) {
var g = pc.svg.selectAll(".dimension");
// step 1 get the dimensions of the brush
var ext,
dExtents = [ Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY ];
ext = brush.modes["1D-axes"].brushState();
if(!ext[dimension]) {
ext = brush.modes["1D-axes-multi"].brushState();
}
if(ext[dimension]) {
ext[dimension].forEach(function(e) {
if(dExtents[0] > e[0]) {
dExtents[0] = e[0];
}
if(dExtents[1] < e[1]) {
dExtents[1] = e[1];
}
});
pc.brushReset();
pc.zoomScale(dimension, dExtents);
} else {
// no brush on the data
// an undo zoom
if(pc.checkZoomScale(dimension)){
pc.clearZoomScale(dimension);
}
}
if(__.types[dimension] =="number" && yscale[dimension].isZoomed) {
//include extra ticks if the axis is a number axis and zoomed
d3.select(this.parentElement)
.transition()
.duration(1100)
.call(axis.scale(yscale[dimension]).ticks(10));
} else {
d3.select(this.parentElement)
.transition()
.duration(1100)
.call(axis.scale(yscale[dimension]).ticks(5));
}
pc.render();
if (flags.shadows) paths(__.data, ctx.shadows);
}
function flipAxisAndUpdatePCP(dimension) {
var g = pc.svg.selectAll(".dimension");
......@@ -628,21 +751,32 @@ pc.createAxes = function() {
.attr("transform", function(d) { return "translate(" + xscale(d) + ")"; });
// Add an axis and title.
g.append("svg:g")
var svgAxes = g.append("svg:g")
.attr("class", "axis")
.attr("transform", "translate(0,0)")
.each(function(d) { d3.select(this).call(axis.scale(yscale[d])); })
.append("svg:text")
.each(function(d) { d3.select(this).call(axis.scale(yscale[d]));});
svgAxes.append("svg:text")
.attr({
"text-anchor": "middle",
"y": 0,
"transform": "translate(0,-5) rotate(" + __.dimensionTitleRotation + ")",
"transform": "translate(0, -5) rotate(" + __.dimensionTitleRotation + ")",
"x": 0,
"class": "label"
})
.text(dimensionLabels)
.on("dblclick", flipAxisAndUpdatePCP)
.on("wheel", rotateLabels);
svgAxes.append("svg:text")
.attr({
"text-anchor": "middle",
"y": 0,
"x": 0,
"class": "staticlabel"
})
.attr("transform",function(d) { return "translate(0," + (parseInt(yscale[d].range(), 10) * 2 + 11 ) + ")";})
.text(function(d) { return '\uf06e';}) // eye icon in font awseome
.on("dblclick", zoomAxis);
flags.axes= true;
return this;
......@@ -657,7 +791,7 @@ pc.updateAxes = function() {
var g_data = pc.svg.selectAll(".dimension").data(__.dimensions);
// Enter
g_data.enter().append("svg:g")
var svgAxes = g_data.enter().append("svg:g")
.attr("class", "dimension")
.attr("transform", function(p) { return "translate(" + position(p) + ")"; })
.style("opacity", 0)
......@@ -665,7 +799,7 @@ pc.updateAxes = function() {
.attr("class", "axis")
.attr("transform", "translate(0,0)")
.each(function(d) { d3.select(this).call(axis.scale(yscale[d])); })
.append("svg:text")
svgAxes.append("svg:text")
.attr({
"text-anchor": "middle",
"y": 0,
......@@ -676,6 +810,17 @@ pc.updateAxes = function() {
.text(dimensionLabels)
.on("dblclick", flipAxisAndUpdatePCP)
.on("wheel", rotateLabels);
svgAxes.append("svg:text")
.attr({
"text-anchor": "middle",
"y": 0,
"x": 0,
"class": "staticlabel"
})
.attr("transform",function(d) {
return "translate(0," + (parseInt(h(), 10) + 12) + ")"})
.text(function(d) { return '\uf06e' }) // eye icon in font awseome
.on("dblclick", zoomAxis);
// Update
g_data.attr("opacity", 0);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment