@websy/websy-designs 1.4.33 → 1.4.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6570,6 +6570,10 @@ class WebsyTable3 {
6570
6570
  headEl.style.width = 'initial'
6571
6571
  bodyEl.style.width = 'initial'
6572
6572
  this.sizes.bodyHeight = this.sizes.table.height - (this.sizes.header.height + this.sizes.total.height)
6573
+ if (this.options.maxHeight) {
6574
+ let requiredHeight = ((this.totalRowCount || 9) + 1) * this.sizes.cellHeight
6575
+ this.sizes.bodyHeight = Math.min(requiredHeight, this.options.maxHeight - (this.sizes.header.height + this.sizes.total.height))
6576
+ }
6573
6577
  this.sizes.rowsToRender = Math.ceil(this.sizes.bodyHeight / this.sizes.cellHeight)
6574
6578
  this.sizes.rowsToRenderPrecise = this.sizes.bodyHeight / this.sizes.cellHeight
6575
6579
  this.startRow = 0
@@ -6756,7 +6760,13 @@ class WebsyTable3 {
6756
6760
  }
6757
6761
  let bodyEl = document.getElementById(`${this.elementId}_tableBody`)
6758
6762
  // bodyEl.innerHTML = this.buildBodyHtml(data, true)
6759
- bodyEl.style.height = `calc(100% - ${this.sizes.header.height}px - ${this.sizes.total.height}px)`
6763
+ // if (this.options.maxHeight) {
6764
+ // bodyEl.style.height = `${this.options.maxHeight - this.sizes.header.height - this.sizes.total.height}px`
6765
+ // }
6766
+ // else {
6767
+ // bodyEl.style.height = `calc(100% - ${this.sizes.header.height}px - ${this.sizes.total.height}px)`
6768
+ // }
6769
+ bodyEl.style.height = `${this.sizes.bodyHeight}px`
6760
6770
  if (this.options.virtualScroll === true) {
6761
6771
  // set the scroll element positions
6762
6772
  let vScrollEl = document.getElementById(`${this.elementId}_vScrollContainer`)
@@ -6954,7 +6964,9 @@ class WebsyChart {
6954
6964
  showTooltip: true,
6955
6965
  showLegend: false,
6956
6966
  legendPosition: 'bottom',
6957
- tooltipWidth: 200
6967
+ tooltipWidth: 200,
6968
+ brushHeight: 50,
6969
+ minBandWidth: 30
6958
6970
  }
6959
6971
  this.elementId = elementId
6960
6972
  this.options = Object.assign({}, DEFAULTS, options)
@@ -6963,15 +6975,22 @@ class WebsyChart {
6963
6975
  this.topAxis = null
6964
6976
  this.bottomAxis = null
6965
6977
  this.renderedKeys = {}
6978
+ this.brushedDomain = []
6979
+ this.brushBarsInitialized = {}
6980
+ this.brushLinesInitialized = {}
6966
6981
  if (!elementId) {
6967
6982
  console.log('No element Id provided for Websy Chart')
6968
6983
  return
6969
6984
  }
6970
- this.invertOverride = (input, input2) => {
6971
- let xAxis = 'bottomAxis'
6985
+ this.invertOverride = (input, input2, forBrush = false) => {
6986
+ let xAxis = 'bottom'
6972
6987
  if (this.options.orientation === 'horizontal') {
6973
- xAxis = 'leftAxis'
6988
+ xAxis = 'left'
6989
+ }
6990
+ if (forBrush === true) {
6991
+ xAxis += 'Brush'
6974
6992
  }
6993
+ xAxis += 'Axis'
6975
6994
  let width = this[xAxis].step()
6976
6995
  let output
6977
6996
  let domain = [...this[xAxis].domain()]
@@ -6987,6 +7006,65 @@ class WebsyChart {
6987
7006
  }
6988
7007
  }
6989
7008
  return output
7009
+ }
7010
+ let that = this
7011
+ this.brushed = function (event) {
7012
+ console.log('brushing', event)
7013
+ that.brushedDomain = []
7014
+ let xAxis = 'bottom'
7015
+ let xAxisCaps = 'Bottom'
7016
+ if (that.options.orientation === 'horizontal') {
7017
+ xAxis = 'left'
7018
+ xAxisCaps = 'Left'
7019
+ }
7020
+ if (!that[`${xAxis}Axis`].invert) {
7021
+ that[`${xAxis}Axis`].invert = that.invertOverride
7022
+ }
7023
+ let s = event.selection || that[`${xAxis}Axis`].range()
7024
+ if (!event.selection || event.selection.length === 0) {
7025
+ that.brushLayer
7026
+ .select('.brush')
7027
+ .call(that.brush)
7028
+ .call(that.brush.move, s)
7029
+ return
7030
+ }
7031
+ if (that.options.data[xAxis].scale && that.options.data[xAxis].scale === 'Time') {
7032
+ that.brushedDomain = s.map(that[`${xAxis}BrushAxis`].invert, that[[`${xAxis}Axis`]])
7033
+ }
7034
+ else {
7035
+ let startEndOrdinal = s.map((a, b) => that.bottomAxis.invert(a, b, true), that.bottomBrushAxis)
7036
+ if (
7037
+ startEndOrdinal &&
7038
+ startEndOrdinal.length === 2 &&
7039
+ typeof startEndOrdinal[0] !== 'undefined' &&
7040
+ typeof startEndOrdinal[1] !== 'undefined'
7041
+ ) {
7042
+ let domain = []
7043
+ let domainValues = [...that[`${xAxis}BrushAxis`].domain()]
7044
+ for (let i = startEndOrdinal[0]; i < startEndOrdinal[1] + 1; i++) {
7045
+ // domain.push(that.xRange[i])
7046
+ that.brushedDomain.push(domainValues[i])
7047
+ }
7048
+ }
7049
+ }
7050
+ if (that.brushedDomain.length > 0) {
7051
+ that[`${xAxis}Axis`].domain(that.brushedDomain)
7052
+ that[`${xAxis}AxisLayer`].call(
7053
+ d3[`axis${xAxisCaps}`](that[`${xAxis}Axis`])
7054
+ )
7055
+ }
7056
+ if (that.leftAxis && that.bottomAxis) {
7057
+ that.renderComponents()
7058
+ if (that.options.orientation === 'vertical') {
7059
+ // that.bottomAxisLayer.call(that.bAxisFunc)
7060
+ if (that.options.data.bottom.rotate) {
7061
+ that.bottomAxisLayer.selectAll('text')
7062
+ .attr('transform', `rotate(${((that.options.data.bottom && that.options.data.bottom.rotate) || 0)})`)
7063
+ .style('text-anchor', `${((that.options.data.bottom && that.options.data.bottom.rotate) || 0) === 0 ? 'middle' : 'end'}`)
7064
+ .style('transform-origin', ((that.options.data.bottom && that.options.data.bottom.rotate) || 0) === 0 ? '0 0' : `0 ${((that.options.data.bottom && that.options.data.bottom.fontSize) || that.options.fontSize)}px`)
7065
+ }
7066
+ }
7067
+ }
6990
7068
  }
6991
7069
  const el = document.getElementById(this.elementId)
6992
7070
  if (el) {
@@ -6996,12 +7074,20 @@ class WebsyChart {
6996
7074
  }
6997
7075
  else {
6998
7076
  el.innerHTML = ''
6999
- this.svg = d3.select(el).append('svg')
7077
+ this.svg = d3.select(el).append('svg') // .attr('id', `${this.elementId}_chartContainer`)
7000
7078
  this.legendArea = d3.select(el).append('div')
7001
7079
  .attr('id', `${this.elementId}_legend`)
7002
7080
  .attr('class', 'websy-chart-legend')
7003
7081
  this.legend = new WebsyDesigns.Legend(`${this.elementId}_legend`, {})
7004
7082
  this.prep()
7083
+ // el.innerHTML += `
7084
+ // <div id="${this.elementId}_errorContainer" class='websy-vis-error-container'>
7085
+ // <div>
7086
+ // <div id="${this.elementId}_errorTitle"></div>
7087
+ // <div id="${this.elementId}_errorMessage"></div>
7088
+ // </div>
7089
+ // </div>
7090
+ // `
7005
7091
  }
7006
7092
  }
7007
7093
  else {
@@ -7026,25 +7112,36 @@ class WebsyChart {
7026
7112
  this.labelLayer.selectAll('*').remove()
7027
7113
  this.symbolLayer.selectAll('*').remove()
7028
7114
  }
7029
- createDomain (side) {
7115
+ createDomain (side, forBrush = false) {
7030
7116
  let domain = []
7031
- /* global d3 side domain:writable */
7032
- if (typeof this.options.data[side].min !== 'undefined' && typeof this.options.data[side].max !== 'undefined') {
7033
- // domain = [this.options.data[side].min - (this.options.data[side].min * 0.1), this.options.data[side].max * 1.1]
7034
- domain = [this.options.data[side].min, this.options.data[side].max]
7035
- if (this.options.forceZero === true) {
7036
- domain = [Math.min(0, this.options.data[side].min), this.options.data[side].max]
7037
- }
7117
+ /* global d3 side domain:writable forBrush */
7118
+ // if we have a brushed domain we use that
7119
+ let xAxis = 'bottom'
7120
+ if (this.options.orientation === 'horizontal') {
7121
+ xAxis = 'left'
7038
7122
  }
7039
- if (this.options.data[side].data) {
7040
- domain = this.options.data[side].data.map(d => d.value)
7123
+ if (this.brushedDomain.length > 0 && side === xAxis && forBrush === false) {
7124
+ domain = [...this.brushedDomain]
7041
7125
  }
7042
- if (this.options.data[side].scale === 'Time') {
7043
- let min = this.options.data[side].data[0].value
7044
- let max = this.options.data[side].data[this.options.data[side].data.length - 1].value
7045
- min = this.parseX(min)
7046
- max = this.parseX(max)
7047
- domain = [min, max]
7126
+ else {
7127
+ // otherwise we create the domain
7128
+ if (typeof this.options.data[side].min !== 'undefined' && typeof this.options.data[side].max !== 'undefined') {
7129
+ // domain = [this.options.data[side].min - (this.options.data[side].min * 0.1), this.options.data[side].max * 1.1]
7130
+ domain = [this.options.data[side].min, this.options.data[side].max]
7131
+ if (this.options.forceZero === true) {
7132
+ domain = [Math.min(0, this.options.data[side].min), this.options.data[side].max]
7133
+ }
7134
+ }
7135
+ if (this.options.data[side].data) {
7136
+ domain = this.options.data[side].data.map(d => d.value)
7137
+ }
7138
+ if (this.options.data[side].scale === 'Time') {
7139
+ let min = this.options.data[side].data[0].value
7140
+ let max = this.options.data[side].data[this.options.data[side].data.length - 1].value
7141
+ min = this.parseX(min)
7142
+ max = this.parseX(max)
7143
+ domain = [min, max]
7144
+ }
7048
7145
  }
7049
7146
 
7050
7147
  return domain
@@ -7175,7 +7272,7 @@ if (this.options.data[side].scale === 'Time') {
7175
7272
  tooltipHTML += tooltipData.map(d => `
7176
7273
  <li>
7177
7274
  <i style='background-color: ${d.color};'></i>
7178
- ${d.tooltipLabel || ''}<span> - ${d.tooltipValue || d.value}</span>
7275
+ ${d.tooltipLabel || ''}<span>: ${d.tooltipValue || d.value}</span>
7179
7276
  </li>
7180
7277
  `).join('')
7181
7278
  tooltipHTML += `</ul>`
@@ -7251,6 +7348,9 @@ if (this.options.data[side].scale === 'Time') {
7251
7348
  }
7252
7349
  prep () {
7253
7350
  /* global d3 WebsyDesigns */
7351
+ this.defs = this.svg.append('defs')
7352
+ this.clip = this.defs.append('clipPath').attr('id', `${this.elementId}_clip`).append('rect')
7353
+ this.brushClip = this.defs.append('clipPath').attr('id', `${this.elementId}_brushclip`).append('rect')
7254
7354
  this.leftAxisLayer = this.svg.append('g').attr('class', 'left-axis-layer')
7255
7355
  this.rightAxisLayer = this.svg.append('g').attr('class', 'right-axis-layer')
7256
7356
  this.bottomAxisLayer = this.svg.append('g').attr('class', 'bottom-axis-layer')
@@ -7267,6 +7367,14 @@ this.refLineLayer = this.svg.append('g').attr('class', 'refline-layer')
7267
7367
  this.trackingLineLayer = this.svg.append('g').attr('class', 'tracking-line-layer')
7268
7368
  this.trackingLineLayer.append('line').attr('class', 'tracking-line')
7269
7369
  this.tooltip = new WebsyDesigns.WebsyChartTooltip(this.svg)
7370
+ this.brushLayer = this.svg
7371
+ .append('g')
7372
+ // .attr(
7373
+ // 'clip-path',
7374
+ // `url(#${this.elementId.replace(/\s/g, '_')}_brushclip)`
7375
+ // )
7376
+ this.brushArea = this.brushLayer.append('g').attr('class', 'brush-area')
7377
+ this.brushLayer.append('g').attr('class', 'brush')
7270
7378
  this.eventLayer = this.svg.append('g').attr('class', 'event-line').append('rect')
7271
7379
  this.eventLayer
7272
7380
  .on('mouseout', this.handleEventMouseOut.bind(this))
@@ -7380,7 +7488,7 @@ else {
7380
7488
  this.longestBottom = this.options.data.bottom.max.toString()
7381
7489
  if (this.options.data.bottom.formatter) {
7382
7490
  this.longestBottom = this.options.data.bottom.formatter(this.options.data.bottom.max).toString()
7383
- firstBottom = this.longestBottom
7491
+ firstBottom = this.options.data.bottom.formatter(this.options.data.bottom.data[0].value).toString()
7384
7492
  }
7385
7493
  else {
7386
7494
  if (this.options.data.bottom.scale === 'Time') {
@@ -7389,6 +7497,7 @@ else {
7389
7497
  }
7390
7498
  else {
7391
7499
  this.longestBottom = this.options.data.bottom.data.reduce((a, b) => a.length > b.value.length ? a : b.value, '')
7500
+ // firstBottom = (this.options.data.bottom.data[0] || [{value: ''}]).value
7392
7501
  firstBottom = this.options.data.bottom.data[0].value
7393
7502
  }
7394
7503
  }
@@ -7464,7 +7573,7 @@ else {
7464
7573
  this.options.margin.axisLeft = Math.max(this.options.margin.axisLeft, longestBottomBounds.width / 2)
7465
7574
  }
7466
7575
  else if (((this.options.data.bottom && this.options.data.bottom.rotate) || 0) < 0 && this.options.axis.hideBottom !== true) {
7467
- this.options.margin.axisLeft = Math.max(this.options.margin.axisLeft, longestBottomBounds.width)
7576
+ this.options.margin.axisLeft = Math.max(this.options.margin.axisLeft, firstBottomWidth / 2)
7468
7577
  }
7469
7578
  else if (((this.options.data.bottom && this.options.data.bottom.rotate) || 0) > 0 && this.options.axis.hideBottom !== true) {
7470
7579
  this.options.margin.axisRight = Math.max(this.options.margin.axisRight, longestBottomBounds.width)
@@ -7494,6 +7603,24 @@ else {
7494
7603
  // Define the plot size
7495
7604
  this.plotWidth = this.width - this.options.margin.legendLeft - this.options.margin.legendRight - this.options.margin.left - this.options.margin.right - this.options.margin.axisLeft - this.options.margin.axisRight
7496
7605
  this.plotHeight = this.height - this.options.margin.legendTop - this.options.margin.legendBottom - this.options.margin.top - this.options.margin.bottom - this.options.margin.axisBottom - this.options.margin.axisTop
7606
+ this.brushNeeded = false
7607
+ if (this.options.orientation === 'vertical') {
7608
+ if (this.options.maxBandWidth) {
7609
+ this.plotWidth = Math.min(this.plotWidth, (this.options.data.bottom.data || []).length * this.options.maxBandWidth)
7610
+ }
7611
+ // some if to check if brushing is needed
7612
+ if (this.plotWidth / this.options.data.bottom.data.length < this.options.minBandWidth) {
7613
+ this.brushNeeded = true
7614
+ this.plotHeight -= this.options.brushHeight
7615
+ }
7616
+ }
7617
+ else {
7618
+ // some if to check if brushing is needed
7619
+ if (this.plotHeight / this.options.data.left.data.length < this.options.minBandWidth) {
7620
+ this.brushNeeded = true
7621
+ this.plotWidth -= this.options.brushHeight
7622
+ }
7623
+ }
7497
7624
  // Translate the layers
7498
7625
  this.leftAxisLayer
7499
7626
  .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
@@ -7526,6 +7653,12 @@ else {
7526
7653
  .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
7527
7654
  this.trackingLineLayer
7528
7655
  .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
7656
+ this.brushLayer
7657
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop + this.plotHeight + longestBottomBounds.height})`)
7658
+ this.brushClip
7659
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop + this.plotHeight + longestBottomBounds.height})`)
7660
+ .attr('width', this.plotWidth)
7661
+ .attr('height', this.options.brushHeight)
7529
7662
  this.eventLayer
7530
7663
  .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
7531
7664
  let that = this
@@ -7537,16 +7670,113 @@ else {
7537
7670
  .attr('fill-opacity', '0')
7538
7671
  // this.tooltip.transform(this.options.margin.left + this.options.margin.axisLeft, this.options.margin.top + this.options.margin.axisTop)
7539
7672
  // Configure the bottom axis
7540
- let bottomDomain = this.createDomain('bottom')
7673
+ let bottomDomain = this.createDomain('bottom')
7674
+ let bottomBrushDomain = this.createDomain('bottom', true)
7541
7675
  this.bottomAxis = d3[`scale${this.options.data.bottom.scale || 'Band'}`]()
7542
7676
  .domain(bottomDomain)
7543
- .range([0, this.plotWidth])
7677
+ .range([0, this.plotWidth])
7678
+ if (!this.brushInitialized) {
7679
+ this.bottomBrushAxis = d3[`scale${this.options.data.bottom.scale || 'Band'}`]()
7680
+ .domain(bottomBrushDomain)
7681
+ .range([0, this.plotWidth])
7682
+ }
7544
7683
  if (this.bottomAxis.nice) {
7545
7684
  // this.bottomAxis.nice()
7546
7685
  }
7547
7686
  if (this.bottomAxis.padding && this.options.data.bottom.padding) {
7548
7687
  this.bottomAxis.padding(this.options.data.bottom.padding || 0)
7549
7688
  }
7689
+ // BRUSH
7690
+ let brushMethod = `brushX`
7691
+ let brushLength = this.plotWidth
7692
+ let brushEnd = this.plotWidth
7693
+ let brushThickness = this.options.brushHeight
7694
+ if (this.options.orientation === 'horizontal') {
7695
+ brushMethod = 'brushY'
7696
+ brushLength = this.options.brushHeight
7697
+ brushThickness = this.plotHeight
7698
+ }
7699
+ else {
7700
+ if (brushLength / bottomDomain.length < this.options.minBandWidth) {
7701
+ brushEnd = this.plotWidth * ((this.plotWidth / this.options.minBandWidth) / bottomDomain.length)
7702
+ }
7703
+ }
7704
+ this.brush = d3[brushMethod]()
7705
+ .extent([
7706
+ [0, 0],
7707
+ [brushLength, brushThickness]
7708
+ ])
7709
+ .on('brush end', this.brushed)
7710
+ const brushResizePath = d => {
7711
+ let e = +(d.type === 'e')
7712
+ let x = e ? 1 : -1
7713
+ let y = this.options.brushHeight
7714
+ return (
7715
+ 'M' +
7716
+ 0.5 * x +
7717
+ ',' +
7718
+ y +
7719
+ 'A6,6 0 0 ' +
7720
+ e +
7721
+ ' ' +
7722
+ 6.5 * x +
7723
+ ',' +
7724
+ (y + 6) +
7725
+ 'V' +
7726
+ (2 * y - 6) +
7727
+ 'A6,6 0 0 ' +
7728
+ e +
7729
+ ' ' +
7730
+ 0.5 * x +
7731
+ ',' +
7732
+ 2 * y +
7733
+ 'Z' +
7734
+ 'M' +
7735
+ 2.5 * x +
7736
+ ',' +
7737
+ (y + 8) +
7738
+ 'V' +
7739
+ (2 * y - 8) +
7740
+ 'M' +
7741
+ 4.5 * x +
7742
+ ',' +
7743
+ (y + 8) +
7744
+ 'V' +
7745
+ (2 * y - 8)
7746
+ )
7747
+ }
7748
+ this.brushHandle = this.brushLayer
7749
+ .select('.brush')
7750
+ .selectAll('.handle--custom')
7751
+ .remove()
7752
+ this.brushHandle = this.brushLayer
7753
+ .select('.brush')
7754
+ .selectAll('.handle--custom')
7755
+ .data([{ type: 'w' }, { type: 'e' }])
7756
+ .enter()
7757
+ .append('path')
7758
+ .attr('class', 'handle--custom')
7759
+ .attr('stroke', 'transparent')
7760
+ .attr('fill', 'transparent')
7761
+ .attr('cursor', 'ew-resize')
7762
+ .attr('d', brushResizePath)
7763
+ // BRUSH END
7764
+ // this.brushArea.selectAll('*').remove()
7765
+ if (this.brushNeeded) {
7766
+ if (!this.brushInitialized) {
7767
+ this.brushLayer.style('visibility', 'visible')
7768
+ this.brushInitialized = true
7769
+ this.brushLayer
7770
+ .select('.brush')
7771
+ .call(this.brush)
7772
+ .call(this.brush.move, [0, brushEnd])
7773
+ }
7774
+ }
7775
+ else {
7776
+ this.brushLayer.style('visibility', 'hidden')
7777
+ // this.brushLayer.selectAll().remove()
7778
+ this.brushArea.selectAll('*').remove()
7779
+ }
7550
7780
  if (this.options.margin.axisBottom > 0) {
7551
7781
  let timeFormatPattern = ''
7552
7782
  let tickDefinition
@@ -7607,15 +7837,12 @@ else {
7607
7837
  tickDefinition = this.options.data.bottom.ticks || 5
7608
7838
  }
7609
7839
  this.options.calculatedTimeFormatPattern = timeFormatPattern
7610
- let bAxisFunc = d3.axisBottom(this.bottomAxis)
7611
- // .ticks(this.options.data.bottom.ticks || Math.min(this.options.data.bottom.data.length, 5))
7612
- .ticks(tickDefinition)
7613
- // console.log('tickDefinition', tickDefinition)
7614
- // console.log(bAxisFunc)
7840
+ this.bAxisFunc = d3.axisBottom(this.bottomAxis)
7841
+ .ticks(tickDefinition)
7615
7842
  if (this.options.data.bottom.formatter) {
7616
- bAxisFunc.tickFormat(d => this.options.data.bottom.formatter(d))
7843
+ this.bAxisFunc.tickFormat(d => this.options.data.bottom.formatter(d))
7617
7844
  }
7618
- this.bottomAxisLayer.call(bAxisFunc)
7845
+ this.bottomAxisLayer.call(this.bAxisFunc)
7619
7846
  // console.log(this.bottomAxisLayer.ticks)
7620
7847
  if (this.options.data.bottom.rotate) {
7621
7848
  this.bottomAxisLayer.selectAll('text')
@@ -7625,11 +7852,15 @@ else {
7625
7852
  }
7626
7853
  }
7627
7854
  // Configure the left axis
7628
- let leftDomain = this.createDomain('left')
7855
+ let leftDomain = this.createDomain('left')
7856
+ let leftBrushDomain = this.createDomain('left', true)
7629
7857
  let rightDomain = this.createDomain('right')
7630
7858
  this.leftAxis = d3[`scale${this.options.data.left.scale || 'Linear'}`]()
7631
7859
  .domain(leftDomain)
7632
7860
  .range([this.plotHeight, 0])
7861
+ this.leftBrushAxis = d3[`scale${this.options.data.left.scale || 'Linear'}`]()
7862
+ .domain(leftBrushDomain)
7863
+ .range([this.options.brushHeight, 0])
7633
7864
  if (this.leftAxis.padding && this.options.data.left.padding) {
7634
7865
  this.leftAxis.padding(this.options.data.left.padding || 0)
7635
7866
  }
@@ -7698,7 +7929,7 @@ else {
7698
7929
  if (this.options.margin.axisRight > 0 && (this.options.data.right.min !== 0 || this.options.data.right.max !== 0)) {
7699
7930
  this.rightAxisLayer.call(
7700
7931
  d3.axisRight(this.rightAxis)
7701
- .ticks(this.options.data.left.ticks || 5)
7932
+ .ticks(this.options.data.right.ticks || 5)
7702
7933
  .tickFormat(d => {
7703
7934
  if (this.options.data.right.formatter) {
7704
7935
  d = this.options.data.right.formatter(d)
@@ -7745,25 +7976,29 @@ else {
7745
7976
  this[`remove${this.renderedKeys[key]}`](key)
7746
7977
  }
7747
7978
  }
7748
- // Draw the series data
7749
- this.renderedKeys = {}
7750
- this.options.data.series.forEach((series, index) => {
7751
- if (!series.key) {
7752
- series.key = this.createIdentity()
7753
- }
7754
- if (!series.color) {
7755
- series.color = this.options.colors[index % this.options.colors.length]
7756
- }
7757
- this[`render${series.type || 'bar'}`](series, index)
7758
- this.renderLabels(series, index)
7759
- this.renderedKeys[series.key] = series.type
7760
- })
7761
- if (this.options.refLines && this.options.refLines.length > 0) {
7762
- this.options.refLines.forEach(l => this.renderRefLine(l))
7763
- }
7979
+ this.renderComponents()
7764
7980
  }
7765
7981
  }
7766
7982
 
7983
+ }
7984
+ renderComponents () {
7985
+ // Draw the series data
7986
+ this.renderedKeys = {}
7987
+ this.options.data.series.forEach((series, index) => {
7988
+ if (!series.key) {
7989
+ series.key = this.createIdentity()
7990
+ }
7991
+ if (!series.color) {
7992
+ series.color = this.options.colors[index % this.options.colors.length]
7993
+ }
7994
+ this[`render${series.type || 'bar'}`](series, index)
7995
+ this.renderLabels(series, index)
7996
+ this.renderedKeys[series.key] = series.type
7997
+ })
7998
+ if (this.options.refLines && this.options.refLines.length > 0) {
7999
+ this.options.refLines.forEach(l => this.renderRefLine(l))
8000
+ }
8001
+
7767
8002
  }
7768
8003
  renderarea (series, index) {
7769
8004
  /* global d3 series index */
@@ -7822,74 +8057,111 @@ areas.enter().append('path')
7822
8057
  let xAxis = 'bottom'
7823
8058
  let yAxis = 'left'
7824
8059
  let bars = this.barLayer.selectAll(`.bar_${series.key}`).data(series.data)
8060
+ let brushBars = this.brushArea.selectAll(`.bar_${series.key}`).data(series.data)
7825
8061
  let acummulativeY = new Array(this.options.data.series.length).fill(0)
7826
8062
  if (this.options.orientation === 'horizontal') {
7827
8063
  xAxis = 'left'
7828
8064
  yAxis = 'bottom'
7829
8065
  }
7830
- let barWidth = this[`${xAxis}Axis`].bandwidth()
7831
- let groupedBarWidth = (barWidth - 10) / this.options.data.series.length
7832
8066
  // if (this.options.data.series.length > 1 && this.options.grouping === 'grouped') {
7833
8067
  // barWidth = barWidth / this.options.data.series.length - 4
7834
8068
  // }
7835
- function getBarHeight (d, i) {
8069
+ function getBarHeight (d, i, heightBounds, yAxis, xAxis) {
8070
+ let barWidth = this[`${xAxis}Axis`].bandwidth()
8071
+ let groupedBarWidth = (barWidth - 10) / this.options.data.series.length
8072
+ let output
7836
8073
  if (this.options.orientation === 'horizontal') {
7837
- return barWidth
8074
+ output = barWidth
7838
8075
  }
7839
8076
  else {
7840
- return this[`${yAxis}Axis`](d.y.value)
8077
+ if (!getBarX.call(this, d, i, xAxis)) {
8078
+ return null
8079
+ }
8080
+ output = (this[`${yAxis}Axis`](0)) - this[`${yAxis}Axis`](Math.abs(d.y.value))
8081
+ }
8082
+ if (isNaN(output)) {
8083
+ return null
7841
8084
  }
8085
+ return output
7842
8086
  }
7843
- function getBarWidth (d, i) {
8087
+ function getBarWidth (d, i, xAxis) {
8088
+ let barWidth = this[`${xAxis}Axis`].bandwidth()
8089
+ let groupedBarWidth = (barWidth - (xAxis.indexOf('Brush') === -1 ? 10 : 2)) / this.options.data.series.length
8090
+ let output
7844
8091
  if (this.options.orientation === 'horizontal') {
7845
8092
  let width = this[`${yAxis}Axis`](d.y.value)
7846
8093
  acummulativeY[d.y.index] += width
7847
- return width
8094
+ output = Math.max(1, width)
7848
8095
  }
7849
8096
  else {
8097
+ if (!getBarX.call(this, d, i, xAxis)) {
8098
+ return null
8099
+ }
7850
8100
  if (this.options.grouping === 'grouped') {
7851
- return groupedBarWidth
8101
+ output = Math.max(1, groupedBarWidth)
8102
+ }
8103
+ else {
8104
+ output = Math.max(1, barWidth)
7852
8105
  }
7853
- return barWidth
7854
8106
  }
8107
+ if (isNaN(output)) {
8108
+ return 0
8109
+ }
8110
+ return output
7855
8111
  }
7856
- function getBarX (d, i) {
8112
+ function getBarX (d, i, xAxis) {
8113
+ let barWidth = this[`${xAxis}Axis`].bandwidth()
8114
+ let groupedBarWidth = (barWidth - (xAxis.indexOf('Brush') === -1 ? 10 : 2)) / this.options.data.series.length
8115
+ let output
7857
8116
  if (this.options.orientation === 'horizontal') {
7858
8117
  if (this.options.grouping === 'stacked') {
7859
- return this[`${yAxis}Axis`](d.y.accumulative)
8118
+ output = this[`${yAxis}Axis`](d.y.accumulative)
7860
8119
  }
7861
8120
  else {
7862
- return 0
8121
+ output = 0
7863
8122
  }
7864
8123
  }
7865
8124
  else {
7866
- let adjustment = this.options.data[xAxis].scale === 'Time' ? 0 : this[`${xAxis}Axis`].bandwidth() / 2
8125
+ let adjustment = this.options.data[xAxis.replace('Brush', '')].scale === 'Time' ? 0 : this[`${xAxis}Axis`].bandwidth() / 2
7867
8126
  if (this.options.grouping === 'grouped') {
7868
- let barAdjustment = groupedBarWidth * index + 5 // + (index > 0 ? 4 : 0)
7869
- return this[`${xAxis}Axis`](this.parseX(d.x.value)) + barAdjustment
8127
+ let barAdjustment = groupedBarWidth * index + (xAxis.indexOf('Brush') === -1 ? 5 : 1) // + (index > 0 ? 4 : 0)
8128
+ output = this[`${xAxis}Axis`](this.parseX(d.x.value)) + barAdjustment
7870
8129
  }
7871
8130
  else {
7872
- return this[`${xAxis}Axis`](this.parseX(d.x.value)) + (i * barWidth) + adjustment
8131
+ // output = this[`${xAxis}Axis`](this.parseX(d.x.value)) + (i * barWidth) + adjustment
8132
+ output = this[`${xAxis}Axis`](this.parseX(d.x.value)) // + (i * barWidth)
7873
8133
  }
7874
8134
  }
8135
+ if (isNaN(output)) {
8136
+ return null
8137
+ }
8138
+ return output
7875
8139
  }
7876
- function getBarY (d, i) {
8140
+ function getBarY (d, i, heightBounds, yAxis, xAxis) {
8141
+ let barWidth = this[`${xAxis}Axis`].bandwidth()
8142
+ let groupedBarWidth = (barWidth - 10) / this.options.data.series.length
8143
+ let output
7877
8144
  if (this.options.orientation === 'horizontal') {
7878
8145
  if (this.options.grouping !== 'grouped') {
7879
- return this[`${xAxis}Axis`](this.parseX(d.x.value))
8146
+ output = this[`${xAxis}Axis`](this.parseX(d.x.value))
7880
8147
  }
7881
8148
  else {
7882
- return this[`${xAxis}Axis`](this.parseX(d.x.value)) + ((d.y.index || i) * barWidth)
8149
+ output = this[`${xAxis}Axis`](this.parseX(d.x.value)) + ((d.y.index || i) * barWidth)
7883
8150
  }
7884
8151
  }
7885
8152
  else {
7886
8153
  if (this.options.grouping === 'stacked') {
7887
- return this[`${yAxis}Axis`](d.y.accumulative)
8154
+ output = heightBounds - this[`${yAxis}Axis`](d.y.accumulative)
7888
8155
  }
7889
8156
  else {
7890
- return this.plotHeight - getBarHeight.call(this, d, i)
8157
+ let h = getBarHeight.call(this, d, i, heightBounds, yAxis, xAxis)
8158
+ output = (this[`${yAxis}Axis`](0)) - (h * (d.y.value < 0 ? 0 : 1))
7891
8159
  }
7892
8160
  }
8161
+ if (isNaN(output)) {
8162
+ return null
8163
+ }
8164
+ return output
7893
8165
  }
7894
8166
  bars
7895
8167
  .exit()
@@ -7898,26 +8170,56 @@ bars
7898
8170
  .remove()
7899
8171
 
7900
8172
  bars
7901
- .attr('width', getBarWidth.bind(this))
7902
- .attr('height', getBarHeight.bind(this))
7903
- .attr('x', getBarX.bind(this))
7904
- .attr('y', getBarY.bind(this))
7905
- .transition(this.transition)
8173
+ .attr('width', (d, i) => getBarWidth.call(this, d, i, xAxis))
8174
+ .attr('height', (d, i) => getBarHeight.call(this, d, i, this.plotHeight, yAxis, xAxis))
8175
+ .attr('x', (d, i) => getBarX.call(this, d, i, xAxis))
8176
+ .attr('y', (d, i) => getBarY.call(this, d, i, this.plotHeight, yAxis, xAxis))
8177
+ // .transition(this.transition)
7906
8178
  .attr('fill', d => d.y.color || d.color || series.color)
7907
8179
 
7908
8180
  bars
7909
8181
  .enter()
7910
8182
  .append('rect')
7911
- .attr('width', getBarWidth.bind(this))
7912
- .attr('height', getBarHeight.bind(this))
7913
- .attr('x', getBarX.bind(this))
7914
- .attr('y', getBarY.bind(this))
8183
+ .attr('width', (d, i) => getBarWidth.call(this, d, i, xAxis))
8184
+ .attr('height', (d, i) => getBarHeight.call(this, d, i, this.plotHeight, yAxis, xAxis))
8185
+ .attr('x', (d, i) => getBarX.call(this, d, i, xAxis))
8186
+ .attr('y', (d, i) => getBarY.call(this, d, i, this.plotHeight, yAxis, xAxis))
7915
8187
  // .transition(this.transition)
7916
8188
  .attr('fill', d => d.y.color || d.color || series.color)
7917
8189
  .attr('class', d => {
7918
8190
  return `bar bar_${series.key}`
7919
8191
  })
7920
8192
 
8193
+ if (!this.brushBarsInitialized[series.key]) {
8194
+ this.brushBarsInitialized[series.key] = true
8195
+ brushBars
8196
+ .exit()
8197
+ .transition(this.transition)
8198
+ .style('fill-opacity', 1e-6)
8199
+ .remove()
8200
+
8201
+ brushBars
8202
+ .attr('width', (d, i) => getBarWidth.call(this, d, i, `${xAxis}Brush`))
8203
+ .attr('height', (d, i) => getBarHeight.call(this, d, i, this.options.brushHeight, `${yAxis}Brush`, `${xAxis}Brush`))
8204
+ .attr('x', (d, i) => getBarX.call(this, d, i, `${xAxis}Brush`))
8205
+ .attr('y', (d, i) => getBarY.call(this, d, i, this.options.brushHeight, `${yAxis}Brush`, `${xAxis}Brush`))
8206
+ // .transition(this.transition)
8207
+ .attr('fill', d => d.y.color || d.color || series.color)
8208
+
8209
+ brushBars
8210
+ .enter()
8211
+ .append('rect')
8212
+ .attr('width', (d, i) => getBarWidth.call(this, d, i, `${xAxis}Brush`))
8213
+ .attr('height', (d, i) => getBarHeight.call(this, d, i, this.options.brushHeight, `${yAxis}Brush`, `${xAxis}Brush`))
8214
+ .attr('x', (d, i) => getBarX.call(this, d, i, `${xAxis}Brush`))
8215
+ .attr('y', (d, i) => getBarY.call(this, d, i, this.options.brushHeight, `${yAxis}Brush`, `${xAxis}Brush`))
8216
+ // .transition(this.transition)
8217
+ .attr('fill', d => d.y.color || d.color || series.color)
8218
+ .attr('class', d => {
8219
+ return `bar bar_${series.key}`
8220
+ })
8221
+ }
8222
+
7921
8223
  }
7922
8224
  removebar (key) {
7923
8225
  /* global key d3 */
@@ -8062,7 +8364,7 @@ const drawLine = (xAxis, yAxis, curveStyle) => {
8062
8364
  return d3
8063
8365
  .line()
8064
8366
  .x(d => {
8065
- let adjustment = this.options.data[xAxis].scale === 'Time' ? 0 : this[`${xAxis}Axis`].bandwidth() / 2
8367
+ let adjustment = this.options.data[xAxis.replace('Brush', '')].scale === 'Time' ? 0 : this[`${xAxis}Axis`].bandwidth() / 2
8066
8368
  return this[`${xAxis}Axis`](this.parseX(d.x.value)) + adjustment
8067
8369
  })
8068
8370
  .y(d => {
@@ -8076,8 +8378,16 @@ if (this.options.orienation === 'horizontal') {
8076
8378
  xAxis = series.axis === 'secondary' ? 'right' : 'left'
8077
8379
  yAxis = 'bottom'
8078
8380
  }
8381
+ let xBrushAxis = 'bottomBrush'
8382
+ let yBrushAxis = 'leftBrush'
8383
+ if (this.options.orienation === 'horizontal') {
8384
+ xBrushAxis = 'leftBrush'
8385
+ yBrushAxis = 'bottomBrush'
8386
+ }
8079
8387
  let lines = this.lineLayer.selectAll(`.line_${series.key}`)
8080
8388
  .data([series.data])
8389
+ let brushLines = this.brushArea.selectAll(`.line_${series.key}`)
8390
+ .data([series.data])
8081
8391
  // Exit
8082
8392
  lines.exit()
8083
8393
  .transition(this.transition)
@@ -8104,6 +8414,35 @@ lines.enter().append('path')
8104
8414
  // .transition(this.transition)
8105
8415
  .style('stroke-opacity', 1)
8106
8416
 
8417
+ if (!this.brushLinesInitialized[series.key]) {
8418
+ this.brushLinesInitialized[series.key] = true
8419
+ // Exit
8420
+ brushLines.exit()
8421
+ .transition(this.transition)
8422
+ .style('stroke-opacity', 1e-6)
8423
+ .remove()
8424
+ // Update
8425
+ brushLines
8426
+ .style('stroke-width', 1)
8427
+ // .attr('id', `line_${series.key}`)
8428
+ // .attr('transform', 'translate('+ (that.bandWidth/2) +',0)')
8429
+ .attr('stroke', series.color)
8430
+ .attr('fill', 'transparent')
8431
+ .transition(this.transition)
8432
+ .attr('d', d => drawLine(xBrushAxis, yBrushAxis, series.curveStyle)(d))
8433
+ // Enter
8434
+ brushLines.enter().append('path')
8435
+ .attr('d', d => drawLine(xBrushAxis, yBrushAxis, series.curveStyle)(d))
8436
+ .attr('class', `line_${series.key}`)
8437
+ .attr('id', `line_${series.key}`)
8438
+ // .attr('transform', 'translate('+ (that.bandWidth/2) +',0)')
8439
+ .style('stroke-width', 1)
8440
+ .attr('stroke', series.color)
8441
+ .attr('fill', 'transparent')
8442
+ // .transition(this.transition)
8443
+ .style('stroke-opacity', 1)
8444
+ }
8445
+
8107
8446
  if (series.showArea === true) {
8108
8447
  this.renderarea(series, index)
8109
8448
  }
@@ -8307,6 +8646,44 @@ if (el) {
8307
8646
  }
8308
8647
 
8309
8648
  }
8649
+ hideError () {
8650
+ const el = document.getElementById(`${this.elementId}`)
8651
+ if (el) {
8652
+ el.classList.remove('has-error')
8653
+ }
8654
+ // const chartEl = document.getElementById(`${this.elementId}_chartContainer`)
8655
+ // chartEl.classList.remove('hidden')
8656
+ this.svg.classed('hidden', false)
8657
+ const containerEl = document.getElementById(`${this.elementId}_errorContainer`)
8658
+ if (containerEl) {
8659
+ containerEl.classList.remove('active')
8660
+ }
8661
+ }
8662
+ showError (options) {
8663
+ const el = document.getElementById(`${this.elementId}`)
8664
+ if (el) {
8665
+ el.classList.add('has-error')
8666
+ }
8667
+ // const chartEl = document.getElementById(`${this.elementId}_chartContainer`)
8668
+ // chartEl.classList.add('hidden')
8669
+ this.svg.classed('hidden', true)
8670
+ const containerEl = document.getElementById(`${this.elementId}_errorContainer`)
8671
+ if (containerEl) {
8672
+ containerEl.classList.add('active')
8673
+ }
8674
+ if (options.title) {
8675
+ const titleEl = document.getElementById(`${this.elementId}_errorTitle`)
8676
+ if (titleEl) {
8677
+ titleEl.innerHTML = options.title
8678
+ }
8679
+ }
8680
+ if (options.message) {
8681
+ const messageEl = document.getElementById(`${this.elementId}_errorMessage`)
8682
+ if (messageEl) {
8683
+ messageEl.innerHTML = options.message
8684
+ }
8685
+ }
8686
+ }
8310
8687
  }
8311
8688
 
8312
8689
  class WebsyLegend {