Browse Source

Fix interaction by event rect

pull/2246/head
Masayuki Tanaka 7 years ago
parent
commit
2ba6f22185
  1. 2
      htdocs/samples/interaction_enabled.html
  2. 8
      src/api.flow.js
  3. 12
      src/core.js
  4. 276
      src/interaction.js

2
htdocs/samples/interaction_enabled.html

@ -5,7 +5,7 @@
<body> <body>
<div id="chart"></div> <div id="chart"></div>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> <script src="http://d3js.org/d3.v4.min.js" charset="utf-8"></script>
<script src="/js/c3.js"></script> <script src="/js/c3.js"></script>
<script> <script>

8
src/api.flow.js

@ -240,18 +240,16 @@ c3_chart_internal_fn.generateFlow = function (args) {
wait.add(xgrid.transition(flowTransition).attr('transform', transform)); wait.add(xgrid.transition(flowTransition).attr('transform', transform));
wait.add(xgridLines.transition(flowTransition).attr('transform', transform)); wait.add(xgridLines.transition(flowTransition).attr('transform', transform));
wait(function () { wait(function () {
var i, shapes = [], texts = [], eventRects = []; var i, shapes = [], texts = [];
// remove flowed elements // remove flowed elements
if (flowLength) { if (flowLength) {
for (i = 0; i < flowLength; i++) { for (i = 0; i < flowLength; i++) {
shapes.push('.' + CLASS.shape + '-' + (flowIndex + i)); shapes.push('.' + CLASS.shape + '-' + (flowIndex + i));
texts.push('.' + CLASS.text + '-' + (flowIndex + i)); texts.push('.' + CLASS.text + '-' + (flowIndex + i));
eventRects.push('.' + CLASS.eventRect + '-' + (flowIndex + i));
} }
$$.svg.selectAll('.' + CLASS.shapes).selectAll(shapes).remove(); $$.svg.selectAll('.' + CLASS.shapes).selectAll(shapes).remove();
$$.svg.selectAll('.' + CLASS.texts).selectAll(texts).remove(); $$.svg.selectAll('.' + CLASS.texts).selectAll(texts).remove();
$$.svg.selectAll('.' + CLASS.eventRects).selectAll(eventRects).remove();
$$.svg.select('.' + CLASS.xgrid).remove(); $$.svg.select('.' + CLASS.xgrid).remove();
} }
@ -295,10 +293,6 @@ c3_chart_internal_fn.generateFlow = function (args) {
.attr("x", $$.regionX.bind($$)) .attr("x", $$.regionX.bind($$))
.attr("width", $$.regionWidth.bind($$)); .attr("width", $$.regionWidth.bind($$));
if (config.interaction_enabled) {
$$.redrawEventRect();
}
// callback for end of flow // callback for end of flow
done(); done();

12
src/core.js

@ -279,10 +279,6 @@ c3_chart_internal_fn.initWithData = function (data) {
// Cover whole with rects for events // Cover whole with rects for events
$$.initEventRect(); $$.initEventRect();
// event rect handle zoom event as well
if (config.zoom_enabled) {
$$.main.select('.' + CLASS.eventRect).call($$.zoom).on("dblclick.zoom", null);
}
// Define g for chart // Define g for chart
$$.initChartElements(); $$.initChartElements();
@ -565,6 +561,9 @@ c3_chart_internal_fn.redraw = function (options, transitions) {
.transition() .transition()
.style('opacity', targetsToShow.length ? 0 : 1); .style('opacity', targetsToShow.length ? 0 : 1);
// event rect
if (withEventRect) { $$.redrawEventRect(); }
// grid // grid
$$.updateGrid(duration); $$.updateGrid(duration);
@ -601,11 +600,6 @@ c3_chart_internal_fn.redraw = function (options, transitions) {
.selectAll('circle') .selectAll('circle')
.remove(); .remove();
// event rects will redrawn when flow called
if (config.interaction_enabled && !options.flow && withEventRect) {
$$.updateEventRect();
}
if (options.flow) { if (options.flow) {
flow = $$.generateFlow({ flow = $$.generateFlow({
targets: targetsToShow, targets: targetsToShow,

276
src/interaction.js

@ -2,233 +2,28 @@ import CLASS from './class';
import { c3_chart_internal_fn } from './core'; import { c3_chart_internal_fn } from './core';
c3_chart_internal_fn.initEventRect = function () { c3_chart_internal_fn.initEventRect = function () {
var $$ = this; var $$ = this, config = $$.config;
$$.main.select('.' + CLASS.chart).append("g") $$.main.select('.' + CLASS.chart).append("g")
.attr("class", CLASS.eventRects) .attr("class", CLASS.eventRects)
.style('fill-opacity', 0); .style('fill-opacity', 0);
$$.redrawEventRect(); $$.eventRect = $$.main.select('.' + CLASS.eventRects).append('rect')
}; .attr('class', CLASS.eventRect);
c3_chart_internal_fn.redrawEventRect = function () {
var $$ = this, config = $$.config,
eventRect, eventRectEnter, maxDataCountTarget,
isMultipleX = $$.isMultipleX();
// rects for mouseover
var eventRects = $$.main.select('.' + CLASS.eventRects)
.style('cursor', config.zoom_enabled ? config.axis_rotated ? 'ns-resize' : 'ew-resize' : null)
.classed(CLASS.eventRectsMultiple, isMultipleX)
.classed(CLASS.eventRectsSingle, !isMultipleX);
if (isMultipleX) {
eventRect = eventRects.selectAll('.' + CLASS.eventRect).data([0]);
// enter : only one rect will be added
eventRectEnter = $$.generateEventRectsForMultipleXs(eventRect.enter());
// update
$$.eventRect = eventRectEnter.merge(eventRect);
$$.updateEventRect();
// exit : not needed because always only one rect exists
}
// DUPLICATED: this will be removed because it seems to be unable to work with zoom...
else {
// clear old rects
eventRects.selectAll('.' + CLASS.eventRect).remove();
// Set data and update $$.eventRect
maxDataCountTarget = $$.getMaxDataCountTarget($$.data.targets);
eventRect.datum(maxDataCountTarget ? maxDataCountTarget.values : []);
eventRect = eventRects.selectAll('.' + CLASS.eventRect).data(function (d) { return d; });
// enter
eventRectEnter = $$.generateEventRectsForSingleX(eventRect.enter());
// update
$$.eventRect = eventRectEnter.merge(eventRect);
$$.updateEventRect();
// exit
eventRect.exit().remove();
}
};
c3_chart_internal_fn.updateEventRect = function (eventRectUpdate) {
var $$ = this, config = $$.config,
x, y, w, h, rectW, rectX;
// set update selection if null
eventRectUpdate = eventRectUpdate || $$.eventRect;
if ($$.isMultipleX()) {
// TODO: rotated not supported yet
x = 0;
y = 0;
w = $$.width;
h = $$.height;
}
// DUPLICATED: this will be removed because it seems to be unable to work with zoom...
else {
if (($$.isCustomX() || $$.isTimeSeries()) && !$$.isCategorized()) {
// update index for x that is used by prevX and nextX
$$.updateXs();
rectW = function (d) {
var prevX = $$.getPrevX(d.index), nextX = $$.getNextX(d.index);
// if there this is a single data point make the eventRect full width (or height)
if (prevX === null && nextX === null) {
return config.axis_rotated ? $$.height : $$.width;
}
if (prevX === null) { prevX = $$.x.domain()[0]; }
if (nextX === null) { nextX = $$.x.domain()[1]; }
return Math.max(0, ($$.x(nextX) - $$.x(prevX)) / 2);
};
rectX = function (d) {
var prevX = $$.getPrevX(d.index), nextX = $$.getNextX(d.index),
thisX = $$.data.xs[d.id][d.index];
// if there this is a single data point position the eventRect at 0
if (prevX === null && nextX === null) {
return 0;
}
if (prevX === null) { prevX = $$.x.domain()[0]; }
return ($$.x(thisX) + $$.x(prevX)) / 2; // event rect handle zoom event as well
}; if (config.zoom_enabled && $$.zoom) {
} else { $$.main.select('.' + CLASS.eventRect).call($$.zoom).on("dblclick.zoom", null);
rectW = $$.getEventRectWidth();
rectX = function (d) {
return $$.x(d.x) - (rectW / 2);
};
}
x = config.axis_rotated ? 0 : rectX;
y = config.axis_rotated ? rectX : 0;
w = config.axis_rotated ? $$.width : rectW;
h = config.axis_rotated ? rectW : $$.height;
} }
eventRectUpdate
.attr('class', $$.classEvent.bind($$))
.attr("x", x)
.attr("y", y)
.attr("width", w)
.attr("height", h);
}; };
// DUPLICATED: this will be removed because it seems to be unable to work with zoom... c3_chart_internal_fn.redrawEventRect = function () {
c3_chart_internal_fn.generateEventRectsForSingleX = function (eventRectEnter) { var $$ = this, d3 = $$.d3, config = $$.config,
var $$ = this, d3 = $$.d3, config = $$.config; x, y, w, h;
return eventRectEnter.append("rect")
.attr("class", $$.classEvent.bind($$))
.style("cursor", config.data_selection_enabled && config.data_selection_grouped ? "pointer" : null)
.on('mouseover', function (d) {
var index = d.index;
if ($$.dragging || $$.flowing) { return; } // do nothing while dragging/flowing
if ($$.hasArcType()) { return; }
// Expand shapes for selection
if (config.point_focus_expand_enabled) { $$.expandCircles(index, null, true); }
$$.expandBars(index, null, true);
// Call event handler
$$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) {
config.data_onmouseover.call($$.api, d);
});
})
.on('mouseout', function (d) {
var index = d.index;
if (!$$.config) { return; } // chart is destroyed
if ($$.hasArcType()) { return; }
$$.hideXGridFocus();
$$.hideTooltip();
// Undo expanded shapes
$$.unexpandCircles();
$$.unexpandBars();
// Call event handler
$$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) {
config.data_onmouseout.call($$.api, d);
});
})
.on('mousemove', function (d) {
var selectedData, index = d.index,
eventRect = $$.svg.select('.' + CLASS.eventRect + '-' + index);
if ($$.dragging || $$.flowing) { return; } // do nothing while dragging/flowing
if ($$.hasArcType()) { return; }
if ($$.isStepType(d) && $$.config.line_step_type === 'step-after' && d3.mouse(this)[0] < $$.x($$.getXValue(d.id, index))) {
index -= 1;
}
// Show tooltip
selectedData = $$.filterTargetsToShow($$.data.targets).map(function (t) {
return $$.addName($$.getValueOnIndex(t.values, index));
});
if (config.tooltip_grouped) {
$$.showTooltip(selectedData, this);
$$.showXGridFocus(selectedData);
}
if (config.tooltip_grouped && (!config.data_selection_enabled || config.data_selection_grouped)) {
return;
}
$$.main.selectAll('.' + CLASS.shape + '-' + index) // TODO: rotated not supported yet
.each(function () { x = 0;
d3.select(this).classed(CLASS.EXPANDED, true); y = 0;
if (config.data_selection_enabled) { w = $$.width;
eventRect.style('cursor', config.data_selection_grouped ? 'pointer' : null); h = $$.height;
}
if (!config.tooltip_grouped) {
$$.hideXGridFocus();
$$.hideTooltip();
if (!config.data_selection_grouped) {
$$.unexpandCircles(index);
$$.unexpandBars(index);
}
}
})
.filter(function (d) {
return $$.isWithinShape(this, d);
})
.each(function (d) {
if (config.data_selection_enabled && (config.data_selection_grouped || config.data_selection_isselectable(d))) {
eventRect.style('cursor', 'pointer');
}
if (!config.tooltip_grouped) {
$$.showTooltip([d], this);
$$.showXGridFocus([d]);
if (config.point_focus_expand_enabled) { $$.expandCircles(index, d.id, true); }
$$.expandBars(index, d.id, true);
}
});
})
.on('click', function (d) {
var index = d.index;
if ($$.hasArcType() || !$$.toggleShape) { return; }
if ($$.cancelClick) {
$$.cancelClick = false;
return;
}
if ($$.isStepType(d) && config.line_step_type === 'step-after' && d3.mouse(this)[0] < $$.x($$.getXValue(d.id, index))) {
index -= 1;
}
$$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) {
if (config.data_selection_grouped || $$.isWithinShape(this, d)) {
$$.toggleShape(this, d, index);
$$.config.data_onclick.call($$.api, d, this);
}
});
})
.call(
config.data_selection_draggable && $$.drag ? (
d3.drag()
.on('drag', function () { $$.drag(d3.mouse(this)); })
.on('start', function () { $$.dragstart(d3.mouse(this)); })
.on('end', function () { $$.dragend(); })
) : function () {}
);
};
c3_chart_internal_fn.generateEventRectsForMultipleXs = function (eventRectEnter) {
var $$ = this, d3 = $$.d3, config = $$.config;
function mouseout() { function mouseout() {
$$.svg.select('.' + CLASS.eventRect).style('cursor', null); $$.svg.select('.' + CLASS.eventRect).style('cursor', null);
@ -238,24 +33,27 @@ c3_chart_internal_fn.generateEventRectsForMultipleXs = function (eventRectEnter)
$$.unexpandBars(); $$.unexpandBars();
} }
return eventRectEnter.append('rect') // rects for mouseover
.attr('x', 0) $$.main.select('.' + CLASS.eventRects)
.attr('y', 0) .style('cursor', config.zoom_enabled ? config.axis_rotated ? 'ns-resize' : 'ew-resize' : null);
.attr('width', $$.width)
.attr('height', $$.height) $$.eventRect
.attr('class', CLASS.eventRect) .attr('x', x)
.on('mouseout', function () { .attr('y', y)
if (!$$.config) { return; } // chart is destroyed .attr('width', w)
.attr('height', h)
.on('mouseout', config.interaction_enabled ? function () {
if (!config) { return; } // chart is destroyed
if ($$.hasArcType()) { return; } if ($$.hasArcType()) { return; }
mouseout(); mouseout();
}) } : null)
.on('mousemove', function () { .on('mousemove', config.interaction_enabled ? function () {
var targetsToShow = $$.filterTargetsToShow($$.data.targets); var targetsToShow, mouse, closest, sameXData, selectedData;
var mouse, closest, sameXData, selectedData;
if ($$.dragging) { return; } // do nothing when dragging if ($$.dragging) { return; } // do nothing when dragging
if ($$.hasArcType(targetsToShow)) { return; } if ($$.hasArcType(targetsToShow)) { return; }
targetsToShow = $$.filterTargetsToShow($$.data.targets);
mouse = d3.mouse(this); mouse = d3.mouse(this);
closest = $$.findClosestFromTargets(targetsToShow, mouse); closest = $$.findClosestFromTargets(targetsToShow, mouse);
@ -298,12 +96,12 @@ c3_chart_internal_fn.generateEventRectsForMultipleXs = function (eventRectEnter)
$$.mouseover = closest; $$.mouseover = closest;
} }
} }
}) } : null)
.on('click', function () { .on('click', config.interaction_enabled ? function () {
var targetsToShow = $$.filterTargetsToShow($$.data.targets); var targetsToShow, mouse, closest;
var mouse, closest;
if ($$.hasArcType(targetsToShow)) { return; } if ($$.hasArcType(targetsToShow)) { return; }
targetsToShow = $$.filterTargetsToShow($$.data.targets);
mouse = d3.mouse(this); mouse = d3.mouse(this);
closest = $$.findClosestFromTargets(targetsToShow, mouse); closest = $$.findClosestFromTargets(targetsToShow, mouse);
if (! closest) { return; } if (! closest) { return; }
@ -312,13 +110,13 @@ c3_chart_internal_fn.generateEventRectsForMultipleXs = function (eventRectEnter)
$$.main.selectAll('.' + CLASS.shapes + $$.getTargetSelectorSuffix(closest.id)).selectAll('.' + CLASS.shape + '-' + closest.index).each(function () { $$.main.selectAll('.' + CLASS.shapes + $$.getTargetSelectorSuffix(closest.id)).selectAll('.' + CLASS.shape + '-' + closest.index).each(function () {
if (config.data_selection_grouped || $$.isWithinShape(this, closest)) { if (config.data_selection_grouped || $$.isWithinShape(this, closest)) {
$$.toggleShape(this, closest, closest.index); $$.toggleShape(this, closest, closest.index);
$$.config.data_onclick.call($$.api, closest, this); config.data_onclick.call($$.api, closest, this);
} }
}); });
} }
}) } : null)
.call( .call(
config.data_selection_draggable && $$.drag ? ( config.interaction_enabled && config.data_selection_draggable && $$.drag ? (
d3.drag() d3.drag()
.on('drag', function () { $$.drag(d3.mouse(this)); }) .on('drag', function () { $$.drag(d3.mouse(this)); })
.on('start', function () { $$.dragstart(d3.mouse(this)); }) .on('start', function () { $$.dragstart(d3.mouse(this)); })

Loading…
Cancel
Save