You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
266 lines
11 KiB
266 lines
11 KiB
import CLASS from './class'; |
|
import { ChartInternal } from './core'; |
|
import { isFunction } from './util'; |
|
|
|
ChartInternal.prototype.initBrush = function (scale) { |
|
var $$ = this, d3 = $$.d3; |
|
// TODO: dynamically change brushY/brushX according to axis_rotated. |
|
$$.brush = ($$.config.axis_rotated ? d3.brushY() : d3.brushX()).on("brush", function () { |
|
var event = d3.event.sourceEvent; |
|
if (event && event.type === "zoom") { return; } |
|
$$.redrawForBrush(); |
|
}).on("end", function () { |
|
var event = d3.event.sourceEvent; |
|
if (event && event.type === "zoom") { return; } |
|
if ($$.brush.empty() && event && event.type !== 'end') { $$.brush.clear(); } |
|
}); |
|
$$.brush.updateExtent = function () { |
|
var range = this.scale.range(), extent; |
|
if ($$.config.axis_rotated) { |
|
extent = [[0, range[0]], [$$.width2, range[1]]]; |
|
} |
|
else { |
|
extent = [[range[0], 0], [range[1], $$.height2]]; |
|
} |
|
this.extent(extent); |
|
return this; |
|
}; |
|
$$.brush.updateScale = function (scale) { |
|
this.scale = scale; |
|
return this; |
|
}; |
|
$$.brush.update = function (scale) { |
|
this.updateScale(scale || $$.subX).updateExtent(); |
|
$$.context.select('.' + CLASS.brush).call(this); |
|
}; |
|
$$.brush.clear = function () { |
|
$$.context.select('.' + CLASS.brush).call($$.brush.move, null); |
|
}; |
|
$$.brush.selection = function () { |
|
return d3.brushSelection($$.context.select('.' + CLASS.brush).node()); |
|
}; |
|
$$.brush.selectionAsValue = function (selectionAsValue, withTransition) { |
|
var selection, brush; |
|
if (selectionAsValue) { |
|
if ($$.context) { |
|
selection = [this.scale(selectionAsValue[0]), this.scale(selectionAsValue[1])]; |
|
brush = $$.context.select('.' + CLASS.brush); |
|
if (withTransition) { brush = brush.transition(); } |
|
$$.brush.move(brush, selection); |
|
} |
|
return []; |
|
} |
|
selection = $$.brush.selection() || [0,0]; |
|
return [this.scale.invert(selection[0]), this.scale.invert(selection[1])]; |
|
}; |
|
$$.brush.empty = function () { |
|
var selection = $$.brush.selection(); |
|
return !selection || selection[0] === selection[1]; |
|
}; |
|
return $$.brush.updateScale(scale); |
|
}; |
|
ChartInternal.prototype.initSubchart = function () { |
|
var $$ = this, config = $$.config, |
|
context = $$.context = $$.svg.append("g").attr("transform", $$.getTranslate('context')), |
|
visibility = config.subchart_show ? 'visible' : 'hidden'; |
|
|
|
// set style |
|
context.style('visibility', visibility); |
|
|
|
// Define g for chart area |
|
context.append('g') |
|
.attr("clip-path", $$.clipPathForSubchart) |
|
.attr('class', CLASS.chart); |
|
|
|
// Define g for bar chart area |
|
context.select('.' + CLASS.chart).append("g") |
|
.attr("class", CLASS.chartBars); |
|
|
|
// Define g for line chart area |
|
context.select('.' + CLASS.chart).append("g") |
|
.attr("class", CLASS.chartLines); |
|
|
|
// Add extent rect for Brush |
|
context.append("g") |
|
.attr("clip-path", $$.clipPath) |
|
.attr("class", CLASS.brush); |
|
|
|
// ATTENTION: This must be called AFTER chart added |
|
// Add Axis |
|
$$.axes.subx = context.append("g") |
|
.attr("class", CLASS.axisX) |
|
.attr("transform", $$.getTranslate('subx')) |
|
.attr("clip-path", config.axis_rotated ? "" : $$.clipPathForXAxis); |
|
}; |
|
ChartInternal.prototype.initSubchartBrush = function () { |
|
var $$ = this; |
|
// Add extent rect for Brush |
|
$$.initBrush($$.subX).updateExtent(); |
|
$$.context.select('.' + CLASS.brush).call($$.brush); |
|
}; |
|
ChartInternal.prototype.updateTargetsForSubchart = function (targets) { |
|
var $$ = this, context = $$.context, config = $$.config, |
|
contextLineEnter, contextLine, contextBarEnter, contextBar, |
|
classChartBar = $$.classChartBar.bind($$), |
|
classBars = $$.classBars.bind($$), |
|
classChartLine = $$.classChartLine.bind($$), |
|
classLines = $$.classLines.bind($$), |
|
classAreas = $$.classAreas.bind($$); |
|
|
|
if (config.subchart_show) { |
|
//-- Bar --// |
|
contextBar = context.select('.' + CLASS.chartBars).selectAll('.' + CLASS.chartBar) |
|
.data(targets); |
|
contextBarEnter = contextBar.enter().append('g') |
|
.style('opacity', 0); |
|
contextBarEnter.merge(contextBar) |
|
.attr('class', classChartBar); |
|
// Bars for each data |
|
contextBarEnter.append('g') |
|
.attr("class", classBars); |
|
|
|
//-- Line --// |
|
contextLine = context.select('.' + CLASS.chartLines).selectAll('.' + CLASS.chartLine) |
|
.data(targets); |
|
contextLineEnter = contextLine.enter().append('g') |
|
.style('opacity', 0); |
|
contextLineEnter.merge(contextLine) |
|
.attr('class', classChartLine); |
|
// Lines for each data |
|
contextLineEnter.append("g") |
|
.attr("class", classLines); |
|
// Area |
|
contextLineEnter.append("g") |
|
.attr("class", classAreas); |
|
|
|
//-- Brush --// |
|
context.selectAll('.' + CLASS.brush + ' rect') |
|
.attr(config.axis_rotated ? "width" : "height", config.axis_rotated ? $$.width2 : $$.height2); |
|
} |
|
}; |
|
ChartInternal.prototype.updateBarForSubchart = function (durationForExit) { |
|
var $$ = this; |
|
var contextBar = $$.context.selectAll('.' + CLASS.bars).selectAll('.' + CLASS.bar) |
|
.data($$.barData.bind($$)); |
|
var contextBarEnter = contextBar.enter().append('path') |
|
.attr("class", $$.classBar.bind($$)) |
|
.style("stroke", 'none') |
|
.style("fill", $$.color); |
|
contextBar.exit().transition().duration(durationForExit) |
|
.style('opacity', 0) |
|
.remove(); |
|
$$.contextBar = contextBarEnter.merge(contextBar) |
|
.style("opacity", $$.initialOpacity.bind($$)); |
|
}; |
|
ChartInternal.prototype.redrawBarForSubchart = function (drawBarOnSub, withTransition, duration) { |
|
(withTransition ? this.contextBar.transition(Math.random().toString()).duration(duration) : this.contextBar) |
|
.attr('d', drawBarOnSub) |
|
.style('opacity', 1); |
|
}; |
|
ChartInternal.prototype.updateLineForSubchart = function (durationForExit) { |
|
var $$ = this; |
|
var contextLine = $$.context.selectAll('.' + CLASS.lines).selectAll('.' + CLASS.line) |
|
.data($$.lineData.bind($$)); |
|
var contextLineEnter = contextLine.enter().append('path') |
|
.attr('class', $$.classLine.bind($$)) |
|
.style('stroke', $$.color); |
|
contextLine.exit().transition().duration(durationForExit) |
|
.style('opacity', 0) |
|
.remove(); |
|
$$.contextLine = contextLineEnter.merge(contextLine) |
|
.style("opacity", $$.initialOpacity.bind($$)); |
|
}; |
|
ChartInternal.prototype.redrawLineForSubchart = function (drawLineOnSub, withTransition, duration) { |
|
(withTransition ? this.contextLine.transition(Math.random().toString()).duration(duration) : this.contextLine) |
|
.attr("d", drawLineOnSub) |
|
.style('opacity', 1); |
|
}; |
|
ChartInternal.prototype.updateAreaForSubchart = function (durationForExit) { |
|
var $$ = this, d3 = $$.d3; |
|
var contextArea = $$.context.selectAll('.' + CLASS.areas).selectAll('.' + CLASS.area) |
|
.data($$.lineData.bind($$)); |
|
var contextAreaEnter = contextArea.enter().append('path') |
|
.attr("class", $$.classArea.bind($$)) |
|
.style("fill", $$.color) |
|
.style("opacity", function () { $$.orgAreaOpacity = +d3.select(this).style('opacity'); return 0; }); |
|
contextArea.exit().transition().duration(durationForExit) |
|
.style('opacity', 0) |
|
.remove(); |
|
$$.contextArea = contextAreaEnter.merge(contextArea) |
|
.style("opacity", 0); |
|
}; |
|
ChartInternal.prototype.redrawAreaForSubchart = function (drawAreaOnSub, withTransition, duration) { |
|
(withTransition ? this.contextArea.transition(Math.random().toString()).duration(duration) : this.contextArea) |
|
.attr("d", drawAreaOnSub) |
|
.style("fill", this.color) |
|
.style("opacity", this.orgAreaOpacity); |
|
}; |
|
ChartInternal.prototype.redrawSubchart = function (withSubchart, transitions, duration, durationForExit, areaIndices, barIndices, lineIndices) { |
|
var $$ = this, d3 = $$.d3, config = $$.config, |
|
drawAreaOnSub, drawBarOnSub, drawLineOnSub; |
|
|
|
$$.context.style('visibility', config.subchart_show ? 'visible' : 'hidden'); |
|
|
|
// subchart |
|
if (config.subchart_show) { |
|
// reflect main chart to extent on subchart if zoomed |
|
if (d3.event && d3.event.type === 'zoom') { |
|
$$.brush.selectionAsValue($$.x.orgDomain()); |
|
} |
|
// update subchart elements if needed |
|
if (withSubchart) { |
|
// extent rect |
|
if (!$$.brush.empty()) { |
|
$$.brush.selectionAsValue($$.x.orgDomain()); |
|
} |
|
// setup drawer - MEMO: this must be called after axis updated |
|
drawAreaOnSub = $$.generateDrawArea(areaIndices, true); |
|
drawBarOnSub = $$.generateDrawBar(barIndices, true); |
|
drawLineOnSub = $$.generateDrawLine(lineIndices, true); |
|
|
|
$$.updateBarForSubchart(duration); |
|
$$.updateLineForSubchart(duration); |
|
$$.updateAreaForSubchart(duration); |
|
|
|
$$.redrawBarForSubchart(drawBarOnSub, duration, duration); |
|
$$.redrawLineForSubchart(drawLineOnSub, duration, duration); |
|
$$.redrawAreaForSubchart(drawAreaOnSub, duration, duration); |
|
} |
|
} |
|
}; |
|
ChartInternal.prototype.redrawForBrush = function () { |
|
var $$ = this, x = $$.x, d3 = $$.d3, s; |
|
$$.redraw({ |
|
withTransition: false, |
|
withY: $$.config.zoom_rescale, |
|
withSubchart: false, |
|
withUpdateXDomain: true, |
|
withEventRect: false, |
|
withDimension: false |
|
}); |
|
// update zoom transation binded to event rect |
|
s = d3.event.selection || $$.brush.scale.range(); |
|
$$.main.select('.' + CLASS.eventRect).call($$.zoom.transform, d3.zoomIdentity |
|
.scale($$.width / (s[1] - s[0])) |
|
.translate(-s[0], 0)); |
|
$$.config.subchart_onbrush.call($$.api, x.orgDomain()); |
|
}; |
|
ChartInternal.prototype.transformContext = function (withTransition, transitions) { |
|
var $$ = this, subXAxis; |
|
if (transitions && transitions.axisSubX) { |
|
subXAxis = transitions.axisSubX; |
|
} else { |
|
subXAxis = $$.context.select('.' + CLASS.axisX); |
|
if (withTransition) { subXAxis = subXAxis.transition(); } |
|
} |
|
$$.context.attr("transform", $$.getTranslate('context')); |
|
subXAxis.attr("transform", $$.getTranslate('subx')); |
|
}; |
|
ChartInternal.prototype.getDefaultSelection = function () { |
|
var $$ = this, config = $$.config, |
|
selection = isFunction(config.axis_x_selection) ? config.axis_x_selection($$.getXDomain($$.data.targets)) : config.axis_x_selection; |
|
if ($$.isTimeSeries()) { |
|
selection = [$$.parseDate(selection[0]), $$.parseDate(selection[1])]; |
|
} |
|
return selection; |
|
};
|
|
|