').addClass("facet-range-status").appendTo(bodyDiv);
- this._otherChoicesDiv = $('
').addClass("facet-range-other-choices").appendTo(bodyDiv);
-
- this._histogram = new HistogramWidget(this._histogramDiv, { binColors: [ "#ccccff", "#6666ff" ] });
-
- var onSlide = function(event, ui) {
- switch (self._config.mode) {
- case "min":
- self._from = ui.value;
- break;
- case "max":
- self._to = ui.value;
- break;
- default:
- self._from = ui.values[0];
- self._to = ui.values[1];
- }
+ this._elmts.sliderWidgetDiv.bind("slide", function(evt, data) {
+ self._from = data.from;
+ self._to = data.to;
self._setRangeIndicators();
- };
- var onStop = function() {
+ }).bind("stop", function(evt, data) {
+ self._from = data.from;
+ self._to = data.to;
self._selectNumeric = true;
self._updateRest();
- };
- var sliderConfig = {
- min: this._config.min,
- max: this._config.max,
- stop: onStop,
- slide: onSlide
- };
-
- switch (this._config.mode) {
- case "min":
- sliderConfig.range = "max";
- sliderConfig.value = this._config.min;
- break;
- case "max":
- sliderConfig.range = "min";
- sliderConfig.value = this._config.max;
- break;
- default:
- sliderConfig.range = true;
- sliderConfig.values = [ this._config.min, this._config.max ];
- }
-
- this._sliderDiv.slider(sliderConfig);
+ });
};
RangeFacet.prototype._renderOtherChoices = function() {
var self = this;
- var container = this._otherChoicesDiv.empty();
+ var container = this._elmts.otherChoicesDiv.empty();
if (this._baseNonNumericCount === 0 && this._baseBlankCount === 0 && this._baseErrorCount === 0) {
return;
@@ -274,20 +231,7 @@ RangeFacet.prototype._renderOtherChoices = function() {
};
RangeFacet.prototype._setRangeIndicators = function() {
- var text;
- switch (this._config.mode) {
- case "min":
- text = "At least " + this._from;
- break;
- case "max":
- text = "At most " + this._to;
- break;
- default:
- text = this._from + " to " + this._to;
- }
-
- this._statusDiv.text(text);
- this._histogram.highlight(this._from, this._to);
+ this._elmts.statusDiv.html(this._from + " — " + this._to);
};
RangeFacet.prototype.updateState = function(data) {
@@ -340,31 +284,32 @@ RangeFacet.prototype.render = function() {
}
if (this._error) {
- this._messageDiv.text(this._errorMessage).show();
- this._sliderDiv.hide();
- this._histogramDiv.hide();
- this._statusDiv.hide();
- this._otherChoicesDiv.hide();
+ this._elmts.messageDiv.text(this._errorMessage).show();
+ this._elmts.sliderWidgetDiv.hide();
+ this._elmts.histogramDiv.hide();
+ this._elmts.statusDiv.hide();
+ this._elmts.otherChoicesDiv.hide();
return;
}
- this._messageDiv.hide();
- this._sliderDiv.show();
- this._histogramDiv.show();
- this._statusDiv.show();
- this._otherChoicesDiv.show();
-
- this._sliderDiv.slider("option", "min", this._config.min);
- this._sliderDiv.slider("option", "max", this._config.max);
- this._sliderDiv.slider("option", "step", this._config.step);
+ this._elmts.messageDiv.hide();
+ this._elmts.sliderWidgetDiv.show();
+ this._elmts.histogramDiv.show();
+ this._elmts.statusDiv.show();
+ this._elmts.otherChoicesDiv.show();
+ this._sliderWidget.update(
+ this._config.min,
+ this._config.max,
+ this._config.step,
+ this._from,
+ this._to
+ );
this._histogram.update(
this._config.min,
this._config.max,
this._config.step,
- [ this._baseBins, this._bins ],
- this._from,
- this._to
+ [ this._baseBins, this._bins ]
);
this._setRangeIndicators();
diff --git a/src/main/webapp/scripts/widgets/histogram-widget.js b/src/main/webapp/scripts/widgets/histogram-widget.js
index 5c08026e8..2713330a1 100644
--- a/src/main/webapp/scripts/widgets/histogram-widget.js
+++ b/src/main/webapp/scripts/widgets/histogram-widget.js
@@ -4,21 +4,18 @@ function HistogramWidget(elmt, options) {
this._range = null;
this._binMatrix = null;
- this._highlight = null;
this._initializeUI();
}
-HistogramWidget.prototype.highlight = function(from, to) {
- this._highlight = { from: from, to: to };
- this._update();
-};
-
-HistogramWidget.prototype.update = function(min, max, step, binMatrix, from, to) {
- if (typeof min == "undefined" || typeof binMatrix == "undefined" || binMatrix.length === 0 || binMatrix[0].length === 0) {
+HistogramWidget.prototype.update = function(min, max, step, binMatrix) {
+ if (typeof min == "undefined" ||
+ typeof binMatrix == "undefined" ||
+ binMatrix.length === 0 ||
+ binMatrix[0].length === 0) {
+
this._range = null;
this._binMatrix = null;
- this._highlight = null;
this._elmt.hide();
} else {
@@ -33,21 +30,12 @@ HistogramWidget.prototype.update = function(min, max, step, binMatrix, from, to)
}
}
- if (typeof from != "undefined" && typeof to != "undefined") {
- this._highlight = { from: from, to: to };
- }
-
this._update();
}
};
HistogramWidget.prototype._update = function() {
if (this._binMatrix !== null) {
- if (this._highlight !== null) {
- this._highlight.from = Math.max(this._highlight.from, this._range.min);
- this._highlight.to = Math.min(this._highlight.to, this._range.max);
- }
-
this._elmt.show();
this._resize();
this._render();
@@ -67,8 +55,11 @@ HistogramWidget.prototype._initializeUI = function() {
};
HistogramWidget.prototype._resize = function() {
- this._elmts.canvas.attr("height", "height" in this._options ? this._options.height : 50);
+ var height = "height" in this._options ? this._options.height : 50;
+
+ this._elmts.canvas.attr("height", height);
this._elmts.canvas.attr("width", this._elmts.canvas.width());
+ this._elmt.height(height);
};
HistogramWidget.prototype._render = function() {
@@ -132,29 +123,5 @@ HistogramWidget.prototype._render = function() {
);
}
- /*
- * Draw highlight
- */
- if (this._highlight !== null) {
- ctx.fillStyle = "rgba(192,192,192, 0.5)";
- ctx.globalCompositeOperation = "source-over";
- if (this._highlight.from > this._range.min) {
- ctx.fillRect(
- 0,
- 0,
- (this._highlight.from - this._range.min) * stepScale,
- canvas.height
- );
- }
- if (this._highlight.to < this._range.max) {
- ctx.fillRect(
- (this._highlight.to - this._range.min) * stepScale,
- 0,
- canvas.width - (this._highlight.to - this._range.min) * stepScale,
- canvas.height
- );
- }
- }
-
ctx.restore();
};
diff --git a/src/main/webapp/scripts/widgets/slider-widget.js b/src/main/webapp/scripts/widgets/slider-widget.js
new file mode 100644
index 000000000..5717d0f74
--- /dev/null
+++ b/src/main/webapp/scripts/widgets/slider-widget.js
@@ -0,0 +1,180 @@
+function SliderWidget(elmt, options) {
+ this._elmt = elmt;
+ this._options = options || {};
+
+ this._range = {
+ min: 0,
+ max: 1,
+ step: 1,
+ from: 0,
+ to: 0
+ };
+ this._drag = null;
+
+ this._initializeUI();
+ this._update();
+}
+
+SliderWidget.prototype.update = function(min, max, step, from, to) {
+ if (step <= 0) {
+ step = 1;
+ }
+ max = Math.max(max, min + step);
+ from = Math.max(min, from);
+ to = Math.min(max, to);
+
+ this._range = {
+ min: min,
+ max: max,
+ step: step,
+ from: from,
+ to: to
+ };
+ this._update();
+}
+
+SliderWidget.prototype._initializeUI = function() {
+ this._elmt.addClass("slider-widget");
+
+ this._leftTintedRect = $("
").addClass("slider-widget-tint left").appendTo(this._elmt);
+ this._rightTintedRect = $("
").addClass("slider-widget-tint right").appendTo(this._elmt);
+ this._highlightRect = $("
").addClass("slider-widget-highlight slider-widget-draggable").attr("part", "highlight").appendTo(this._elmt);
+ this._leftBracket = $("
").addClass("slider-widget-bracket slider-widget-draggable left").attr("part", "left").appendTo(this._elmt);
+ this._rightBracket = $("
").addClass("slider-widget-bracket slider-widget-draggable right").attr("part", "right").appendTo(this._elmt);
+
+ var self = this;
+ this._elmt.find(".slider-widget-draggable")
+ .mousedown(function(evt) {
+ return self._onMouseDown(evt, this.getAttribute("part"));
+ });
+
+ this._highlightRect.dblclick(function(evt) {
+ if (self._range.from > self._range.min || self._range.to < self._range.max) {
+ self._range.from = self._range.min;
+ self._range.to = self._range.max;
+ self._update();
+ self._trigger("stop");
+ }
+ });
+
+ this._elmt
+ .mousemove(function(evt) {
+ return self._onMouseMove(evt);
+ })
+ .mouseup(function(evt) {
+ return self._onMouseUp(evt);
+ });
+};
+
+SliderWidget.prototype._onMouseDown = function(evt, part) {
+ if (this._drag) {
+ return;
+ }
+
+ this._drag = {
+ sureDrag: false
+ };
+ if ("highlight" == part) {
+ this._drag.elmt = this._highlightRect;
+ this._drag.value = this._range.from;
+ } else if ("left" == part) {
+ this._drag.elmt = this._leftBracket;
+ } else if ("right" == part) {
+ this._drag.elmt = this._rightBracket;
+ }
+ this._drag.what = part;
+ this._drag.from = this._range.from;
+ this._drag.to = this._range.to;
+ this._drag.down = {
+ x: evt.pageX,
+ y: evt.pageY
+ };
+};
+
+SliderWidget.prototype._onMouseUp = function(evt) {
+ if (!(this._drag)) {
+ return;
+ }
+
+ if (this._drag.sureDrag) {
+ this._update();
+ this._trigger("stop");
+ }
+ this._drag = null;
+};
+
+SliderWidget.prototype._trigger = function(eventName) {
+ this._elmt.trigger(eventName, [{ from: this._range.from, to: this._range.to }]);
+};
+
+SliderWidget.prototype._onMouseMove = function(evt) {
+ if (!(this._drag)) {
+ return;
+ }
+
+ var drag = this._drag;
+ var range = this._range;
+
+ var offset = this._elmt.offset();
+ var xDiff = evt.pageX - drag.down.x;
+ var yDiff = evt.pageX - drag.down.y;
+
+ if (Math.abs(xDiff) >= 2) {
+ drag.sureDrag = true;
+ }
+
+ var pixelWidth = this._elmt.width();
+ var scale = pixelWidth / (range.max - range.min);
+ var vDiff = xDiff / scale;
+
+ var adjustFrom = function() {
+ range.from = drag.from + Math.floor(vDiff / range.step) * range.step;
+ range.from = Math.max(Math.min(range.from, range.max), range.min);
+ };
+ var adjustTo = function() {
+ range.to = drag.to + Math.floor(vDiff / range.step) * range.step;
+ range.to = Math.max(Math.min(range.to, range.max), range.min);
+ };
+
+ if (drag.what == "left") {
+ adjustFrom();
+ range.to = Math.min(Math.max(range.to, range.from + range.step), range.max);
+ } else if (drag.what == "right") {
+ adjustTo();
+ range.from = Math.max(Math.min(range.from, range.to - range.step), range.min);
+ } else {
+ adjustFrom();
+ adjustTo();
+ }
+
+ this._update();
+ this._trigger("slide");
+
+ evt.preventDefault();
+ return false;
+};
+
+SliderWidget.prototype._update = function() {
+ var range = this._range;
+
+ var pixelWidth = this._elmt.width();
+ var scale = pixelWidth / (range.max - range.min);
+ var valueToPixel = function(x) {
+ return (x - range.min) * scale;
+ };
+
+ var fromPixel = Math.floor(valueToPixel(range.from));
+ var toPixel = Math.floor(valueToPixel(range.to));
+
+ if (range.from == range.min && range.to == range.max) {
+ this._leftTintedRect.hide();
+ this._rightTintedRect.hide();
+ } else {
+ this._leftTintedRect.show().width(fromPixel);
+ this._rightTintedRect.show().width(pixelWidth - toPixel);
+ }
+
+ this._highlightRect.css("left", (fromPixel - 1) + "px").width(toPixel - fromPixel);
+ this._leftBracket.css("left", fromPixel + "px");
+ this._rightBracket.css("left", toPixel + "px");
+};
diff --git a/src/main/webapp/styles/dialogs/clustering-dialog.css b/src/main/webapp/styles/dialogs/clustering-dialog.css
index a9230efd6..87c8cff95 100644
--- a/src/main/webapp/styles/dialogs/clustering-dialog.css
+++ b/src/main/webapp/styles/dialogs/clustering-dialog.css
@@ -64,11 +64,10 @@ table.clustering-dialog-entry-table a:hover {
font-weight: bold;
}
.clustering-dialog-facet-histogram {
- margin: 10px;
overflow: hidden;
}
.clustering-dialog-facet-slider {
- margin: 5px 10px;
+ margin: 5px;
}
.clustering-dialog-facet-selection {
text-align: center;
diff --git a/src/main/webapp/styles/project/browsing.css b/src/main/webapp/styles/project/browsing.css
index 29e2a1457..0dd6585a2 100644
--- a/src/main/webapp/styles/project/browsing.css
+++ b/src/main/webapp/styles/project/browsing.css
@@ -143,21 +143,15 @@ img.facet-choice-link {
color: #f88;
}
.facet-range-histogram {
- margin: 10px 0px;
overflow: hidden;
}
-.facet-range-slider.ui-corner-all {
- border-bottom-left-radius: 0px 0px;
- border-bottom-right-radius: 0px 0px;
- border-top-left-radius: 0px 0px;
- border-top-right-radius: 0px 0px;
+.facet-range-slider {
+ margin: 0px;
}
-
.facet-range-status {
- margin: 10px 0;
+ margin: 5px 0;
text-align: center;
- color: #aaa;
}
.facet-text-body {
diff --git a/src/main/webapp/styles/widgets/slider-widget.css b/src/main/webapp/styles/widgets/slider-widget.css
new file mode 100644
index 000000000..c0a03ebeb
--- /dev/null
+++ b/src/main/webapp/styles/widgets/slider-widget.css
@@ -0,0 +1,45 @@
+.slider-widget {
+ position: relative;
+ overflow: visible;
+ margin-left: 12px;
+ margin-right: 12px;
+}
+
+.slider-widget-tint {
+ position: absolute;
+ top: 0px;
+ height: 100%;
+ background: black;
+ opacity: 0.4;
+ display: none;
+}
+.slider-widget-tint.left {
+ left: 0px;
+}
+.slider-widget-tint.right {
+ right: 0px;
+}
+.slider-widget-highlight {
+ position: absolute;
+ padding: 1px 0px;
+ border: 1px solid #faa;
+ top: -2px;
+ height: 100%;
+ cursor: move;
+}
+.slider-widget-bracket {
+ position: absolute;
+ width: 12px;
+ top: 0px;
+ height: 100%;
+}
+.slider-widget-bracket.left {
+ background: url(../../images/slider-left-bracket.png) no-repeat center right;
+ margin-left: -14px;
+ cursor: e-resize;
+}
+.slider-widget-bracket.right {
+ background: url(../../images/slider-right-bracket.png) no-repeat center left;
+ margin-left: 2px;
+ cursor: w-resize;
+}