| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592 |
- import CLASS from './class'
- import { ChartInternal } from './core'
- import { isValue, isFunction, isUndefined, isDefined } from './util'
- ChartInternal.prototype.initLine = function() {
- var $$ = this
- $$.main
- .select('.' + CLASS.chart)
- .append('g')
- .attr('class', CLASS.chartLines)
- }
- ChartInternal.prototype.updateTargetsForLine = function(targets) {
- var $$ = this,
- config = $$.config,
- mainLines,
- mainLineEnter,
- classChartLine = $$.classChartLine.bind($$),
- classLines = $$.classLines.bind($$),
- classAreas = $$.classAreas.bind($$),
- classCircles = $$.classCircles.bind($$),
- classFocus = $$.classFocus.bind($$)
- mainLines = $$.main
- .select('.' + CLASS.chartLines)
- .selectAll('.' + CLASS.chartLine)
- .data(targets)
- .attr('class', function(d) {
- return classChartLine(d) + classFocus(d)
- })
- mainLineEnter = mainLines
- .enter()
- .append('g')
- .attr('class', classChartLine)
- .style('opacity', 0)
- .style('pointer-events', 'none')
- // Lines for each data
- mainLineEnter.append('g').attr('class', classLines)
- // Areas
- mainLineEnter.append('g').attr('class', classAreas)
- // Circles for each data point on lines
- mainLineEnter.append('g').attr('class', function(d) {
- return $$.generateClass(CLASS.selectedCircles, d.id)
- })
- mainLineEnter
- .append('g')
- .attr('class', classCircles)
- .style('cursor', function(d) {
- return config.data_selection_isselectable(d) ? 'pointer' : null
- })
- // Update date for selected circles
- targets.forEach(function(t) {
- $$.main
- .selectAll('.' + CLASS.selectedCircles + $$.getTargetSelectorSuffix(t.id))
- .selectAll('.' + CLASS.selectedCircle)
- .each(function(d) {
- d.value = t.values[d.index].value
- })
- })
- // MEMO: can not keep same color...
- //mainLineUpdate.exit().remove();
- }
- ChartInternal.prototype.updateLine = function(durationForExit) {
- var $$ = this
- var mainLine = $$.main
- .selectAll('.' + CLASS.lines)
- .selectAll('.' + CLASS.line)
- .data($$.lineData.bind($$))
- var mainLineEnter = mainLine
- .enter()
- .append('path')
- .attr('class', $$.classLine.bind($$))
- .style('stroke', $$.color)
- $$.mainLine = mainLineEnter
- .merge(mainLine)
- .style('opacity', $$.initialOpacity.bind($$))
- .style('shape-rendering', function(d) {
- return $$.isStepType(d) ? 'crispEdges' : ''
- })
- .attr('transform', null)
- mainLine
- .exit()
- .transition()
- .duration(durationForExit)
- .style('opacity', 0)
- }
- ChartInternal.prototype.redrawLine = function(
- drawLine,
- withTransition,
- transition
- ) {
- return [
- (withTransition ? this.mainLine.transition(transition) : this.mainLine)
- .attr('d', drawLine)
- .style('stroke', this.color)
- .style('opacity', 1)
- ]
- }
- ChartInternal.prototype.generateDrawLine = function(lineIndices, isSub) {
- var $$ = this,
- config = $$.config,
- line = $$.d3.line(),
- getPoints = $$.generateGetLinePoints(lineIndices, isSub),
- yScaleGetter = isSub ? $$.getSubYScale : $$.getYScale,
- xValue = function(d) {
- return (isSub ? $$.subxx : $$.xx).call($$, d)
- },
- yValue = function(d, i) {
- return config.data_groups.length > 0
- ? getPoints(d, i)[0][1]
- : yScaleGetter.call($$, d.id)(d.value)
- }
- line = config.axis_rotated
- ? line.x(yValue).y(xValue)
- : line.x(xValue).y(yValue)
- if (!config.line_connectNull) {
- line = line.defined(function(d) {
- return d.value != null
- })
- }
- return function(d) {
- var values = config.line_connectNull
- ? $$.filterRemoveNull(d.values)
- : d.values,
- x = isSub ? $$.subX : $$.x,
- y = yScaleGetter.call($$, d.id),
- x0 = 0,
- y0 = 0,
- path
- if ($$.isLineType(d)) {
- if (config.data_regions[d.id]) {
- path = $$.lineWithRegions(values, x, y, config.data_regions[d.id])
- } else {
- if ($$.isStepType(d)) {
- values = $$.convertValuesToStep(values)
- }
- path = line.curve($$.getInterpolate(d))(values)
- }
- } else {
- if (values[0]) {
- x0 = x(values[0].x)
- y0 = y(values[0].value)
- }
- path = config.axis_rotated ? 'M ' + y0 + ' ' + x0 : 'M ' + x0 + ' ' + y0
- }
- return path ? path : 'M 0 0'
- }
- }
- ChartInternal.prototype.generateGetLinePoints = function(lineIndices, isSub) {
- // partial duplication of generateGetBarPoints
- var $$ = this,
- config = $$.config,
- lineTargetsNum = lineIndices.__max__ + 1,
- x = $$.getShapeX(0, lineTargetsNum, lineIndices, !!isSub),
- y = $$.getShapeY(!!isSub),
- lineOffset = $$.getShapeOffset($$.isLineType, lineIndices, !!isSub),
- yScale = isSub ? $$.getSubYScale : $$.getYScale
- return function(d, i) {
- var y0 = yScale.call($$, d.id)(0),
- offset = lineOffset(d, i) || y0, // offset is for stacked area chart
- posX = x(d),
- posY = y(d)
- // fix posY not to overflow opposite quadrant
- if (config.axis_rotated) {
- if ((0 < d.value && posY < y0) || (d.value < 0 && y0 < posY)) {
- posY = y0
- }
- }
- // 1 point that marks the line position
- return [
- [posX, posY - (y0 - offset)],
- [posX, posY - (y0 - offset)], // needed for compatibility
- [posX, posY - (y0 - offset)], // needed for compatibility
- [posX, posY - (y0 - offset)] // needed for compatibility
- ]
- }
- }
- ChartInternal.prototype.lineWithRegions = function(d, x, y, _regions) {
- var $$ = this,
- config = $$.config,
- prev = -1,
- i,
- j,
- s = 'M',
- sWithRegion,
- xp,
- yp,
- dx,
- dy,
- dd,
- diff,
- diffx2,
- xOffset = $$.isCategorized() ? 0.5 : 0,
- xValue,
- yValue,
- regions = []
- function isWithinRegions(x, regions) {
- var i
- for (i = 0; i < regions.length; i++) {
- if (regions[i].start < x && x <= regions[i].end) {
- return true
- }
- }
- return false
- }
- // Check start/end of regions
- if (isDefined(_regions)) {
- for (i = 0; i < _regions.length; i++) {
- regions[i] = {}
- if (isUndefined(_regions[i].start)) {
- regions[i].start = d[0].x
- } else {
- regions[i].start = $$.isTimeSeries()
- ? $$.parseDate(_regions[i].start)
- : _regions[i].start
- }
- if (isUndefined(_regions[i].end)) {
- regions[i].end = d[d.length - 1].x
- } else {
- regions[i].end = $$.isTimeSeries()
- ? $$.parseDate(_regions[i].end)
- : _regions[i].end
- }
- }
- }
- // Set scales
- xValue = config.axis_rotated
- ? function(d) {
- return y(d.value)
- }
- : function(d) {
- return x(d.x)
- }
- yValue = config.axis_rotated
- ? function(d) {
- return x(d.x)
- }
- : function(d) {
- return y(d.value)
- }
- // Define svg generator function for region
- function generateM(points) {
- return (
- 'M' +
- points[0][0] +
- ' ' +
- points[0][1] +
- ' ' +
- points[1][0] +
- ' ' +
- points[1][1]
- )
- }
- if ($$.isTimeSeries()) {
- sWithRegion = function(d0, d1, j, diff) {
- var x0 = d0.x.getTime(),
- x_diff = d1.x - d0.x,
- xv0 = new Date(x0 + x_diff * j),
- xv1 = new Date(x0 + x_diff * (j + diff)),
- points
- if (config.axis_rotated) {
- points = [
- [y(yp(j)), x(xv0)],
- [y(yp(j + diff)), x(xv1)]
- ]
- } else {
- points = [
- [x(xv0), y(yp(j))],
- [x(xv1), y(yp(j + diff))]
- ]
- }
- return generateM(points)
- }
- } else {
- sWithRegion = function(d0, d1, j, diff) {
- var points
- if (config.axis_rotated) {
- points = [
- [y(yp(j), true), x(xp(j))],
- [y(yp(j + diff), true), x(xp(j + diff))]
- ]
- } else {
- points = [
- [x(xp(j), true), y(yp(j))],
- [x(xp(j + diff), true), y(yp(j + diff))]
- ]
- }
- return generateM(points)
- }
- }
- // Generate
- for (i = 0; i < d.length; i++) {
- // Draw as normal
- if (isUndefined(regions) || !isWithinRegions(d[i].x, regions)) {
- s += ' ' + xValue(d[i]) + ' ' + yValue(d[i])
- }
- // Draw with region // TODO: Fix for horizotal charts
- else {
- xp = $$.getScale(
- d[i - 1].x + xOffset,
- d[i].x + xOffset,
- $$.isTimeSeries()
- )
- yp = $$.getScale(d[i - 1].value, d[i].value)
- dx = x(d[i].x) - x(d[i - 1].x)
- dy = y(d[i].value) - y(d[i - 1].value)
- dd = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2))
- diff = 2 / dd
- diffx2 = diff * 2
- for (j = diff; j <= 1; j += diffx2) {
- s += sWithRegion(d[i - 1], d[i], j, diff)
- }
- }
- prev = d[i].x
- }
- return s
- }
- ChartInternal.prototype.updateArea = function(durationForExit) {
- var $$ = this,
- d3 = $$.d3
- var mainArea = $$.main
- .selectAll('.' + CLASS.areas)
- .selectAll('.' + CLASS.area)
- .data($$.lineData.bind($$))
- var mainAreaEnter = mainArea
- .enter()
- .append('path')
- .attr('class', $$.classArea.bind($$))
- .style('fill', $$.color)
- .style('opacity', function() {
- $$.orgAreaOpacity = +d3.select(this).style('opacity')
- return 0
- })
- $$.mainArea = mainAreaEnter
- .merge(mainArea)
- .style('opacity', $$.orgAreaOpacity)
- mainArea
- .exit()
- .transition()
- .duration(durationForExit)
- .style('opacity', 0)
- }
- ChartInternal.prototype.redrawArea = function(
- drawArea,
- withTransition,
- transition
- ) {
- return [
- (withTransition ? this.mainArea.transition(transition) : this.mainArea)
- .attr('d', drawArea)
- .style('fill', this.color)
- .style('opacity', this.orgAreaOpacity)
- ]
- }
- ChartInternal.prototype.generateDrawArea = function(areaIndices, isSub) {
- var $$ = this,
- config = $$.config,
- area = $$.d3.area(),
- getPoints = $$.generateGetAreaPoints(areaIndices, isSub),
- yScaleGetter = isSub ? $$.getSubYScale : $$.getYScale,
- xValue = function(d) {
- return (isSub ? $$.subxx : $$.xx).call($$, d)
- },
- value0 = function(d, i) {
- return config.data_groups.length > 0
- ? getPoints(d, i)[0][1]
- : yScaleGetter.call($$, d.id)($$.getAreaBaseValue(d.id))
- },
- value1 = function(d, i) {
- return config.data_groups.length > 0
- ? getPoints(d, i)[1][1]
- : yScaleGetter.call($$, d.id)(d.value)
- }
- area = config.axis_rotated
- ? area
- .x0(value0)
- .x1(value1)
- .y(xValue)
- : area
- .x(xValue)
- .y0(config.area_above ? 0 : value0)
- .y1(value1)
- if (!config.line_connectNull) {
- area = area.defined(function(d) {
- return d.value !== null
- })
- }
- return function(d) {
- var values = config.line_connectNull
- ? $$.filterRemoveNull(d.values)
- : d.values,
- x0 = 0,
- y0 = 0,
- path
- if ($$.isAreaType(d)) {
- if ($$.isStepType(d)) {
- values = $$.convertValuesToStep(values)
- }
- path = area.curve($$.getInterpolate(d))(values)
- } else {
- if (values[0]) {
- x0 = $$.x(values[0].x)
- y0 = $$.getYScale(d.id)(values[0].value)
- }
- path = config.axis_rotated ? 'M ' + y0 + ' ' + x0 : 'M ' + x0 + ' ' + y0
- }
- return path ? path : 'M 0 0'
- }
- }
- ChartInternal.prototype.getAreaBaseValue = function() {
- return 0
- }
- ChartInternal.prototype.generateGetAreaPoints = function(areaIndices, isSub) {
- // partial duplication of generateGetBarPoints
- var $$ = this,
- config = $$.config,
- areaTargetsNum = areaIndices.__max__ + 1,
- x = $$.getShapeX(0, areaTargetsNum, areaIndices, !!isSub),
- y = $$.getShapeY(!!isSub),
- areaOffset = $$.getShapeOffset($$.isAreaType, areaIndices, !!isSub),
- yScale = isSub ? $$.getSubYScale : $$.getYScale
- return function(d, i) {
- var y0 = yScale.call($$, d.id)(0),
- offset = areaOffset(d, i) || y0, // offset is for stacked area chart
- posX = x(d),
- posY = y(d)
- // fix posY not to overflow opposite quadrant
- if (config.axis_rotated) {
- if ((0 < d.value && posY < y0) || (d.value < 0 && y0 < posY)) {
- posY = y0
- }
- }
- // 1 point that marks the area position
- return [
- [posX, offset],
- [posX, posY - (y0 - offset)],
- [posX, posY - (y0 - offset)], // needed for compatibility
- [posX, offset] // needed for compatibility
- ]
- }
- }
- ChartInternal.prototype.updateCircle = function(cx, cy) {
- var $$ = this
- var mainCircle = $$.main
- .selectAll('.' + CLASS.circles)
- .selectAll('.' + CLASS.circle)
- .data($$.lineOrScatterOrStanfordData.bind($$))
- var mainCircleEnter = mainCircle
- .enter()
- .append('circle')
- .attr('shape-rendering', $$.isStanfordGraphType() ? 'crispEdges' : '')
- .attr('class', $$.classCircle.bind($$))
- .attr('cx', cx)
- .attr('cy', cy)
- .attr('r', $$.pointR.bind($$))
- .style(
- 'color',
- $$.isStanfordGraphType() ? $$.getStanfordPointColor.bind($$) : $$.color
- )
- $$.mainCircle = mainCircleEnter
- .merge(mainCircle)
- .style(
- 'opacity',
- $$.isStanfordGraphType() ? 1 : $$.initialOpacityForCircle.bind($$)
- )
- mainCircle.exit().style('opacity', 0)
- }
- ChartInternal.prototype.redrawCircle = function(
- cx,
- cy,
- withTransition,
- transition
- ) {
- var $$ = this,
- selectedCircles = $$.main.selectAll('.' + CLASS.selectedCircle)
- return [
- (withTransition ? $$.mainCircle.transition(transition) : $$.mainCircle)
- .style('opacity', this.opacityForCircle.bind($$))
- .style(
- 'color',
- $$.isStanfordGraphType() ? $$.getStanfordPointColor.bind($$) : $$.color
- )
- .attr('cx', cx)
- .attr('cy', cy),
- (withTransition ? selectedCircles.transition(transition) : selectedCircles)
- .attr('cx', cx)
- .attr('cy', cy)
- ]
- }
- ChartInternal.prototype.circleX = function(d) {
- return d.x || d.x === 0 ? this.x(d.x) : null
- }
- ChartInternal.prototype.updateCircleY = function() {
- var $$ = this,
- lineIndices,
- getPoints
- if ($$.config.data_groups.length > 0) {
- ;(lineIndices = $$.getShapeIndices($$.isLineType)),
- (getPoints = $$.generateGetLinePoints(lineIndices))
- $$.circleY = function(d, i) {
- return getPoints(d, i)[0][1]
- }
- } else {
- $$.circleY = function(d) {
- return $$.getYScale(d.id)(d.value)
- }
- }
- }
- ChartInternal.prototype.getCircles = function(i, id) {
- var $$ = this
- return (id
- ? $$.main.selectAll('.' + CLASS.circles + $$.getTargetSelectorSuffix(id))
- : $$.main
- ).selectAll('.' + CLASS.circle + (isValue(i) ? '-' + i : ''))
- }
- ChartInternal.prototype.expandCircles = function(i, id, reset) {
- var $$ = this,
- r = $$.pointExpandedR.bind($$)
- if (reset) {
- $$.unexpandCircles()
- }
- $$.getCircles(i, id)
- .classed(CLASS.EXPANDED, true)
- .attr('r', r)
- }
- ChartInternal.prototype.unexpandCircles = function(i) {
- var $$ = this,
- r = $$.pointR.bind($$)
- $$.getCircles(i)
- .filter(function() {
- return $$.d3.select(this).classed(CLASS.EXPANDED)
- })
- .classed(CLASS.EXPANDED, false)
- .attr('r', r)
- }
- ChartInternal.prototype.pointR = function(d) {
- var $$ = this,
- config = $$.config
- return $$.isStepType(d)
- ? 0
- : isFunction(config.point_r)
- ? config.point_r(d)
- : config.point_r
- }
- ChartInternal.prototype.pointExpandedR = function(d) {
- var $$ = this,
- config = $$.config
- if (config.point_focus_expand_enabled) {
- return isFunction(config.point_focus_expand_r)
- ? config.point_focus_expand_r(d)
- : config.point_focus_expand_r
- ? config.point_focus_expand_r
- : $$.pointR(d) * 1.75
- } else {
- return $$.pointR(d)
- }
- }
- ChartInternal.prototype.pointSelectR = function(d) {
- var $$ = this,
- config = $$.config
- return isFunction(config.point_select_r)
- ? config.point_select_r(d)
- : config.point_select_r
- ? config.point_select_r
- : $$.pointR(d) * 4
- }
- ChartInternal.prototype.isWithinCircle = function(that, r) {
- var d3 = this.d3,
- mouse = d3.mouse(that),
- d3_this = d3.select(that),
- cx = +d3_this.attr('cx'),
- cy = +d3_this.attr('cy')
- return Math.sqrt(Math.pow(cx - mouse[0], 2) + Math.pow(cy - mouse[1], 2)) < r
- }
- ChartInternal.prototype.isWithinStep = function(that, y) {
- return Math.abs(y - this.d3.mouse(that)[1]) < 30
- }
|