From bfad26193a090e15df1200a58d52cabacbc0285c Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Fri, 4 Dec 2015 20:21:34 +0000 Subject: [PATCH] Added support to zoom types (scroll and drag) with option to disable default zoom behavior. Added uncorrect removed files. Fixed build files permissions. Fixed visibility property spelling. Fixed bug on returned zoom domain in 'onzoomend' event. Prevent a drag from a single click. removed fix for false click. Fixed bug in update zoom when zoom type is drag. --- .gitignore | 7 ++ htdocs/index.html | 3 + htdocs/samples/zoom_type.html | 62 +++++++++++++++++ src/class.js | 1 + src/config.js | 2 + src/core.js | 1 + src/scss/main.scss | 4 ++ src/scss/zoom.scss | 13 ++++ src/zoom.js | 121 +++++++++++++++++++++++++++++----- 9 files changed, 196 insertions(+), 18 deletions(-) create mode 100644 htdocs/samples/zoom_type.html create mode 100644 src/scss/zoom.scss diff --git a/.gitignore b/.gitignore index e6f33ca..3c2ef74 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,10 @@ build # coverage report /coverage + +# OS related +.DS_Store + +# IDE related +.idea + diff --git a/htdocs/index.html b/htdocs/index.html index 7f2c06a..a8fe49e 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -356,6 +356,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 66171a7..9202e92 100644 --- a/src/class.js +++ b/src/class.js @@ -22,6 +22,7 @@ var CLASS = c3_chart_internal_fn.CLASS = { 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 ae9aa9f..4331c26 100644 --- a/src/config.js +++ b/src/config.js @@ -10,6 +10,8 @@ c3_chart_internal_fn.getDefaultConfig = function () { padding_bottom: undefined, resize_auto: true, zoom_enabled: false, + zoom_type: 'scroll', + zoom_disableDefaultBehavior: false, zoom_extent: undefined, zoom_privileged: false, zoom_rescale: false, diff --git a/src/core.js b/src/core.js index 4dad60d..bfb84f8 100644 --- a/src/core.js +++ b/src/core.js @@ -268,6 +268,7 @@ c3_chart_internal_fn.initWithData = function (data) { // Define regions main = $$.main = $$.svg.append("g").attr("transform", $$.getTranslate('main')); + if ($$.initDragZoom) { $$.initDragZoom(); } if ($$.initSubchart) { $$.initSubchart(); } if ($$.initTooltip) { $$.initTooltip(); } if ($$.initLegend) { $$.initLegend(); } 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 c11dd8b..cef0ad8 100644 --- a/src/zoom.js +++ b/src/zoom.js @@ -3,14 +3,26 @@ c3_chart_internal_fn.initZoom = function () { $$.zoom = d3.behavior.zoom() .on("zoomstart", function () { + if (config.zoom_type !== 'scroll') { + return; + } + startEvent = d3.event.sourceEvent; $$.zoom.altDomain = d3.event.sourceEvent.altKey ? $$.x.orgDomain() : null; config.zoom_onzoomstart.call($$.api, d3.event.sourceEvent); }) .on("zoom", function () { + if (config.zoom_type !== 'scroll') { + return; + } + $$.redrawForZoom.call($$); }) .on('zoomend', function () { + if (config.zoom_type !== 'scroll') { + return; + } + var event = d3.event.sourceEvent; // if click, do nothing. otherwise, click interaction will be canceled. if (event && startEvent.clientX === event.clientX && startEvent.clientY === event.clientY) { @@ -20,6 +32,7 @@ c3_chart_internal_fn.initZoom = function () { $$.updateZoom(); config.zoom_onzoomend.call($$.api, $$.x.orgDomain()); }); + $$.zoom.scale = function (scale) { return config.axis_rotated ? this.y(scale) : this.x(scale); }; @@ -34,6 +47,75 @@ c3_chart_internal_fn.initZoom = function () { return this; }; }; + +c3_chart_internal_fn.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); + }); + } +}; + c3_chart_internal_fn.getZoomDomain = function () { var $$ = this, config = $$.config, d3 = $$.d3, min = d3.min([$$.orgXDomain[0], config.zoom_x_min]), @@ -41,7 +123,7 @@ c3_chart_internal_fn.getZoomDomain = function () { return [min, max]; }; c3_chart_internal_fn.updateZoom = function () { - var $$ = this, z = $$.config.zoom_enabled ? $$.zoom : function () {}; + var $$ = this, z = $$.config.zoom_enabled && $$.config.zoom_type === 'scroll' ? $$.zoom : function () {}; $$.main.select('.' + CLASS.zoomRect).call(z).on("dblclick.zoom", null); $$.main.selectAll('.' + CLASS.eventRect).call(z).on("dblclick.zoom", null); }; @@ -53,23 +135,26 @@ c3_chart_internal_fn.redrawForZoom = function () { if ($$.filterTargetsToShow($$.data.targets).length === 0) { return; } - if (d3.event.sourceEvent.type === 'mousemove' && zoom.altDomain) { - x.domain(zoom.altDomain); - zoom.scale(x).updateScaleExtent(); - return; - } - if ($$.isCategorized() && x.orgDomain()[0] === $$.orgXDomain[0]) { - x.domain([$$.orgXDomain[0] - 1e-10, x.orgDomain()[1]]); - } - $$.redraw({ - withTransition: false, - withY: config.zoom_rescale, - withSubchart: false, - withEventRect: false, - withDimension: false - }); - if (d3.event.sourceEvent.type === 'mousemove') { - $$.cancelClick = true; + + if (config.zoom_type === 'scroll' && !config.zoom_disableDefaultBehavior) { + if (d3.event.sourceEvent.type === 'mousemove' && zoom.altDomain) { + x.domain(zoom.altDomain); + zoom.scale(x).updateScaleExtent(); + return; + } + if ($$.isCategorized() && x.orgDomain()[0] === $$.orgXDomain[0]) { + x.domain([$$.orgXDomain[0] - 1e-10, x.orgDomain()[1]]); + } + $$.redraw({ + withTransition: false, + withY: config.zoom_rescale, + withSubchart: false, + withEventRect: false, + withDimension: false + }); + if (d3.event.sourceEvent.type === 'mousemove') { + $$.cancelClick = true; + } } config.zoom_onzoom.call($$.api, x.orgDomain()); };