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.
1325 lines
34 KiB
1325 lines
34 KiB
1 year ago
|
import { ChartInternal } from './chart-internal'
|
||
|
import { Chart } from './chart'
|
||
|
import { AxisInternal } from './axis-internal'
|
||
|
import Axis from './axis'
|
||
|
import CLASS from './class'
|
||
|
|
||
|
import {
|
||
|
asHalfPixel,
|
||
|
getOption,
|
||
|
getPathBox,
|
||
|
isFunction,
|
||
|
isValue,
|
||
|
notEmpty
|
||
|
} from './util'
|
||
|
|
||
|
var c3 = {
|
||
|
version: '0.7.20',
|
||
|
chart: {
|
||
|
fn: Chart.prototype,
|
||
|
internal: {
|
||
|
fn: ChartInternal.prototype,
|
||
|
axis: {
|
||
|
fn: Axis.prototype,
|
||
|
internal: {
|
||
|
fn: AxisInternal.prototype
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
generate: function(config) {
|
||
|
return new Chart(config)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export { c3 }
|
||
|
|
||
|
ChartInternal.prototype.beforeInit = function() {
|
||
|
// can do something
|
||
|
}
|
||
|
ChartInternal.prototype.afterInit = function() {
|
||
|
// can do something
|
||
|
}
|
||
|
ChartInternal.prototype.init = function() {
|
||
|
var $$ = this,
|
||
|
config = $$.config
|
||
|
|
||
|
$$.initParams()
|
||
|
|
||
|
if (config.data_url) {
|
||
|
$$.convertUrlToData(
|
||
|
config.data_url,
|
||
|
config.data_mimeType,
|
||
|
config.data_headers,
|
||
|
config.data_keys,
|
||
|
$$.initWithData
|
||
|
)
|
||
|
} else if (config.data_json) {
|
||
|
$$.initWithData($$.convertJsonToData(config.data_json, config.data_keys))
|
||
|
} else if (config.data_rows) {
|
||
|
$$.initWithData($$.convertRowsToData(config.data_rows))
|
||
|
} else if (config.data_columns) {
|
||
|
$$.initWithData($$.convertColumnsToData(config.data_columns))
|
||
|
} else {
|
||
|
throw Error('url or json or rows or columns is required.')
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.initParams = function() {
|
||
|
var $$ = this,
|
||
|
d3 = $$.d3,
|
||
|
config = $$.config
|
||
|
|
||
|
// MEMO: clipId needs to be unique because it conflicts when multiple charts exist
|
||
|
$$.clipId = 'c3-' + new Date().valueOf() + '-clip'
|
||
|
$$.clipIdForXAxis = $$.clipId + '-xaxis'
|
||
|
$$.clipIdForYAxis = $$.clipId + '-yaxis'
|
||
|
$$.clipIdForGrid = $$.clipId + '-grid'
|
||
|
$$.clipIdForSubchart = $$.clipId + '-subchart'
|
||
|
$$.clipPath = $$.getClipPath($$.clipId)
|
||
|
$$.clipPathForXAxis = $$.getClipPath($$.clipIdForXAxis)
|
||
|
$$.clipPathForYAxis = $$.getClipPath($$.clipIdForYAxis)
|
||
|
$$.clipPathForGrid = $$.getClipPath($$.clipIdForGrid)
|
||
|
$$.clipPathForSubchart = $$.getClipPath($$.clipIdForSubchart)
|
||
|
|
||
|
$$.dragStart = null
|
||
|
$$.dragging = false
|
||
|
$$.flowing = false
|
||
|
$$.cancelClick = false
|
||
|
$$.mouseover = undefined
|
||
|
$$.transiting = false
|
||
|
|
||
|
$$.color = $$.generateColor()
|
||
|
$$.levelColor = $$.generateLevelColor()
|
||
|
|
||
|
$$.dataTimeParse = (config.data_xLocaltime ? d3.timeParse : d3.utcParse)(
|
||
|
$$.config.data_xFormat
|
||
|
)
|
||
|
$$.axisTimeFormat = config.axis_x_localtime ? d3.timeFormat : d3.utcFormat
|
||
|
$$.defaultAxisTimeFormat = function(date) {
|
||
|
if (date.getMilliseconds()) {
|
||
|
return d3.timeFormat('.%L')(date)
|
||
|
}
|
||
|
if (date.getSeconds()) {
|
||
|
return d3.timeFormat(':%S')(date)
|
||
|
}
|
||
|
if (date.getMinutes()) {
|
||
|
return d3.timeFormat('%I:%M')(date)
|
||
|
}
|
||
|
if (date.getHours()) {
|
||
|
return d3.timeFormat('%I %p')(date)
|
||
|
}
|
||
|
if (date.getDay() && date.getDate() !== 1) {
|
||
|
return d3.timeFormat('%-m/%-d')(date)
|
||
|
}
|
||
|
if (date.getDate() !== 1) {
|
||
|
return d3.timeFormat('%-m/%-d')(date)
|
||
|
}
|
||
|
if (date.getMonth()) {
|
||
|
return d3.timeFormat('%-m/%-d')(date)
|
||
|
}
|
||
|
return d3.timeFormat('%Y/%-m/%-d')(date)
|
||
|
}
|
||
|
$$.hiddenTargetIds = []
|
||
|
$$.hiddenLegendIds = []
|
||
|
$$.focusedTargetIds = []
|
||
|
$$.defocusedTargetIds = []
|
||
|
|
||
|
$$.xOrient = config.axis_rotated
|
||
|
? config.axis_x_inner
|
||
|
? 'right'
|
||
|
: 'left'
|
||
|
: config.axis_x_inner
|
||
|
? 'top'
|
||
|
: 'bottom'
|
||
|
$$.yOrient = config.axis_rotated
|
||
|
? config.axis_y_inner
|
||
|
? 'top'
|
||
|
: 'bottom'
|
||
|
: config.axis_y_inner
|
||
|
? 'right'
|
||
|
: 'left'
|
||
|
$$.y2Orient = config.axis_rotated
|
||
|
? config.axis_y2_inner
|
||
|
? 'bottom'
|
||
|
: 'top'
|
||
|
: config.axis_y2_inner
|
||
|
? 'left'
|
||
|
: 'right'
|
||
|
$$.subXOrient = config.axis_rotated ? 'left' : 'bottom'
|
||
|
|
||
|
$$.isLegendRight = config.legend_position === 'right'
|
||
|
$$.isLegendInset = config.legend_position === 'inset'
|
||
|
$$.isLegendTop =
|
||
|
config.legend_inset_anchor === 'top-left' ||
|
||
|
config.legend_inset_anchor === 'top-right'
|
||
|
$$.isLegendLeft =
|
||
|
config.legend_inset_anchor === 'top-left' ||
|
||
|
config.legend_inset_anchor === 'bottom-left'
|
||
|
$$.legendStep = 0
|
||
|
$$.legendItemWidth = 0
|
||
|
$$.legendItemHeight = 0
|
||
|
|
||
|
$$.currentMaxTickWidths = {
|
||
|
x: 0,
|
||
|
y: 0,
|
||
|
y2: 0
|
||
|
}
|
||
|
|
||
|
$$.rotated_padding_left = 30
|
||
|
$$.rotated_padding_right = config.axis_rotated && !config.axis_x_show ? 0 : 30
|
||
|
$$.rotated_padding_top = 5
|
||
|
|
||
|
$$.withoutFadeIn = {}
|
||
|
|
||
|
$$.intervalForObserveInserted = undefined
|
||
|
|
||
|
$$.axes.subx = d3.selectAll([]) // needs when excluding subchart.js
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.initChartElements = function() {
|
||
|
if (this.initBar) {
|
||
|
this.initBar()
|
||
|
}
|
||
|
if (this.initLine) {
|
||
|
this.initLine()
|
||
|
}
|
||
|
if (this.initArc) {
|
||
|
this.initArc()
|
||
|
}
|
||
|
if (this.initGauge) {
|
||
|
this.initGauge()
|
||
|
}
|
||
|
if (this.initText) {
|
||
|
this.initText()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.initWithData = function(data) {
|
||
|
var $$ = this,
|
||
|
d3 = $$.d3,
|
||
|
config = $$.config
|
||
|
var defs,
|
||
|
main,
|
||
|
binding = true
|
||
|
|
||
|
$$.axis = new Axis($$)
|
||
|
|
||
|
if (!config.bindto) {
|
||
|
$$.selectChart = d3.selectAll([])
|
||
|
} else if (typeof config.bindto.node === 'function') {
|
||
|
$$.selectChart = config.bindto
|
||
|
} else {
|
||
|
$$.selectChart = d3.select(config.bindto)
|
||
|
}
|
||
|
if ($$.selectChart.empty()) {
|
||
|
$$.selectChart = d3
|
||
|
.select(document.createElement('div'))
|
||
|
.style('opacity', 0)
|
||
|
$$.observeInserted($$.selectChart)
|
||
|
binding = false
|
||
|
}
|
||
|
$$.selectChart.html('').classed('c3', true)
|
||
|
|
||
|
// Init data as targets
|
||
|
$$.data.xs = {}
|
||
|
$$.data.targets = $$.convertDataToTargets(data)
|
||
|
|
||
|
if (config.data_filter) {
|
||
|
$$.data.targets = $$.data.targets.filter(config.data_filter)
|
||
|
}
|
||
|
|
||
|
// Set targets to hide if needed
|
||
|
if (config.data_hide) {
|
||
|
$$.addHiddenTargetIds(
|
||
|
config.data_hide === true
|
||
|
? $$.mapToIds($$.data.targets)
|
||
|
: config.data_hide
|
||
|
)
|
||
|
}
|
||
|
if (config.legend_hide) {
|
||
|
$$.addHiddenLegendIds(
|
||
|
config.legend_hide === true
|
||
|
? $$.mapToIds($$.data.targets)
|
||
|
: config.legend_hide
|
||
|
)
|
||
|
}
|
||
|
|
||
|
if ($$.isStanfordGraphType()) {
|
||
|
$$.initStanfordData()
|
||
|
}
|
||
|
|
||
|
// Init sizes and scales
|
||
|
$$.updateSizes()
|
||
|
$$.updateScales()
|
||
|
|
||
|
// Set domains for each scale
|
||
|
$$.x.domain(d3.extent($$.getXDomain($$.data.targets)))
|
||
|
$$.y.domain($$.getYDomain($$.data.targets, 'y'))
|
||
|
$$.y2.domain($$.getYDomain($$.data.targets, 'y2'))
|
||
|
$$.subX.domain($$.x.domain())
|
||
|
$$.subY.domain($$.y.domain())
|
||
|
$$.subY2.domain($$.y2.domain())
|
||
|
|
||
|
// Save original x domain for zoom update
|
||
|
$$.orgXDomain = $$.x.domain()
|
||
|
|
||
|
/*-- Basic Elements --*/
|
||
|
|
||
|
// Define svgs
|
||
|
$$.svg = $$.selectChart
|
||
|
.append('svg')
|
||
|
.style('overflow', 'hidden')
|
||
|
.on('mouseenter', function() {
|
||
|
return config.onmouseover.call($$)
|
||
|
})
|
||
|
.on('mouseleave', function() {
|
||
|
return config.onmouseout.call($$)
|
||
|
})
|
||
|
|
||
|
if ($$.config.svg_classname) {
|
||
|
$$.svg.attr('class', $$.config.svg_classname)
|
||
|
}
|
||
|
|
||
|
// Define defs
|
||
|
defs = $$.svg.append('defs')
|
||
|
$$.clipChart = $$.appendClip(defs, $$.clipId)
|
||
|
$$.clipXAxis = $$.appendClip(defs, $$.clipIdForXAxis)
|
||
|
$$.clipYAxis = $$.appendClip(defs, $$.clipIdForYAxis)
|
||
|
$$.clipGrid = $$.appendClip(defs, $$.clipIdForGrid)
|
||
|
$$.clipSubchart = $$.appendClip(defs, $$.clipIdForSubchart)
|
||
|
$$.updateSvgSize()
|
||
|
|
||
|
// Define regions
|
||
|
main = $$.main = $$.svg.append('g').attr('transform', $$.getTranslate('main'))
|
||
|
|
||
|
if ($$.initPie) {
|
||
|
$$.initPie()
|
||
|
}
|
||
|
if ($$.initDragZoom) {
|
||
|
$$.initDragZoom()
|
||
|
}
|
||
|
if (config.subchart_show && $$.initSubchart) {
|
||
|
$$.initSubchart()
|
||
|
}
|
||
|
if ($$.initTooltip) {
|
||
|
$$.initTooltip()
|
||
|
}
|
||
|
if ($$.initLegend) {
|
||
|
$$.initLegend()
|
||
|
}
|
||
|
if ($$.initTitle) {
|
||
|
$$.initTitle()
|
||
|
}
|
||
|
if ($$.initZoom) {
|
||
|
$$.initZoom()
|
||
|
}
|
||
|
if ($$.isStanfordGraphType()) {
|
||
|
$$.drawColorScale()
|
||
|
}
|
||
|
|
||
|
// Update selection based on size and scale
|
||
|
// TODO: currently this must be called after initLegend because of update of sizes, but it should be done in initSubchart.
|
||
|
if (config.subchart_show && $$.initSubchartBrush) {
|
||
|
$$.initSubchartBrush()
|
||
|
}
|
||
|
|
||
|
/*-- Main Region --*/
|
||
|
|
||
|
// text when empty
|
||
|
main
|
||
|
.append('text')
|
||
|
.attr('class', CLASS.text + ' ' + CLASS.empty)
|
||
|
.attr('text-anchor', 'middle') // horizontal centering of text at x position in all browsers.
|
||
|
.attr('dominant-baseline', 'middle') // vertical centering of text at y position in all browsers, except IE.
|
||
|
|
||
|
// Regions
|
||
|
$$.initRegion()
|
||
|
|
||
|
// Grids
|
||
|
$$.initGrid()
|
||
|
|
||
|
// Define g for chart area
|
||
|
main
|
||
|
.append('g')
|
||
|
.attr('clip-path', $$.clipPath)
|
||
|
.attr('class', CLASS.chart)
|
||
|
|
||
|
// Grid lines
|
||
|
if (config.grid_lines_front) {
|
||
|
$$.initGridLines()
|
||
|
}
|
||
|
|
||
|
$$.initStanfordElements()
|
||
|
|
||
|
// Cover whole with rects for events
|
||
|
$$.initEventRect()
|
||
|
|
||
|
// Define g for chart
|
||
|
$$.initChartElements()
|
||
|
|
||
|
// Add Axis
|
||
|
$$.axis.init()
|
||
|
|
||
|
// Set targets
|
||
|
$$.updateTargets($$.data.targets)
|
||
|
|
||
|
// Set default extent if defined
|
||
|
if (config.axis_x_selection) {
|
||
|
$$.brush.selectionAsValue($$.getDefaultSelection())
|
||
|
}
|
||
|
|
||
|
// Draw with targets
|
||
|
if (binding) {
|
||
|
$$.updateDimension()
|
||
|
$$.config.oninit.call($$)
|
||
|
$$.redraw({
|
||
|
withTransition: false,
|
||
|
withTransform: true,
|
||
|
withUpdateXDomain: true,
|
||
|
withUpdateOrgXDomain: true,
|
||
|
withTransitionForAxis: false
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// Bind to resize event
|
||
|
$$.bindResize()
|
||
|
|
||
|
// Bind to window focus event
|
||
|
$$.bindWindowFocus()
|
||
|
|
||
|
// export element of the chart
|
||
|
$$.api.element = $$.selectChart.node()
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.smoothLines = function(el, type) {
|
||
|
var $$ = this
|
||
|
if (type === 'grid') {
|
||
|
el.each(function() {
|
||
|
var g = $$.d3.select(this),
|
||
|
x1 = g.attr('x1'),
|
||
|
x2 = g.attr('x2'),
|
||
|
y1 = g.attr('y1'),
|
||
|
y2 = g.attr('y2')
|
||
|
g.attr({
|
||
|
x1: Math.ceil(x1),
|
||
|
x2: Math.ceil(x2),
|
||
|
y1: Math.ceil(y1),
|
||
|
y2: Math.ceil(y2)
|
||
|
})
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.updateSizes = function() {
|
||
|
var $$ = this,
|
||
|
config = $$.config
|
||
|
var legendHeight = $$.legend ? $$.getLegendHeight() : 0,
|
||
|
legendWidth = $$.legend ? $$.getLegendWidth() : 0,
|
||
|
legendHeightForBottom =
|
||
|
$$.isLegendRight || $$.isLegendInset ? 0 : legendHeight,
|
||
|
hasArc = $$.hasArcType(),
|
||
|
xAxisHeight =
|
||
|
config.axis_rotated || hasArc ? 0 : $$.getHorizontalAxisHeight('x'),
|
||
|
subchartXAxisHeight = config.axis_rotated || hasArc ? 0 : $$.getHorizontalAxisHeight('x',true),
|
||
|
subchartHeight =
|
||
|
config.subchart_show && !hasArc
|
||
|
? config.subchart_size_height + subchartXAxisHeight
|
||
|
: 0
|
||
|
|
||
|
$$.currentWidth = $$.getCurrentWidth()
|
||
|
$$.currentHeight = $$.getCurrentHeight()
|
||
|
|
||
|
// for main
|
||
|
$$.margin = config.axis_rotated
|
||
|
? {
|
||
|
top: $$.getHorizontalAxisHeight('y2') + $$.getCurrentPaddingTop(),
|
||
|
right: hasArc ? 0 : $$.getCurrentPaddingRight(),
|
||
|
bottom:
|
||
|
$$.getHorizontalAxisHeight('y') +
|
||
|
legendHeightForBottom +
|
||
|
$$.getCurrentPaddingBottom(),
|
||
|
left: subchartHeight + (hasArc ? 0 : $$.getCurrentPaddingLeft())
|
||
|
}
|
||
|
: {
|
||
|
top: 4 + $$.getCurrentPaddingTop(), // for top tick text
|
||
|
right: hasArc ? 0 : $$.getCurrentPaddingRight(),
|
||
|
bottom:
|
||
|
xAxisHeight +
|
||
|
subchartHeight +
|
||
|
legendHeightForBottom +
|
||
|
$$.getCurrentPaddingBottom(),
|
||
|
left: hasArc ? 0 : $$.getCurrentPaddingLeft()
|
||
|
}
|
||
|
|
||
|
// for subchart
|
||
|
$$.margin2 = config.axis_rotated
|
||
|
? {
|
||
|
top: $$.margin.top,
|
||
|
right: NaN,
|
||
|
bottom: 20 + legendHeightForBottom,
|
||
|
left: $$.rotated_padding_left
|
||
|
}
|
||
|
: {
|
||
|
top: $$.currentHeight - subchartHeight - legendHeightForBottom,
|
||
|
right: NaN,
|
||
|
bottom: subchartXAxisHeight + legendHeightForBottom,
|
||
|
left: $$.margin.left
|
||
|
}
|
||
|
|
||
|
// for legend
|
||
|
$$.margin3 = {
|
||
|
top: 0,
|
||
|
right: NaN,
|
||
|
bottom: 0,
|
||
|
left: 0
|
||
|
}
|
||
|
if ($$.updateSizeForLegend) {
|
||
|
$$.updateSizeForLegend(legendHeight, legendWidth)
|
||
|
}
|
||
|
|
||
|
$$.width = $$.currentWidth - $$.margin.left - $$.margin.right
|
||
|
$$.height = $$.currentHeight - $$.margin.top - $$.margin.bottom
|
||
|
if ($$.width < 0) {
|
||
|
$$.width = 0
|
||
|
}
|
||
|
if ($$.height < 0) {
|
||
|
$$.height = 0
|
||
|
}
|
||
|
|
||
|
$$.width2 = config.axis_rotated
|
||
|
? $$.margin.left - $$.rotated_padding_left - $$.rotated_padding_right
|
||
|
: $$.width
|
||
|
$$.height2 = config.axis_rotated
|
||
|
? $$.height
|
||
|
: $$.currentHeight - $$.margin2.top - $$.margin2.bottom
|
||
|
if ($$.width2 < 0) {
|
||
|
$$.width2 = 0
|
||
|
}
|
||
|
if ($$.height2 < 0) {
|
||
|
$$.height2 = 0
|
||
|
}
|
||
|
|
||
|
// for arc
|
||
|
$$.arcWidth = $$.width - ($$.isLegendRight ? legendWidth + 10 : 0)
|
||
|
$$.arcHeight = $$.height - ($$.isLegendRight ? 0 : 10)
|
||
|
if ($$.hasType('gauge') && !config.gauge_fullCircle) {
|
||
|
$$.arcHeight += $$.height - $$.getGaugeLabelHeight()
|
||
|
}
|
||
|
if ($$.updateRadius) {
|
||
|
$$.updateRadius()
|
||
|
}
|
||
|
|
||
|
if ($$.isLegendRight && hasArc) {
|
||
|
$$.margin3.left = $$.arcWidth / 2 + $$.radiusExpanded * 1.1
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.updateTargets = function(targets) {
|
||
|
var $$ = this,
|
||
|
config = $$.config
|
||
|
|
||
|
/*-- Main --*/
|
||
|
|
||
|
//-- Text --//
|
||
|
$$.updateTargetsForText(targets)
|
||
|
|
||
|
//-- Bar --//
|
||
|
$$.updateTargetsForBar(targets)
|
||
|
|
||
|
//-- Line --//
|
||
|
$$.updateTargetsForLine(targets)
|
||
|
|
||
|
//-- Arc --//
|
||
|
if ($$.hasArcType() && $$.updateTargetsForArc) {
|
||
|
$$.updateTargetsForArc(targets)
|
||
|
}
|
||
|
|
||
|
/*-- Sub --*/
|
||
|
|
||
|
if (config.subchart_show && $$.updateTargetsForSubchart) {
|
||
|
$$.updateTargetsForSubchart(targets)
|
||
|
}
|
||
|
|
||
|
// Fade-in each chart
|
||
|
$$.showTargets()
|
||
|
}
|
||
|
ChartInternal.prototype.showTargets = function() {
|
||
|
var $$ = this
|
||
|
$$.svg
|
||
|
.selectAll('.' + CLASS.target)
|
||
|
.filter(function(d) {
|
||
|
return $$.isTargetToShow(d.id)
|
||
|
})
|
||
|
.transition()
|
||
|
.duration($$.config.transition_duration)
|
||
|
.style('opacity', 1)
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.redraw = function(options, transitions) {
|
||
|
var $$ = this,
|
||
|
main = $$.main,
|
||
|
d3 = $$.d3,
|
||
|
config = $$.config
|
||
|
var areaIndices = $$.getShapeIndices($$.isAreaType),
|
||
|
barIndices = $$.getShapeIndices($$.isBarType),
|
||
|
lineIndices = $$.getShapeIndices($$.isLineType)
|
||
|
var withY,
|
||
|
withSubchart,
|
||
|
withTransition,
|
||
|
withTransitionForExit,
|
||
|
withTransitionForAxis,
|
||
|
withTransform,
|
||
|
withUpdateXDomain,
|
||
|
withUpdateOrgXDomain,
|
||
|
withTrimXDomain,
|
||
|
withLegend,
|
||
|
withEventRect,
|
||
|
withDimension,
|
||
|
withUpdateXAxis
|
||
|
var hideAxis = $$.hasArcType()
|
||
|
var drawArea, drawBar, drawLine, xForText, yForText
|
||
|
var duration, durationForExit, durationForAxis
|
||
|
var transitionsToWait, waitForDraw, flow, transition
|
||
|
var targetsToShow = $$.filterTargetsToShow($$.data.targets),
|
||
|
tickValues,
|
||
|
i,
|
||
|
intervalForCulling,
|
||
|
xDomainForZoom
|
||
|
var xv = $$.xv.bind($$),
|
||
|
cx,
|
||
|
cy
|
||
|
|
||
|
options = options || {}
|
||
|
withY = getOption(options, 'withY', true)
|
||
|
withSubchart = getOption(options, 'withSubchart', true)
|
||
|
withTransition = getOption(options, 'withTransition', true)
|
||
|
withTransform = getOption(options, 'withTransform', false)
|
||
|
withUpdateXDomain = getOption(options, 'withUpdateXDomain', false)
|
||
|
withUpdateOrgXDomain = getOption(options, 'withUpdateOrgXDomain', false)
|
||
|
withTrimXDomain = getOption(options, 'withTrimXDomain', true)
|
||
|
withUpdateXAxis = getOption(options, 'withUpdateXAxis', withUpdateXDomain)
|
||
|
withLegend = getOption(options, 'withLegend', false)
|
||
|
withEventRect = getOption(options, 'withEventRect', true)
|
||
|
withDimension = getOption(options, 'withDimension', true)
|
||
|
withTransitionForExit = getOption(
|
||
|
options,
|
||
|
'withTransitionForExit',
|
||
|
withTransition
|
||
|
)
|
||
|
withTransitionForAxis = getOption(
|
||
|
options,
|
||
|
'withTransitionForAxis',
|
||
|
withTransition
|
||
|
)
|
||
|
|
||
|
duration = withTransition ? config.transition_duration : 0
|
||
|
durationForExit = withTransitionForExit ? duration : 0
|
||
|
durationForAxis = withTransitionForAxis ? duration : 0
|
||
|
|
||
|
transitions = transitions || $$.axis.generateTransitions(durationForAxis)
|
||
|
|
||
|
// update legend and transform each g
|
||
|
if (withLegend && config.legend_show) {
|
||
|
$$.updateLegend($$.mapToIds($$.data.targets), options, transitions)
|
||
|
} else if (withDimension) {
|
||
|
// need to update dimension (e.g. axis.y.tick.values) because y tick values should change
|
||
|
// no need to update axis in it because they will be updated in redraw()
|
||
|
$$.updateDimension(true)
|
||
|
}
|
||
|
|
||
|
// MEMO: needed for grids calculation
|
||
|
if ($$.isCategorized() && targetsToShow.length === 0) {
|
||
|
$$.x.domain([0, $$.axes.x.selectAll('.tick').size()])
|
||
|
}
|
||
|
|
||
|
if (targetsToShow.length) {
|
||
|
$$.updateXDomain(
|
||
|
targetsToShow,
|
||
|
withUpdateXDomain,
|
||
|
withUpdateOrgXDomain,
|
||
|
withTrimXDomain
|
||
|
)
|
||
|
if (!config.axis_x_tick_values) {
|
||
|
tickValues = $$.axis.updateXAxisTickValues(targetsToShow)
|
||
|
}
|
||
|
} else {
|
||
|
$$.xAxis.tickValues([])
|
||
|
$$.subXAxis.tickValues([])
|
||
|
}
|
||
|
|
||
|
if (config.zoom_rescale && !options.flow) {
|
||
|
xDomainForZoom = $$.x.orgDomain()
|
||
|
}
|
||
|
|
||
|
$$.y.domain($$.getYDomain(targetsToShow, 'y', xDomainForZoom))
|
||
|
$$.y2.domain($$.getYDomain(targetsToShow, 'y2', xDomainForZoom))
|
||
|
|
||
|
if (!config.axis_y_tick_values && config.axis_y_tick_count) {
|
||
|
$$.yAxis.tickValues(
|
||
|
$$.axis.generateTickValues($$.y.domain(), config.axis_y_tick_count)
|
||
|
)
|
||
|
}
|
||
|
if (!config.axis_y2_tick_values && config.axis_y2_tick_count) {
|
||
|
$$.y2Axis.tickValues(
|
||
|
$$.axis.generateTickValues($$.y2.domain(), config.axis_y2_tick_count)
|
||
|
)
|
||
|
}
|
||
|
|
||
|
// axes
|
||
|
$$.axis.redraw(durationForAxis, hideAxis)
|
||
|
|
||
|
// Update axis label
|
||
|
$$.axis.updateLabels(withTransition)
|
||
|
|
||
|
// show/hide if manual culling needed
|
||
|
if ((withUpdateXDomain || withUpdateXAxis) && targetsToShow.length) {
|
||
|
if (config.axis_x_tick_culling && tickValues) {
|
||
|
for (i = 1; i < tickValues.length; i++) {
|
||
|
if (tickValues.length / i < config.axis_x_tick_culling_max) {
|
||
|
intervalForCulling = i
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
$$.svg.selectAll('.' + CLASS.axisX + ' .tick text').each(function(e) {
|
||
|
var index = tickValues.indexOf(e)
|
||
|
if (index >= 0) {
|
||
|
d3.select(this).style(
|
||
|
'display',
|
||
|
index % intervalForCulling ? 'none' : 'block'
|
||
|
)
|
||
|
}
|
||
|
})
|
||
|
} else {
|
||
|
$$.svg
|
||
|
.selectAll('.' + CLASS.axisX + ' .tick text')
|
||
|
.style('display', 'block')
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// setup drawer - MEMO: these must be called after axis updated
|
||
|
drawArea = $$.generateDrawArea
|
||
|
? $$.generateDrawArea(areaIndices, false)
|
||
|
: undefined
|
||
|
drawBar = $$.generateDrawBar ? $$.generateDrawBar(barIndices) : undefined
|
||
|
drawLine = $$.generateDrawLine
|
||
|
? $$.generateDrawLine(lineIndices, false)
|
||
|
: undefined
|
||
|
xForText = $$.generateXYForText(areaIndices, barIndices, lineIndices, true)
|
||
|
yForText = $$.generateXYForText(areaIndices, barIndices, lineIndices, false)
|
||
|
|
||
|
// update circleY based on updated parameters
|
||
|
$$.updateCircleY()
|
||
|
// generate circle x/y functions depending on updated params
|
||
|
cx = ($$.config.axis_rotated ? $$.circleY : $$.circleX).bind($$)
|
||
|
cy = ($$.config.axis_rotated ? $$.circleX : $$.circleY).bind($$)
|
||
|
|
||
|
// Update sub domain
|
||
|
if (withY) {
|
||
|
$$.subY.domain($$.getYDomain(targetsToShow, 'y'))
|
||
|
$$.subY2.domain($$.getYDomain(targetsToShow, 'y2'))
|
||
|
}
|
||
|
|
||
|
// xgrid focus
|
||
|
$$.updateXgridFocus()
|
||
|
|
||
|
// Data empty label positioning and text.
|
||
|
main
|
||
|
.select('text.' + CLASS.text + '.' + CLASS.empty)
|
||
|
.attr('x', $$.width / 2)
|
||
|
.attr('y', $$.height / 2)
|
||
|
.text(config.data_empty_label_text)
|
||
|
.transition()
|
||
|
.style('opacity', targetsToShow.length ? 0 : 1)
|
||
|
|
||
|
// event rect
|
||
|
if (withEventRect) {
|
||
|
$$.redrawEventRect()
|
||
|
}
|
||
|
|
||
|
// grid
|
||
|
$$.updateGrid(duration)
|
||
|
|
||
|
$$.updateStanfordElements(duration)
|
||
|
|
||
|
// rect for regions
|
||
|
$$.updateRegion(duration)
|
||
|
|
||
|
// bars
|
||
|
$$.updateBar(durationForExit)
|
||
|
|
||
|
// lines, areas and circles
|
||
|
$$.updateLine(durationForExit)
|
||
|
$$.updateArea(durationForExit)
|
||
|
$$.updateCircle(cx, cy)
|
||
|
|
||
|
// text
|
||
|
if ($$.hasDataLabel()) {
|
||
|
$$.updateText(xForText, yForText, durationForExit)
|
||
|
}
|
||
|
|
||
|
// title
|
||
|
if ($$.redrawTitle) {
|
||
|
$$.redrawTitle()
|
||
|
}
|
||
|
|
||
|
// arc
|
||
|
if ($$.redrawArc) {
|
||
|
$$.redrawArc(duration, durationForExit, withTransform)
|
||
|
}
|
||
|
|
||
|
// subchart
|
||
|
if (config.subchart_show && $$.redrawSubchart) {
|
||
|
$$.redrawSubchart(
|
||
|
withSubchart,
|
||
|
transitions,
|
||
|
duration,
|
||
|
durationForExit,
|
||
|
areaIndices,
|
||
|
barIndices,
|
||
|
lineIndices
|
||
|
)
|
||
|
}
|
||
|
|
||
|
if ($$.isStanfordGraphType()) {
|
||
|
$$.drawColorScale()
|
||
|
}
|
||
|
|
||
|
// circles for select
|
||
|
main
|
||
|
.selectAll('.' + CLASS.selectedCircles)
|
||
|
.filter($$.isBarType.bind($$))
|
||
|
.selectAll('circle')
|
||
|
.remove()
|
||
|
|
||
|
if (options.flow) {
|
||
|
flow = $$.generateFlow({
|
||
|
targets: targetsToShow,
|
||
|
flow: options.flow,
|
||
|
duration: options.flow.duration,
|
||
|
drawBar: drawBar,
|
||
|
drawLine: drawLine,
|
||
|
drawArea: drawArea,
|
||
|
cx: cx,
|
||
|
cy: cy,
|
||
|
xv: xv,
|
||
|
xForText: xForText,
|
||
|
yForText: yForText
|
||
|
})
|
||
|
}
|
||
|
|
||
|
if (duration && $$.isTabVisible()) {
|
||
|
// Only use transition if tab visible. See #938.
|
||
|
// transition should be derived from one transition
|
||
|
transition = d3.transition().duration(duration)
|
||
|
transitionsToWait = []
|
||
|
;[
|
||
|
$$.redrawBar(drawBar, true, transition),
|
||
|
$$.redrawLine(drawLine, true, transition),
|
||
|
$$.redrawArea(drawArea, true, transition),
|
||
|
$$.redrawCircle(cx, cy, true, transition),
|
||
|
$$.redrawText(xForText, yForText, options.flow, true, transition),
|
||
|
$$.redrawRegion(true, transition),
|
||
|
$$.redrawGrid(true, transition)
|
||
|
].forEach(function(transitions) {
|
||
|
transitions.forEach(function(transition) {
|
||
|
transitionsToWait.push(transition)
|
||
|
})
|
||
|
})
|
||
|
// Wait for end of transitions to call flow and onrendered callback
|
||
|
waitForDraw = $$.generateWait()
|
||
|
transitionsToWait.forEach(function(t) {
|
||
|
waitForDraw.add(t)
|
||
|
})
|
||
|
waitForDraw(function() {
|
||
|
if (flow) {
|
||
|
flow()
|
||
|
}
|
||
|
if (config.onrendered) {
|
||
|
config.onrendered.call($$)
|
||
|
}
|
||
|
})
|
||
|
} else {
|
||
|
$$.redrawBar(drawBar)
|
||
|
$$.redrawLine(drawLine)
|
||
|
$$.redrawArea(drawArea)
|
||
|
$$.redrawCircle(cx, cy)
|
||
|
$$.redrawText(xForText, yForText, options.flow)
|
||
|
$$.redrawRegion()
|
||
|
$$.redrawGrid()
|
||
|
if (flow) {
|
||
|
flow()
|
||
|
}
|
||
|
if (config.onrendered) {
|
||
|
config.onrendered.call($$)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// update fadein condition
|
||
|
$$.mapToIds($$.data.targets).forEach(function(id) {
|
||
|
$$.withoutFadeIn[id] = true
|
||
|
})
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.updateAndRedraw = function(options) {
|
||
|
var $$ = this,
|
||
|
config = $$.config,
|
||
|
transitions
|
||
|
options = options || {}
|
||
|
// same with redraw
|
||
|
options.withTransition = getOption(options, 'withTransition', true)
|
||
|
options.withTransform = getOption(options, 'withTransform', false)
|
||
|
options.withLegend = getOption(options, 'withLegend', false)
|
||
|
// NOT same with redraw
|
||
|
options.withUpdateXDomain = getOption(options, 'withUpdateXDomain', true)
|
||
|
options.withUpdateOrgXDomain = getOption(
|
||
|
options,
|
||
|
'withUpdateOrgXDomain',
|
||
|
true
|
||
|
)
|
||
|
options.withTransitionForExit = false
|
||
|
options.withTransitionForTransform = getOption(
|
||
|
options,
|
||
|
'withTransitionForTransform',
|
||
|
options.withTransition
|
||
|
)
|
||
|
// MEMO: this needs to be called before updateLegend and it means this ALWAYS needs to be called)
|
||
|
$$.updateSizes()
|
||
|
// MEMO: called in updateLegend in redraw if withLegend
|
||
|
if (!(options.withLegend && config.legend_show)) {
|
||
|
transitions = $$.axis.generateTransitions(
|
||
|
options.withTransitionForAxis ? config.transition_duration : 0
|
||
|
)
|
||
|
// Update scales
|
||
|
$$.updateScales()
|
||
|
$$.updateSvgSize()
|
||
|
// Update g positions
|
||
|
$$.transformAll(options.withTransitionForTransform, transitions)
|
||
|
}
|
||
|
// Draw with new sizes & scales
|
||
|
$$.redraw(options, transitions)
|
||
|
}
|
||
|
ChartInternal.prototype.redrawWithoutRescale = function() {
|
||
|
this.redraw({
|
||
|
withY: false,
|
||
|
withSubchart: false,
|
||
|
withEventRect: false,
|
||
|
withTransitionForAxis: false
|
||
|
})
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.isTimeSeries = function() {
|
||
|
return this.config.axis_x_type === 'timeseries'
|
||
|
}
|
||
|
ChartInternal.prototype.isCategorized = function() {
|
||
|
return this.config.axis_x_type.indexOf('categor') >= 0
|
||
|
}
|
||
|
ChartInternal.prototype.isCustomX = function() {
|
||
|
var $$ = this,
|
||
|
config = $$.config
|
||
|
return !$$.isTimeSeries() && (config.data_x || notEmpty(config.data_xs))
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.isTimeSeriesY = function() {
|
||
|
return this.config.axis_y_type === 'timeseries'
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.getTranslate = function(target) {
|
||
|
var $$ = this,
|
||
|
config = $$.config,
|
||
|
x,
|
||
|
y
|
||
|
if (target === 'main') {
|
||
|
x = asHalfPixel($$.margin.left)
|
||
|
y = asHalfPixel($$.margin.top)
|
||
|
} else if (target === 'context') {
|
||
|
x = asHalfPixel($$.margin2.left)
|
||
|
y = asHalfPixel($$.margin2.top)
|
||
|
} else if (target === 'legend') {
|
||
|
x = $$.margin3.left
|
||
|
y = $$.margin3.top
|
||
|
} else if (target === 'x') {
|
||
|
x = 0
|
||
|
y = config.axis_rotated ? 0 : $$.height
|
||
|
} else if (target === 'y') {
|
||
|
x = 0
|
||
|
y = config.axis_rotated ? $$.height : 0
|
||
|
} else if (target === 'y2') {
|
||
|
x = config.axis_rotated ? 0 : $$.width
|
||
|
y = config.axis_rotated ? 1 : 0
|
||
|
} else if (target === 'subx') {
|
||
|
x = 0
|
||
|
y = config.axis_rotated ? 0 : $$.height2
|
||
|
} else if (target === 'arc') {
|
||
|
x = $$.arcWidth / 2
|
||
|
y = $$.arcHeight / 2 - ($$.hasType('gauge') ? 6 : 0) // to prevent wrong display of min and max label
|
||
|
}
|
||
|
return 'translate(' + x + ',' + y + ')'
|
||
|
}
|
||
|
ChartInternal.prototype.initialOpacity = function(d) {
|
||
|
return d.value !== null && this.withoutFadeIn[d.id] ? 1 : 0
|
||
|
}
|
||
|
ChartInternal.prototype.initialOpacityForCircle = function(d) {
|
||
|
return d.value !== null && this.withoutFadeIn[d.id]
|
||
|
? this.opacityForCircle(d)
|
||
|
: 0
|
||
|
}
|
||
|
ChartInternal.prototype.opacityForCircle = function(d) {
|
||
|
var isPointShouldBeShown = isFunction(this.config.point_show)
|
||
|
? this.config.point_show(d)
|
||
|
: this.config.point_show
|
||
|
var opacity = isPointShouldBeShown || this.isStanfordType(d) ? 1 : 0
|
||
|
return isValue(d.value) ? (this.isScatterType(d) ? 0.5 : opacity) : 0
|
||
|
}
|
||
|
ChartInternal.prototype.opacityForText = function() {
|
||
|
return this.hasDataLabel() ? 1 : 0
|
||
|
}
|
||
|
ChartInternal.prototype.xx = function(d) {
|
||
|
return d ? this.x(d.x) : null
|
||
|
}
|
||
|
ChartInternal.prototype.xvCustom = function(d, xyValue) {
|
||
|
var $$ = this,
|
||
|
value = xyValue ? d[xyValue] : d.value
|
||
|
if ($$.isTimeSeries()) {
|
||
|
value = $$.parseDate(d.value)
|
||
|
} else if ($$.isCategorized() && typeof d.value === 'string') {
|
||
|
value = $$.config.axis_x_categories.indexOf(d.value)
|
||
|
}
|
||
|
return Math.ceil($$.x(value))
|
||
|
}
|
||
|
ChartInternal.prototype.yvCustom = function(d, xyValue) {
|
||
|
var $$ = this,
|
||
|
yScale = d.axis && d.axis === 'y2' ? $$.y2 : $$.y,
|
||
|
value = xyValue ? d[xyValue] : d.value
|
||
|
return Math.ceil(yScale(value))
|
||
|
}
|
||
|
ChartInternal.prototype.xv = function(d) {
|
||
|
var $$ = this,
|
||
|
value = d.value
|
||
|
if ($$.isTimeSeries()) {
|
||
|
value = $$.parseDate(d.value)
|
||
|
} else if ($$.isCategorized() && typeof d.value === 'string') {
|
||
|
value = $$.config.axis_x_categories.indexOf(d.value)
|
||
|
}
|
||
|
return Math.ceil($$.x(value))
|
||
|
}
|
||
|
ChartInternal.prototype.yv = function(d) {
|
||
|
var $$ = this,
|
||
|
yScale = d.axis && d.axis === 'y2' ? $$.y2 : $$.y
|
||
|
return Math.ceil(yScale(d.value))
|
||
|
}
|
||
|
ChartInternal.prototype.subxx = function(d) {
|
||
|
return d ? this.subX(d.x) : null
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.transformMain = function(withTransition, transitions) {
|
||
|
var $$ = this,
|
||
|
xAxis,
|
||
|
yAxis,
|
||
|
y2Axis
|
||
|
if (transitions && transitions.axisX) {
|
||
|
xAxis = transitions.axisX
|
||
|
} else {
|
||
|
xAxis = $$.main.select('.' + CLASS.axisX)
|
||
|
if (withTransition) {
|
||
|
xAxis = xAxis.transition()
|
||
|
}
|
||
|
}
|
||
|
if (transitions && transitions.axisY) {
|
||
|
yAxis = transitions.axisY
|
||
|
} else {
|
||
|
yAxis = $$.main.select('.' + CLASS.axisY)
|
||
|
if (withTransition) {
|
||
|
yAxis = yAxis.transition()
|
||
|
}
|
||
|
}
|
||
|
if (transitions && transitions.axisY2) {
|
||
|
y2Axis = transitions.axisY2
|
||
|
} else {
|
||
|
y2Axis = $$.main.select('.' + CLASS.axisY2)
|
||
|
if (withTransition) {
|
||
|
y2Axis = y2Axis.transition()
|
||
|
}
|
||
|
}
|
||
|
;(withTransition ? $$.main.transition() : $$.main).attr(
|
||
|
'transform',
|
||
|
$$.getTranslate('main')
|
||
|
)
|
||
|
xAxis.attr('transform', $$.getTranslate('x'))
|
||
|
yAxis.attr('transform', $$.getTranslate('y'))
|
||
|
y2Axis.attr('transform', $$.getTranslate('y2'))
|
||
|
$$.main
|
||
|
.select('.' + CLASS.chartArcs)
|
||
|
.attr('transform', $$.getTranslate('arc'))
|
||
|
}
|
||
|
ChartInternal.prototype.transformAll = function(withTransition, transitions) {
|
||
|
var $$ = this
|
||
|
$$.transformMain(withTransition, transitions)
|
||
|
if ($$.config.subchart_show) {
|
||
|
$$.transformContext(withTransition, transitions)
|
||
|
}
|
||
|
if ($$.legend) {
|
||
|
$$.transformLegend(withTransition)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.updateSvgSize = function() {
|
||
|
var $$ = this,
|
||
|
brush = $$.svg.select(`.${CLASS.brush} .overlay`)
|
||
|
$$.svg.attr('width', $$.currentWidth).attr('height', $$.currentHeight)
|
||
|
$$.svg
|
||
|
.selectAll(['#' + $$.clipId, '#' + $$.clipIdForGrid])
|
||
|
.select('rect')
|
||
|
.attr('width', $$.width)
|
||
|
.attr('height', $$.height)
|
||
|
$$.svg
|
||
|
.select('#' + $$.clipIdForXAxis)
|
||
|
.select('rect')
|
||
|
.attr('x', $$.getXAxisClipX.bind($$))
|
||
|
.attr('y', $$.getXAxisClipY.bind($$))
|
||
|
.attr('width', $$.getXAxisClipWidth.bind($$))
|
||
|
.attr('height', $$.getXAxisClipHeight.bind($$))
|
||
|
$$.svg
|
||
|
.select('#' + $$.clipIdForYAxis)
|
||
|
.select('rect')
|
||
|
.attr('x', $$.getYAxisClipX.bind($$))
|
||
|
.attr('y', $$.getYAxisClipY.bind($$))
|
||
|
.attr('width', $$.getYAxisClipWidth.bind($$))
|
||
|
.attr('height', $$.getYAxisClipHeight.bind($$))
|
||
|
$$.svg
|
||
|
.select('#' + $$.clipIdForSubchart)
|
||
|
.select('rect')
|
||
|
.attr('width', $$.width)
|
||
|
.attr('height', (brush.size() && brush.attr('height')) || 0)
|
||
|
// MEMO: parent div's height will be bigger than svg when <!DOCTYPE html>
|
||
|
$$.selectChart.style('max-height', $$.currentHeight + 'px')
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.updateDimension = function(withoutAxis) {
|
||
|
var $$ = this
|
||
|
if (!withoutAxis) {
|
||
|
if ($$.config.axis_rotated) {
|
||
|
$$.axes.x.call($$.xAxis)
|
||
|
$$.axes.subx.call($$.subXAxis)
|
||
|
} else {
|
||
|
$$.axes.y.call($$.yAxis)
|
||
|
$$.axes.y2.call($$.y2Axis)
|
||
|
}
|
||
|
}
|
||
|
$$.updateSizes()
|
||
|
$$.updateScales()
|
||
|
$$.updateSvgSize()
|
||
|
$$.transformAll(false)
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.observeInserted = function(selection) {
|
||
|
var $$ = this,
|
||
|
observer
|
||
|
if (typeof MutationObserver === 'undefined') {
|
||
|
window.console.error('MutationObserver not defined.')
|
||
|
return
|
||
|
}
|
||
|
observer = new MutationObserver(function(mutations) {
|
||
|
mutations.forEach(function(mutation) {
|
||
|
if (mutation.type === 'childList' && mutation.previousSibling) {
|
||
|
observer.disconnect()
|
||
|
// need to wait for completion of load because size calculation requires the actual sizes determined after that completion
|
||
|
$$.intervalForObserveInserted = window.setInterval(function() {
|
||
|
// parentNode will NOT be null when completed
|
||
|
if (selection.node().parentNode) {
|
||
|
window.clearInterval($$.intervalForObserveInserted)
|
||
|
$$.updateDimension()
|
||
|
if ($$.brush) {
|
||
|
$$.brush.update()
|
||
|
}
|
||
|
$$.config.oninit.call($$)
|
||
|
$$.redraw({
|
||
|
withTransform: true,
|
||
|
withUpdateXDomain: true,
|
||
|
withUpdateOrgXDomain: true,
|
||
|
withTransition: false,
|
||
|
withTransitionForTransform: false,
|
||
|
withLegend: true
|
||
|
})
|
||
|
selection.transition().style('opacity', 1)
|
||
|
}
|
||
|
}, 10)
|
||
|
}
|
||
|
})
|
||
|
})
|
||
|
observer.observe(selection.node(), {
|
||
|
attributes: true,
|
||
|
childList: true,
|
||
|
characterData: true
|
||
|
})
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Binds handlers to the window resize event.
|
||
|
*/
|
||
|
ChartInternal.prototype.bindResize = function() {
|
||
|
var $$ = this,
|
||
|
config = $$.config
|
||
|
|
||
|
$$.resizeFunction = $$.generateResize() // need to call .remove
|
||
|
|
||
|
$$.resizeFunction.add(function() {
|
||
|
config.onresize.call($$)
|
||
|
})
|
||
|
if (config.resize_auto) {
|
||
|
$$.resizeFunction.add(function() {
|
||
|
if ($$.resizeTimeout !== undefined) {
|
||
|
window.clearTimeout($$.resizeTimeout)
|
||
|
}
|
||
|
$$.resizeTimeout = window.setTimeout(function() {
|
||
|
delete $$.resizeTimeout
|
||
|
$$.updateAndRedraw({
|
||
|
withUpdateXDomain: false,
|
||
|
withUpdateOrgXDomain: false,
|
||
|
withTransition: false,
|
||
|
withTransitionForTransform: false,
|
||
|
withLegend: true
|
||
|
})
|
||
|
if ($$.brush) {
|
||
|
$$.brush.update()
|
||
|
}
|
||
|
}, 100)
|
||
|
})
|
||
|
}
|
||
|
$$.resizeFunction.add(function() {
|
||
|
config.onresized.call($$)
|
||
|
})
|
||
|
|
||
|
$$.resizeIfElementDisplayed = function() {
|
||
|
// if element not displayed skip it
|
||
|
if ($$.api == null || !$$.api.element.offsetParent) {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
$$.resizeFunction()
|
||
|
}
|
||
|
|
||
|
window.addEventListener('resize', $$.resizeIfElementDisplayed, false)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Binds handlers to the window focus event.
|
||
|
*/
|
||
|
ChartInternal.prototype.bindWindowFocus = function() {
|
||
|
if (this.windowFocusHandler) {
|
||
|
// The handler is already set
|
||
|
return
|
||
|
}
|
||
|
|
||
|
this.windowFocusHandler = () => {
|
||
|
this.redraw()
|
||
|
}
|
||
|
|
||
|
window.addEventListener('focus', this.windowFocusHandler)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Unbinds from the window focus event.
|
||
|
*/
|
||
|
ChartInternal.prototype.unbindWindowFocus = function() {
|
||
|
window.removeEventListener('focus', this.windowFocusHandler)
|
||
|
delete this.windowFocusHandler
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.generateResize = function() {
|
||
|
var resizeFunctions = []
|
||
|
|
||
|
function callResizeFunctions() {
|
||
|
resizeFunctions.forEach(function(f) {
|
||
|
f()
|
||
|
})
|
||
|
}
|
||
|
callResizeFunctions.add = function(f) {
|
||
|
resizeFunctions.push(f)
|
||
|
}
|
||
|
callResizeFunctions.remove = function(f) {
|
||
|
for (var i = 0; i < resizeFunctions.length; i++) {
|
||
|
if (resizeFunctions[i] === f) {
|
||
|
resizeFunctions.splice(i, 1)
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return callResizeFunctions
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.endall = function(transition, callback) {
|
||
|
var n = 0
|
||
|
transition
|
||
|
.each(function() {
|
||
|
++n
|
||
|
})
|
||
|
.on('end', function() {
|
||
|
if (!--n) {
|
||
|
callback.apply(this, arguments)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
ChartInternal.prototype.generateWait = function() {
|
||
|
var $$ = this
|
||
|
var transitionsToWait = [],
|
||
|
f = function(callback) {
|
||
|
var timer = setInterval(function() {
|
||
|
if (!$$.isTabVisible()) {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var done = 0
|
||
|
transitionsToWait.forEach(function(t) {
|
||
|
if (t.empty()) {
|
||
|
done += 1
|
||
|
return
|
||
|
}
|
||
|
try {
|
||
|
t.transition()
|
||
|
} catch (e) {
|
||
|
done += 1
|
||
|
}
|
||
|
})
|
||
|
if (done === transitionsToWait.length) {
|
||
|
clearInterval(timer)
|
||
|
if (callback) {
|
||
|
callback()
|
||
|
}
|
||
|
}
|
||
|
}, 50)
|
||
|
}
|
||
|
;(f as any).add = function(transition) {
|
||
|
transitionsToWait.push(transition)
|
||
|
}
|
||
|
return f
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.parseDate = function(date) {
|
||
|
var $$ = this,
|
||
|
parsedDate
|
||
|
if (date instanceof Date) {
|
||
|
parsedDate = date
|
||
|
} else if (typeof date === 'string') {
|
||
|
parsedDate = $$.dataTimeParse(date)
|
||
|
} else if (typeof date === 'object') {
|
||
|
parsedDate = new Date(+date)
|
||
|
} else if (typeof date === 'number' && !isNaN(date)) {
|
||
|
parsedDate = new Date(+date)
|
||
|
}
|
||
|
if (!parsedDate || isNaN(+parsedDate)) {
|
||
|
window.console.error("Failed to parse x '" + date + "' to Date object")
|
||
|
}
|
||
|
return parsedDate
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.isTabVisible = function() {
|
||
|
return !document.hidden
|
||
|
}
|
||
|
|
||
|
ChartInternal.prototype.getPathBox = getPathBox
|
||
|
ChartInternal.prototype.CLASS = CLASS
|
||
|
|
||
|
export { Chart }
|
||
|
export { ChartInternal }
|