diff --git a/.gitignore b/.gitignore index dfafee4..ffc6074 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,10 @@ components # coverage report /coverage + +# OS related +.DS_Store + +# IDE related +.idea + diff --git a/htdocs/index.html b/htdocs/index.html index fcddafb..33ddd2a 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -371,6 +371,9 @@ Enable zoom + + Change Zoom Type + Zoom on category axis diff --git a/htdocs/samples/zoom_type.html b/htdocs/samples/zoom_type.html new file mode 100644 index 0000000..042cf1c --- /dev/null +++ b/htdocs/samples/zoom_type.html @@ -0,0 +1,62 @@ + + + + + +

Zoom Type Scroll with Default Zoom Behavior

+
+ +

Zoom Type Drag with Default Zoom Behavior

+
+ + + + + + diff --git a/src/class.js b/src/class.js index 7cc0b61..695c1f3 100644 --- a/src/class.js +++ b/src/class.js @@ -22,6 +22,7 @@ export default { eventRectsMultiple: 'c3-event-rects-multiple', zoomRect: 'c3-zoom-rect', brush: 'c3-brush', + dragZoom: 'c3-drag-zoom', focused: 'c3-focused', defocused: 'c3-defocused', region: 'c3-region', diff --git a/src/config.js b/src/config.js index 7ea0bb8..693cd3e 100644 --- a/src/config.js +++ b/src/config.js @@ -14,6 +14,8 @@ ChartInternal.prototype.getDefaultConfig = function () { resize_auto: true, zoom_enabled: false, zoom_initialRange: undefined, + zoom_type: 'scroll', + zoom_disableDefaultBehavior: false, zoom_privileged: false, zoom_rescale: false, zoom_onzoom: function () {}, diff --git a/src/core.js b/src/core.js index a69efe0..6a3bea4 100644 --- a/src/core.js +++ b/src/core.js @@ -257,6 +257,9 @@ ChartInternal.prototype.initWithData = function(data) { if ($$.initPie) { $$.initPie(); } + if ($$.initDragZoom) { + $$.initDragZoom(); + } if ($$.initSubchart) { $$.initSubchart(); } diff --git a/src/scss/main.scss b/src/scss/main.scss index fecfcfe..0b34feb 100644 --- a/src/scss/main.scss +++ b/src/scss/main.scss @@ -61,3 +61,7 @@ /*-- Arc --*/ @import 'arc'; + +/*-- Zoom --*/ + +@import 'zoom'; diff --git a/src/scss/zoom.scss b/src/scss/zoom.scss new file mode 100644 index 0000000..1e0c6fe --- /dev/null +++ b/src/scss/zoom.scss @@ -0,0 +1,13 @@ +.c3-drag-zoom.enabled{ + pointer-events: all!important; + visibility: visible; +} + +.c3-drag-zoom.disabled{ + pointer-events: none!important; + visibility: hidden; +} + +.c3-drag-zoom .extent { + fill-opacity: .1; +} diff --git a/src/zoom.js b/src/zoom.js index b7dd217..ebdf98f 100644 --- a/src/zoom.js +++ b/src/zoom.js @@ -5,17 +5,29 @@ ChartInternal.prototype.initZoom = function () { $$.zoom = d3.zoom() .on("start", function () { + if (config.zoom_type !== 'scroll') { + return; + } + var e = d3.event.sourceEvent; if (e && e.type === "brush") { return; } startEvent = e; config.zoom_onzoomstart.call($$.api, e); }) .on("zoom", function () { + if (config.zoom_type !== 'scroll') { + return; + } + var e = d3.event.sourceEvent; if (e && e.type === "brush") { return; } $$.redrawForZoom.call($$); }) .on('end', function () { + if (config.zoom_type !== 'scroll') { + return; + } + var e = d3.event.sourceEvent; if (e && e.type === "brush") { return; } // if click, do nothing. otherwise, click interaction will be canceled. @@ -48,6 +60,74 @@ ChartInternal.prototype.zoomTransform = function (range) { return $$.d3.zoomIdentity.scale($$.width / (s[1] - s[0])).translate(-s[0], 0); }; +ChartInternal.prototype.initDragZoom = function () { + if (this.config.zoom_type === 'drag' && this.config.zoom_enabled) { + var $$ = this, d3 = $$.d3, config = $$.config, + context = $$.context = $$.svg, + brushXPos, brushYPos; + + $$.dragZoomBrush = d3.svg.brush() + .x($$.x) + .y($$.y) + .on("brushstart", function () { + config.zoom_onzoomstart.call($$.api, $$.x.orgDomain()); + }) + .on("brush", function () { + var extent = $$.dragZoomBrush.extent(), + ar1 = [extent[0][0], $$.y.domain()[0]], + ar2 = [extent[1][0], $$.y.domain()[1]]; + + $$.dragZoomBrush.extent([ar1, ar2]); + $$.svg.select("." + CLASS.dragZoom).call($$.dragZoomBrush); + + + config.zoom_onzoom.call($$.api, $$.x.orgDomain()); + }) + .on("brushend", function () { + var extent = $$.dragZoomBrush.extent(); + + if (!config.zoom_disableDefaultBehavior) { + $$.api.zoom([extent[0][0], extent[1][0]]); + } + else { + var ar1 = [$$.x.domain()[0], $$.y.domain()[0]], + ar2 = [$$.x.domain()[1], $$.y.domain()[1]]; + $$.dragZoomBrush.extent([ar1, ar2]); + $$.api.zoom([$$.x.domain()[0], $$.x.domain()[1]]); + } + + d3.selectAll("." + CLASS.dragZoom) + .attr("class", CLASS.dragZoom + " disabled"); + + $$.dragZoomBrush.clear(); + $$.svg.select("." + CLASS.dragZoom).call($$.dragZoomBrush); + + config.zoom_onzoomend.call($$.api, [extent[0][0], extent[1][0]]); + }); + + brushXPos = $$.margin.left + 20.5; + brushYPos = $$.margin.top + 0.5; + context.append("g") + .attr("clip-path", $$.clipPath) + .attr("class", CLASS.dragZoom + " disabled") + .attr("transform", "translate(" + brushXPos + "," + brushYPos + ")") + .call($$.dragZoomBrush); + + $$.svg.on("mousedown", function () { + d3.selectAll("." + CLASS.dragZoom) + .attr("class", CLASS.dragZoom + " enabled"); + + var brush_elm = $$.svg.select("." + CLASS.dragZoom).node(); + var new_click_event = new Event('mousedown'); + new_click_event.pageX = d3.event.pageX; + new_click_event.clientX = d3.event.clientX; + new_click_event.pageY = d3.event.pageY; + new_click_event.clientY = d3.event.clientY; + brush_elm.dispatchEvent(new_click_event); + }); + } +}; + ChartInternal.prototype.getZoomDomain = function () { var $$ = this, config = $$.config, d3 = $$.d3, min = d3.min([$$.orgXDomain[0], config.zoom_x_min]),