@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.
@@ -6158,6 +6158,10 @@ class WebsyTable3 {
6158
6158
  headEl.style.width = 'initial'
6159
6159
  bodyEl.style.width = 'initial'
6160
6160
  this.sizes.bodyHeight = this.sizes.table.height - (this.sizes.header.height + this.sizes.total.height)
6161
+ if (this.options.maxHeight) {
6162
+ let requiredHeight = ((this.totalRowCount || 9) + 1) * this.sizes.cellHeight
6163
+ this.sizes.bodyHeight = Math.min(requiredHeight, this.options.maxHeight - (this.sizes.header.height + this.sizes.total.height))
6164
+ }
6161
6165
  this.sizes.rowsToRender = Math.ceil(this.sizes.bodyHeight / this.sizes.cellHeight)
6162
6166
  this.sizes.rowsToRenderPrecise = this.sizes.bodyHeight / this.sizes.cellHeight
6163
6167
  this.startRow = 0
@@ -6344,7 +6348,13 @@ class WebsyTable3 {
6344
6348
  }
6345
6349
  let bodyEl = document.getElementById(`${this.elementId}_tableBody`)
6346
6350
  // bodyEl.innerHTML = this.buildBodyHtml(data, true)
6347
- bodyEl.style.height = `calc(100% - ${this.sizes.header.height}px - ${this.sizes.total.height}px)`
6351
+ // if (this.options.maxHeight) {
6352
+ // bodyEl.style.height = `${this.options.maxHeight - this.sizes.header.height - this.sizes.total.height}px`
6353
+ // }
6354
+ // else {
6355
+ // bodyEl.style.height = `calc(100% - ${this.sizes.header.height}px - ${this.sizes.total.height}px)`
6356
+ // }
6357
+ bodyEl.style.height = `${this.sizes.bodyHeight}px`
6348
6358
  if (this.options.virtualScroll === true) {
6349
6359
  // set the scroll element positions
6350
6360
  let vScrollEl = document.getElementById(`${this.elementId}_vScrollContainer`)
@@ -6542,7 +6552,9 @@ class WebsyChart {
6542
6552
  showTooltip: true,
6543
6553
  showLegend: false,
6544
6554
  legendPosition: 'bottom',
6545
- tooltipWidth: 200
6555
+ tooltipWidth: 200,
6556
+ brushHeight: 50,
6557
+ minBandWidth: 30
6546
6558
  }
6547
6559
  this.elementId = elementId
6548
6560
  this.options = Object.assign({}, DEFAULTS, options)
@@ -6551,15 +6563,22 @@ class WebsyChart {
6551
6563
  this.topAxis = null
6552
6564
  this.bottomAxis = null
6553
6565
  this.renderedKeys = {}
6566
+ this.brushedDomain = []
6567
+ this.brushBarsInitialized = {}
6568
+ this.brushLinesInitialized = {}
6554
6569
  if (!elementId) {
6555
6570
  console.log('No element Id provided for Websy Chart')
6556
6571
  return
6557
6572
  }
6558
- this.invertOverride = (input, input2) => {
6559
- let xAxis = 'bottomAxis'
6573
+ this.invertOverride = (input, input2, forBrush = false) => {
6574
+ let xAxis = 'bottom'
6560
6575
  if (this.options.orientation === 'horizontal') {
6561
- xAxis = 'leftAxis'
6576
+ xAxis = 'left'
6577
+ }
6578
+ if (forBrush === true) {
6579
+ xAxis += 'Brush'
6562
6580
  }
6581
+ xAxis += 'Axis'
6563
6582
  let width = this[xAxis].step()
6564
6583
  let output
6565
6584
  let domain = [...this[xAxis].domain()]
@@ -6575,6 +6594,65 @@ class WebsyChart {
6575
6594
  }
6576
6595
  }
6577
6596
  return output
6597
+ }
6598
+ let that = this
6599
+ this.brushed = function (event) {
6600
+ console.log('brushing', event)
6601
+ that.brushedDomain = []
6602
+ let xAxis = 'bottom'
6603
+ let xAxisCaps = 'Bottom'
6604
+ if (that.options.orientation === 'horizontal') {
6605
+ xAxis = 'left'
6606
+ xAxisCaps = 'Left'
6607
+ }
6608
+ if (!that[`${xAxis}Axis`].invert) {
6609
+ that[`${xAxis}Axis`].invert = that.invertOverride
6610
+ }
6611
+ let s = event.selection || that[`${xAxis}Axis`].range()
6612
+ if (!event.selection || event.selection.length === 0) {
6613
+ that.brushLayer
6614
+ .select('.brush')
6615
+ .call(that.brush)
6616
+ .call(that.brush.move, s)
6617
+ return
6618
+ }
6619
+ if (that.options.data[xAxis].scale && that.options.data[xAxis].scale === 'Time') {
6620
+ that.brushedDomain = s.map(that[`${xAxis}BrushAxis`].invert, that[[`${xAxis}Axis`]])
6621
+ }
6622
+ else {
6623
+ let startEndOrdinal = s.map((a, b) => that.bottomAxis.invert(a, b, true), that.bottomBrushAxis)
6624
+ if (
6625
+ startEndOrdinal &&
6626
+ startEndOrdinal.length === 2 &&
6627
+ typeof startEndOrdinal[0] !== 'undefined' &&
6628
+ typeof startEndOrdinal[1] !== 'undefined'
6629
+ ) {
6630
+ let domain = []
6631
+ let domainValues = [...that[`${xAxis}BrushAxis`].domain()]
6632
+ for (let i = startEndOrdinal[0]; i < startEndOrdinal[1] + 1; i++) {
6633
+ // domain.push(that.xRange[i])
6634
+ that.brushedDomain.push(domainValues[i])
6635
+ }
6636
+ }
6637
+ }
6638
+ if (that.brushedDomain.length > 0) {
6639
+ that[`${xAxis}Axis`].domain(that.brushedDomain)
6640
+ that[`${xAxis}AxisLayer`].call(
6641
+ d3[`axis${xAxisCaps}`](that[`${xAxis}Axis`])
6642
+ )
6643
+ }
6644
+ if (that.leftAxis && that.bottomAxis) {
6645
+ that.renderComponents()
6646
+ if (that.options.orientation === 'vertical') {
6647
+ // that.bottomAxisLayer.call(that.bAxisFunc)
6648
+ if (that.options.data.bottom.rotate) {
6649
+ that.bottomAxisLayer.selectAll('text')
6650
+ .attr('transform', `rotate(${((that.options.data.bottom && that.options.data.bottom.rotate) || 0)})`)
6651
+ .style('text-anchor', `${((that.options.data.bottom && that.options.data.bottom.rotate) || 0) === 0 ? 'middle' : 'end'}`)
6652
+ .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`)
6653
+ }
6654
+ }
6655
+ }
6578
6656
  }
6579
6657
  const el = document.getElementById(this.elementId)
6580
6658
  if (el) {
@@ -6584,12 +6662,20 @@ class WebsyChart {
6584
6662
  }
6585
6663
  else {
6586
6664
  el.innerHTML = ''
6587
- this.svg = d3.select(el).append('svg')
6665
+ this.svg = d3.select(el).append('svg') // .attr('id', `${this.elementId}_chartContainer`)
6588
6666
  this.legendArea = d3.select(el).append('div')
6589
6667
  .attr('id', `${this.elementId}_legend`)
6590
6668
  .attr('class', 'websy-chart-legend')
6591
6669
  this.legend = new WebsyDesigns.Legend(`${this.elementId}_legend`, {})
6592
6670
  this.prep()
6671
+ // el.innerHTML += `
6672
+ // <div id="${this.elementId}_errorContainer" class='websy-vis-error-container'>
6673
+ // <div>
6674
+ // <div id="${this.elementId}_errorTitle"></div>
6675
+ // <div id="${this.elementId}_errorMessage"></div>
6676
+ // </div>
6677
+ // </div>
6678
+ // `
6593
6679
  }
6594
6680
  }
6595
6681
  else {
@@ -6614,25 +6700,36 @@ class WebsyChart {
6614
6700
  this.labelLayer.selectAll('*').remove()
6615
6701
  this.symbolLayer.selectAll('*').remove()
6616
6702
  }
6617
- createDomain (side) {
6703
+ createDomain (side, forBrush = false) {
6618
6704
  let domain = []
6619
- /* global d3 side domain:writable */
6620
- if (typeof this.options.data[side].min !== 'undefined' && typeof this.options.data[side].max !== 'undefined') {
6621
- // domain = [this.options.data[side].min - (this.options.data[side].min * 0.1), this.options.data[side].max * 1.1]
6622
- domain = [this.options.data[side].min, this.options.data[side].max]
6623
- if (this.options.forceZero === true) {
6624
- domain = [Math.min(0, this.options.data[side].min), this.options.data[side].max]
6625
- }
6705
+ /* global d3 side domain:writable forBrush */
6706
+ // if we have a brushed domain we use that
6707
+ let xAxis = 'bottom'
6708
+ if (this.options.orientation === 'horizontal') {
6709
+ xAxis = 'left'
6626
6710
  }
6627
- if (this.options.data[side].data) {
6628
- domain = this.options.data[side].data.map(d => d.value)
6711
+ if (this.brushedDomain.length > 0 && side === xAxis && forBrush === false) {
6712
+ domain = [...this.brushedDomain]
6629
6713
  }
6630
- if (this.options.data[side].scale === 'Time') {
6631
- let min = this.options.data[side].data[0].value
6632
- let max = this.options.data[side].data[this.options.data[side].data.length - 1].value
6633
- min = this.parseX(min)
6634
- max = this.parseX(max)
6635
- domain = [min, max]
6714
+ else {
6715
+ // otherwise we create the domain
6716
+ if (typeof this.options.data[side].min !== 'undefined' && typeof this.options.data[side].max !== 'undefined') {
6717
+ // domain = [this.options.data[side].min - (this.options.data[side].min * 0.1), this.options.data[side].max * 1.1]
6718
+ domain = [this.options.data[side].min, this.options.data[side].max]
6719
+ if (this.options.forceZero === true) {
6720
+ domain = [Math.min(0, this.options.data[side].min), this.options.data[side].max]
6721
+ }
6722
+ }
6723
+ if (this.options.data[side].data) {
6724
+ domain = this.options.data[side].data.map(d => d.value)
6725
+ }
6726
+ if (this.options.data[side].scale === 'Time') {
6727
+ let min = this.options.data[side].data[0].value
6728
+ let max = this.options.data[side].data[this.options.data[side].data.length - 1].value
6729
+ min = this.parseX(min)
6730
+ max = this.parseX(max)
6731
+ domain = [min, max]
6732
+ }
6636
6733
  }
6637
6734
 
6638
6735
  return domain
@@ -6763,7 +6860,7 @@ if (this.options.data[side].scale === 'Time') {
6763
6860
  tooltipHTML += tooltipData.map(d => `
6764
6861
  <li>
6765
6862
  <i style='background-color: ${d.color};'></i>
6766
- ${d.tooltipLabel || ''}<span> - ${d.tooltipValue || d.value}</span>
6863
+ ${d.tooltipLabel || ''}<span>: ${d.tooltipValue || d.value}</span>
6767
6864
  </li>
6768
6865
  `).join('')
6769
6866
  tooltipHTML += `</ul>`
@@ -6839,6 +6936,9 @@ if (this.options.data[side].scale === 'Time') {
6839
6936
  }
6840
6937
  prep () {
6841
6938
  /* global d3 WebsyDesigns */
6939
+ this.defs = this.svg.append('defs')
6940
+ this.clip = this.defs.append('clipPath').attr('id', `${this.elementId}_clip`).append('rect')
6941
+ this.brushClip = this.defs.append('clipPath').attr('id', `${this.elementId}_brushclip`).append('rect')
6842
6942
  this.leftAxisLayer = this.svg.append('g').attr('class', 'left-axis-layer')
6843
6943
  this.rightAxisLayer = this.svg.append('g').attr('class', 'right-axis-layer')
6844
6944
  this.bottomAxisLayer = this.svg.append('g').attr('class', 'bottom-axis-layer')
@@ -6855,6 +6955,14 @@ this.refLineLayer = this.svg.append('g').attr('class', 'refline-layer')
6855
6955
  this.trackingLineLayer = this.svg.append('g').attr('class', 'tracking-line-layer')
6856
6956
  this.trackingLineLayer.append('line').attr('class', 'tracking-line')
6857
6957
  this.tooltip = new WebsyDesigns.WebsyChartTooltip(this.svg)
6958
+ this.brushLayer = this.svg
6959
+ .append('g')
6960
+ // .attr(
6961
+ // 'clip-path',
6962
+ // `url(#${this.elementId.replace(/\s/g, '_')}_brushclip)`
6963
+ // )
6964
+ this.brushArea = this.brushLayer.append('g').attr('class', 'brush-area')
6965
+ this.brushLayer.append('g').attr('class', 'brush')
6858
6966
  this.eventLayer = this.svg.append('g').attr('class', 'event-line').append('rect')
6859
6967
  this.eventLayer
6860
6968
  .on('mouseout', this.handleEventMouseOut.bind(this))
@@ -6968,7 +7076,7 @@ else {
6968
7076
  this.longestBottom = this.options.data.bottom.max.toString()
6969
7077
  if (this.options.data.bottom.formatter) {
6970
7078
  this.longestBottom = this.options.data.bottom.formatter(this.options.data.bottom.max).toString()
6971
- firstBottom = this.longestBottom
7079
+ firstBottom = this.options.data.bottom.formatter(this.options.data.bottom.data[0].value).toString()
6972
7080
  }
6973
7081
  else {
6974
7082
  if (this.options.data.bottom.scale === 'Time') {
@@ -6977,6 +7085,7 @@ else {
6977
7085
  }
6978
7086
  else {
6979
7087
  this.longestBottom = this.options.data.bottom.data.reduce((a, b) => a.length > b.value.length ? a : b.value, '')
7088
+ // firstBottom = (this.options.data.bottom.data[0] || [{value: ''}]).value
6980
7089
  firstBottom = this.options.data.bottom.data[0].value
6981
7090
  }
6982
7091
  }
@@ -7052,7 +7161,7 @@ else {
7052
7161
  this.options.margin.axisLeft = Math.max(this.options.margin.axisLeft, longestBottomBounds.width / 2)
7053
7162
  }
7054
7163
  else if (((this.options.data.bottom && this.options.data.bottom.rotate) || 0) < 0 && this.options.axis.hideBottom !== true) {
7055
- this.options.margin.axisLeft = Math.max(this.options.margin.axisLeft, longestBottomBounds.width)
7164
+ this.options.margin.axisLeft = Math.max(this.options.margin.axisLeft, firstBottomWidth / 2)
7056
7165
  }
7057
7166
  else if (((this.options.data.bottom && this.options.data.bottom.rotate) || 0) > 0 && this.options.axis.hideBottom !== true) {
7058
7167
  this.options.margin.axisRight = Math.max(this.options.margin.axisRight, longestBottomBounds.width)
@@ -7082,6 +7191,24 @@ else {
7082
7191
  // Define the plot size
7083
7192
  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
7084
7193
  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
7194
+ this.brushNeeded = false
7195
+ if (this.options.orientation === 'vertical') {
7196
+ if (this.options.maxBandWidth) {
7197
+ this.plotWidth = Math.min(this.plotWidth, (this.options.data.bottom.data || []).length * this.options.maxBandWidth)
7198
+ }
7199
+ // some if to check if brushing is needed
7200
+ if (this.plotWidth / this.options.data.bottom.data.length < this.options.minBandWidth) {
7201
+ this.brushNeeded = true
7202
+ this.plotHeight -= this.options.brushHeight
7203
+ }
7204
+ }
7205
+ else {
7206
+ // some if to check if brushing is needed
7207
+ if (this.plotHeight / this.options.data.left.data.length < this.options.minBandWidth) {
7208
+ this.brushNeeded = true
7209
+ this.plotWidth -= this.options.brushHeight
7210
+ }
7211
+ }
7085
7212
  // Translate the layers
7086
7213
  this.leftAxisLayer
7087
7214
  .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
@@ -7114,6 +7241,12 @@ else {
7114
7241
  .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
7115
7242
  this.trackingLineLayer
7116
7243
  .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
7244
+ this.brushLayer
7245
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop + this.plotHeight + longestBottomBounds.height})`)
7246
+ this.brushClip
7247
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop + this.plotHeight + longestBottomBounds.height})`)
7248
+ .attr('width', this.plotWidth)
7249
+ .attr('height', this.options.brushHeight)
7117
7250
  this.eventLayer
7118
7251
  .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
7119
7252
  let that = this
@@ -7125,16 +7258,113 @@ else {
7125
7258
  .attr('fill-opacity', '0')
7126
7259
  // this.tooltip.transform(this.options.margin.left + this.options.margin.axisLeft, this.options.margin.top + this.options.margin.axisTop)
7127
7260
  // Configure the bottom axis
7128
- let bottomDomain = this.createDomain('bottom')
7261
+ let bottomDomain = this.createDomain('bottom')
7262
+ let bottomBrushDomain = this.createDomain('bottom', true)
7129
7263
  this.bottomAxis = d3[`scale${this.options.data.bottom.scale || 'Band'}`]()
7130
7264
  .domain(bottomDomain)
7131
- .range([0, this.plotWidth])
7265
+ .range([0, this.plotWidth])
7266
+ if (!this.brushInitialized) {
7267
+ this.bottomBrushAxis = d3[`scale${this.options.data.bottom.scale || 'Band'}`]()
7268
+ .domain(bottomBrushDomain)
7269
+ .range([0, this.plotWidth])
7270
+ }
7132
7271
  if (this.bottomAxis.nice) {
7133
7272
  // this.bottomAxis.nice()
7134
7273
  }
7135
7274
  if (this.bottomAxis.padding && this.options.data.bottom.padding) {
7136
7275
  this.bottomAxis.padding(this.options.data.bottom.padding || 0)
7137
7276
  }
7277
+ // BRUSH
7278
+ let brushMethod = `brushX`
7279
+ let brushLength = this.plotWidth
7280
+ let brushEnd = this.plotWidth
7281
+ let brushThickness = this.options.brushHeight
7282
+ if (this.options.orientation === 'horizontal') {
7283
+ brushMethod = 'brushY'
7284
+ brushLength = this.options.brushHeight
7285
+ brushThickness = this.plotHeight
7286
+ }
7287
+ else {
7288
+ if (brushLength / bottomDomain.length < this.options.minBandWidth) {
7289
+ brushEnd = this.plotWidth * ((this.plotWidth / this.options.minBandWidth) / bottomDomain.length)
7290
+ }
7291
+ }
7292
+ this.brush = d3[brushMethod]()
7293
+ .extent([
7294
+ [0, 0],
7295
+ [brushLength, brushThickness]
7296
+ ])
7297
+ .on('brush end', this.brushed)
7298
+ const brushResizePath = d => {
7299
+ let e = +(d.type === 'e')
7300
+ let x = e ? 1 : -1
7301
+ let y = this.options.brushHeight
7302
+ return (
7303
+ 'M' +
7304
+ 0.5 * x +
7305
+ ',' +
7306
+ y +
7307
+ 'A6,6 0 0 ' +
7308
+ e +
7309
+ ' ' +
7310
+ 6.5 * x +
7311
+ ',' +
7312
+ (y + 6) +
7313
+ 'V' +
7314
+ (2 * y - 6) +
7315
+ 'A6,6 0 0 ' +
7316
+ e +
7317
+ ' ' +
7318
+ 0.5 * x +
7319
+ ',' +
7320
+ 2 * y +
7321
+ 'Z' +
7322
+ 'M' +
7323
+ 2.5 * x +
7324
+ ',' +
7325
+ (y + 8) +
7326
+ 'V' +
7327
+ (2 * y - 8) +
7328
+ 'M' +
7329
+ 4.5 * x +
7330
+ ',' +
7331
+ (y + 8) +
7332
+ 'V' +
7333
+ (2 * y - 8)
7334
+ )
7335
+ }
7336
+ this.brushHandle = this.brushLayer
7337
+ .select('.brush')
7338
+ .selectAll('.handle--custom')
7339
+ .remove()
7340
+ this.brushHandle = this.brushLayer
7341
+ .select('.brush')
7342
+ .selectAll('.handle--custom')
7343
+ .data([{ type: 'w' }, { type: 'e' }])
7344
+ .enter()
7345
+ .append('path')
7346
+ .attr('class', 'handle--custom')
7347
+ .attr('stroke', 'transparent')
7348
+ .attr('fill', 'transparent')
7349
+ .attr('cursor', 'ew-resize')
7350
+ .attr('d', brushResizePath)
7351
+ // BRUSH END
7352
+ // this.brushArea.selectAll('*').remove()
7353
+ if (this.brushNeeded) {
7354
+ if (!this.brushInitialized) {
7355
+ this.brushLayer.style('visibility', 'visible')
7356
+ this.brushInitialized = true
7357
+ this.brushLayer
7358
+ .select('.brush')
7359
+ .call(this.brush)
7360
+ .call(this.brush.move, [0, brushEnd])
7361
+ }
7362
+ }
7363
+ else {
7364
+ this.brushLayer.style('visibility', 'hidden')
7365
+ // this.brushLayer.selectAll().remove()
7366
+ this.brushArea.selectAll('*').remove()
7367
+ }
7138
7368
  if (this.options.margin.axisBottom > 0) {
7139
7369
  let timeFormatPattern = ''
7140
7370
  let tickDefinition
@@ -7195,15 +7425,12 @@ else {
7195
7425
  tickDefinition = this.options.data.bottom.ticks || 5
7196
7426
  }
7197
7427
  this.options.calculatedTimeFormatPattern = timeFormatPattern
7198
- let bAxisFunc = d3.axisBottom(this.bottomAxis)
7199
- // .ticks(this.options.data.bottom.ticks || Math.min(this.options.data.bottom.data.length, 5))
7200
- .ticks(tickDefinition)
7201
- // console.log('tickDefinition', tickDefinition)
7202
- // console.log(bAxisFunc)
7428
+ this.bAxisFunc = d3.axisBottom(this.bottomAxis)
7429
+ .ticks(tickDefinition)
7203
7430
  if (this.options.data.bottom.formatter) {
7204
- bAxisFunc.tickFormat(d => this.options.data.bottom.formatter(d))
7431
+ this.bAxisFunc.tickFormat(d => this.options.data.bottom.formatter(d))
7205
7432
  }
7206
- this.bottomAxisLayer.call(bAxisFunc)
7433
+ this.bottomAxisLayer.call(this.bAxisFunc)
7207
7434
  // console.log(this.bottomAxisLayer.ticks)
7208
7435
  if (this.options.data.bottom.rotate) {
7209
7436
  this.bottomAxisLayer.selectAll('text')
@@ -7213,11 +7440,15 @@ else {
7213
7440
  }
7214
7441
  }
7215
7442
  // Configure the left axis
7216
- let leftDomain = this.createDomain('left')
7443
+ let leftDomain = this.createDomain('left')
7444
+ let leftBrushDomain = this.createDomain('left', true)
7217
7445
  let rightDomain = this.createDomain('right')
7218
7446
  this.leftAxis = d3[`scale${this.options.data.left.scale || 'Linear'}`]()
7219
7447
  .domain(leftDomain)
7220
7448
  .range([this.plotHeight, 0])
7449
+ this.leftBrushAxis = d3[`scale${this.options.data.left.scale || 'Linear'}`]()
7450
+ .domain(leftBrushDomain)
7451
+ .range([this.options.brushHeight, 0])
7221
7452
  if (this.leftAxis.padding && this.options.data.left.padding) {
7222
7453
  this.leftAxis.padding(this.options.data.left.padding || 0)
7223
7454
  }
@@ -7286,7 +7517,7 @@ else {
7286
7517
  if (this.options.margin.axisRight > 0 && (this.options.data.right.min !== 0 || this.options.data.right.max !== 0)) {
7287
7518
  this.rightAxisLayer.call(
7288
7519
  d3.axisRight(this.rightAxis)
7289
- .ticks(this.options.data.left.ticks || 5)
7520
+ .ticks(this.options.data.right.ticks || 5)
7290
7521
  .tickFormat(d => {
7291
7522
  if (this.options.data.right.formatter) {
7292
7523
  d = this.options.data.right.formatter(d)
@@ -7333,25 +7564,29 @@ else {
7333
7564
  this[`remove${this.renderedKeys[key]}`](key)
7334
7565
  }
7335
7566
  }
7336
- // Draw the series data
7337
- this.renderedKeys = {}
7338
- this.options.data.series.forEach((series, index) => {
7339
- if (!series.key) {
7340
- series.key = this.createIdentity()
7341
- }
7342
- if (!series.color) {
7343
- series.color = this.options.colors[index % this.options.colors.length]
7344
- }
7345
- this[`render${series.type || 'bar'}`](series, index)
7346
- this.renderLabels(series, index)
7347
- this.renderedKeys[series.key] = series.type
7348
- })
7349
- if (this.options.refLines && this.options.refLines.length > 0) {
7350
- this.options.refLines.forEach(l => this.renderRefLine(l))
7351
- }
7567
+ this.renderComponents()
7352
7568
  }
7353
7569
  }
7354
7570
 
7571
+ }
7572
+ renderComponents () {
7573
+ // Draw the series data
7574
+ this.renderedKeys = {}
7575
+ this.options.data.series.forEach((series, index) => {
7576
+ if (!series.key) {
7577
+ series.key = this.createIdentity()
7578
+ }
7579
+ if (!series.color) {
7580
+ series.color = this.options.colors[index % this.options.colors.length]
7581
+ }
7582
+ this[`render${series.type || 'bar'}`](series, index)
7583
+ this.renderLabels(series, index)
7584
+ this.renderedKeys[series.key] = series.type
7585
+ })
7586
+ if (this.options.refLines && this.options.refLines.length > 0) {
7587
+ this.options.refLines.forEach(l => this.renderRefLine(l))
7588
+ }
7589
+
7355
7590
  }
7356
7591
  renderarea (series, index) {
7357
7592
  /* global d3 series index */
@@ -7410,74 +7645,111 @@ areas.enter().append('path')
7410
7645
  let xAxis = 'bottom'
7411
7646
  let yAxis = 'left'
7412
7647
  let bars = this.barLayer.selectAll(`.bar_${series.key}`).data(series.data)
7648
+ let brushBars = this.brushArea.selectAll(`.bar_${series.key}`).data(series.data)
7413
7649
  let acummulativeY = new Array(this.options.data.series.length).fill(0)
7414
7650
  if (this.options.orientation === 'horizontal') {
7415
7651
  xAxis = 'left'
7416
7652
  yAxis = 'bottom'
7417
7653
  }
7418
- let barWidth = this[`${xAxis}Axis`].bandwidth()
7419
- let groupedBarWidth = (barWidth - 10) / this.options.data.series.length
7420
7654
  // if (this.options.data.series.length > 1 && this.options.grouping === 'grouped') {
7421
7655
  // barWidth = barWidth / this.options.data.series.length - 4
7422
7656
  // }
7423
- function getBarHeight (d, i) {
7657
+ function getBarHeight (d, i, heightBounds, yAxis, xAxis) {
7658
+ let barWidth = this[`${xAxis}Axis`].bandwidth()
7659
+ let groupedBarWidth = (barWidth - 10) / this.options.data.series.length
7660
+ let output
7424
7661
  if (this.options.orientation === 'horizontal') {
7425
- return barWidth
7662
+ output = barWidth
7426
7663
  }
7427
7664
  else {
7428
- return this[`${yAxis}Axis`](d.y.value)
7665
+ if (!getBarX.call(this, d, i, xAxis)) {
7666
+ return null
7667
+ }
7668
+ output = (this[`${yAxis}Axis`](0)) - this[`${yAxis}Axis`](Math.abs(d.y.value))
7669
+ }
7670
+ if (isNaN(output)) {
7671
+ return null
7429
7672
  }
7673
+ return output
7430
7674
  }
7431
- function getBarWidth (d, i) {
7675
+ function getBarWidth (d, i, xAxis) {
7676
+ let barWidth = this[`${xAxis}Axis`].bandwidth()
7677
+ let groupedBarWidth = (barWidth - (xAxis.indexOf('Brush') === -1 ? 10 : 2)) / this.options.data.series.length
7678
+ let output
7432
7679
  if (this.options.orientation === 'horizontal') {
7433
7680
  let width = this[`${yAxis}Axis`](d.y.value)
7434
7681
  acummulativeY[d.y.index] += width
7435
- return width
7682
+ output = Math.max(1, width)
7436
7683
  }
7437
7684
  else {
7685
+ if (!getBarX.call(this, d, i, xAxis)) {
7686
+ return null
7687
+ }
7438
7688
  if (this.options.grouping === 'grouped') {
7439
- return groupedBarWidth
7689
+ output = Math.max(1, groupedBarWidth)
7690
+ }
7691
+ else {
7692
+ output = Math.max(1, barWidth)
7440
7693
  }
7441
- return barWidth
7442
7694
  }
7695
+ if (isNaN(output)) {
7696
+ return 0
7697
+ }
7698
+ return output
7443
7699
  }
7444
- function getBarX (d, i) {
7700
+ function getBarX (d, i, xAxis) {
7701
+ let barWidth = this[`${xAxis}Axis`].bandwidth()
7702
+ let groupedBarWidth = (barWidth - (xAxis.indexOf('Brush') === -1 ? 10 : 2)) / this.options.data.series.length
7703
+ let output
7445
7704
  if (this.options.orientation === 'horizontal') {
7446
7705
  if (this.options.grouping === 'stacked') {
7447
- return this[`${yAxis}Axis`](d.y.accumulative)
7706
+ output = this[`${yAxis}Axis`](d.y.accumulative)
7448
7707
  }
7449
7708
  else {
7450
- return 0
7709
+ output = 0
7451
7710
  }
7452
7711
  }
7453
7712
  else {
7454
- let adjustment = this.options.data[xAxis].scale === 'Time' ? 0 : this[`${xAxis}Axis`].bandwidth() / 2
7713
+ let adjustment = this.options.data[xAxis.replace('Brush', '')].scale === 'Time' ? 0 : this[`${xAxis}Axis`].bandwidth() / 2
7455
7714
  if (this.options.grouping === 'grouped') {
7456
- let barAdjustment = groupedBarWidth * index + 5 // + (index > 0 ? 4 : 0)
7457
- return this[`${xAxis}Axis`](this.parseX(d.x.value)) + barAdjustment
7715
+ let barAdjustment = groupedBarWidth * index + (xAxis.indexOf('Brush') === -1 ? 5 : 1) // + (index > 0 ? 4 : 0)
7716
+ output = this[`${xAxis}Axis`](this.parseX(d.x.value)) + barAdjustment
7458
7717
  }
7459
7718
  else {
7460
- return this[`${xAxis}Axis`](this.parseX(d.x.value)) + (i * barWidth) + adjustment
7719
+ // output = this[`${xAxis}Axis`](this.parseX(d.x.value)) + (i * barWidth) + adjustment
7720
+ output = this[`${xAxis}Axis`](this.parseX(d.x.value)) // + (i * barWidth)
7461
7721
  }
7462
7722
  }
7723
+ if (isNaN(output)) {
7724
+ return null
7725
+ }
7726
+ return output
7463
7727
  }
7464
- function getBarY (d, i) {
7728
+ function getBarY (d, i, heightBounds, yAxis, xAxis) {
7729
+ let barWidth = this[`${xAxis}Axis`].bandwidth()
7730
+ let groupedBarWidth = (barWidth - 10) / this.options.data.series.length
7731
+ let output
7465
7732
  if (this.options.orientation === 'horizontal') {
7466
7733
  if (this.options.grouping !== 'grouped') {
7467
- return this[`${xAxis}Axis`](this.parseX(d.x.value))
7734
+ output = this[`${xAxis}Axis`](this.parseX(d.x.value))
7468
7735
  }
7469
7736
  else {
7470
- return this[`${xAxis}Axis`](this.parseX(d.x.value)) + ((d.y.index || i) * barWidth)
7737
+ output = this[`${xAxis}Axis`](this.parseX(d.x.value)) + ((d.y.index || i) * barWidth)
7471
7738
  }
7472
7739
  }
7473
7740
  else {
7474
7741
  if (this.options.grouping === 'stacked') {
7475
- return this[`${yAxis}Axis`](d.y.accumulative)
7742
+ output = heightBounds - this[`${yAxis}Axis`](d.y.accumulative)
7476
7743
  }
7477
7744
  else {
7478
- return this.plotHeight - getBarHeight.call(this, d, i)
7745
+ let h = getBarHeight.call(this, d, i, heightBounds, yAxis, xAxis)
7746
+ output = (this[`${yAxis}Axis`](0)) - (h * (d.y.value < 0 ? 0 : 1))
7479
7747
  }
7480
7748
  }
7749
+ if (isNaN(output)) {
7750
+ return null
7751
+ }
7752
+ return output
7481
7753
  }
7482
7754
  bars
7483
7755
  .exit()
@@ -7486,26 +7758,56 @@ bars
7486
7758
  .remove()
7487
7759
 
7488
7760
  bars
7489
- .attr('width', getBarWidth.bind(this))
7490
- .attr('height', getBarHeight.bind(this))
7491
- .attr('x', getBarX.bind(this))
7492
- .attr('y', getBarY.bind(this))
7493
- .transition(this.transition)
7761
+ .attr('width', (d, i) => getBarWidth.call(this, d, i, xAxis))
7762
+ .attr('height', (d, i) => getBarHeight.call(this, d, i, this.plotHeight, yAxis, xAxis))
7763
+ .attr('x', (d, i) => getBarX.call(this, d, i, xAxis))
7764
+ .attr('y', (d, i) => getBarY.call(this, d, i, this.plotHeight, yAxis, xAxis))
7765
+ // .transition(this.transition)
7494
7766
  .attr('fill', d => d.y.color || d.color || series.color)
7495
7767
 
7496
7768
  bars
7497
7769
  .enter()
7498
7770
  .append('rect')
7499
- .attr('width', getBarWidth.bind(this))
7500
- .attr('height', getBarHeight.bind(this))
7501
- .attr('x', getBarX.bind(this))
7502
- .attr('y', getBarY.bind(this))
7771
+ .attr('width', (d, i) => getBarWidth.call(this, d, i, xAxis))
7772
+ .attr('height', (d, i) => getBarHeight.call(this, d, i, this.plotHeight, yAxis, xAxis))
7773
+ .attr('x', (d, i) => getBarX.call(this, d, i, xAxis))
7774
+ .attr('y', (d, i) => getBarY.call(this, d, i, this.plotHeight, yAxis, xAxis))
7503
7775
  // .transition(this.transition)
7504
7776
  .attr('fill', d => d.y.color || d.color || series.color)
7505
7777
  .attr('class', d => {
7506
7778
  return `bar bar_${series.key}`
7507
7779
  })
7508
7780
 
7781
+ if (!this.brushBarsInitialized[series.key]) {
7782
+ this.brushBarsInitialized[series.key] = true
7783
+ brushBars
7784
+ .exit()
7785
+ .transition(this.transition)
7786
+ .style('fill-opacity', 1e-6)
7787
+ .remove()
7788
+
7789
+ brushBars
7790
+ .attr('width', (d, i) => getBarWidth.call(this, d, i, `${xAxis}Brush`))
7791
+ .attr('height', (d, i) => getBarHeight.call(this, d, i, this.options.brushHeight, `${yAxis}Brush`, `${xAxis}Brush`))
7792
+ .attr('x', (d, i) => getBarX.call(this, d, i, `${xAxis}Brush`))
7793
+ .attr('y', (d, i) => getBarY.call(this, d, i, this.options.brushHeight, `${yAxis}Brush`, `${xAxis}Brush`))
7794
+ // .transition(this.transition)
7795
+ .attr('fill', d => d.y.color || d.color || series.color)
7796
+
7797
+ brushBars
7798
+ .enter()
7799
+ .append('rect')
7800
+ .attr('width', (d, i) => getBarWidth.call(this, d, i, `${xAxis}Brush`))
7801
+ .attr('height', (d, i) => getBarHeight.call(this, d, i, this.options.brushHeight, `${yAxis}Brush`, `${xAxis}Brush`))
7802
+ .attr('x', (d, i) => getBarX.call(this, d, i, `${xAxis}Brush`))
7803
+ .attr('y', (d, i) => getBarY.call(this, d, i, this.options.brushHeight, `${yAxis}Brush`, `${xAxis}Brush`))
7804
+ // .transition(this.transition)
7805
+ .attr('fill', d => d.y.color || d.color || series.color)
7806
+ .attr('class', d => {
7807
+ return `bar bar_${series.key}`
7808
+ })
7809
+ }
7810
+
7509
7811
  }
7510
7812
  removebar (key) {
7511
7813
  /* global key d3 */
@@ -7650,7 +7952,7 @@ const drawLine = (xAxis, yAxis, curveStyle) => {
7650
7952
  return d3
7651
7953
  .line()
7652
7954
  .x(d => {
7653
- let adjustment = this.options.data[xAxis].scale === 'Time' ? 0 : this[`${xAxis}Axis`].bandwidth() / 2
7955
+ let adjustment = this.options.data[xAxis.replace('Brush', '')].scale === 'Time' ? 0 : this[`${xAxis}Axis`].bandwidth() / 2
7654
7956
  return this[`${xAxis}Axis`](this.parseX(d.x.value)) + adjustment
7655
7957
  })
7656
7958
  .y(d => {
@@ -7664,8 +7966,16 @@ if (this.options.orienation === 'horizontal') {
7664
7966
  xAxis = series.axis === 'secondary' ? 'right' : 'left'
7665
7967
  yAxis = 'bottom'
7666
7968
  }
7969
+ let xBrushAxis = 'bottomBrush'
7970
+ let yBrushAxis = 'leftBrush'
7971
+ if (this.options.orienation === 'horizontal') {
7972
+ xBrushAxis = 'leftBrush'
7973
+ yBrushAxis = 'bottomBrush'
7974
+ }
7667
7975
  let lines = this.lineLayer.selectAll(`.line_${series.key}`)
7668
7976
  .data([series.data])
7977
+ let brushLines = this.brushArea.selectAll(`.line_${series.key}`)
7978
+ .data([series.data])
7669
7979
  // Exit
7670
7980
  lines.exit()
7671
7981
  .transition(this.transition)
@@ -7692,6 +8002,35 @@ lines.enter().append('path')
7692
8002
  // .transition(this.transition)
7693
8003
  .style('stroke-opacity', 1)
7694
8004
 
8005
+ if (!this.brushLinesInitialized[series.key]) {
8006
+ this.brushLinesInitialized[series.key] = true
8007
+ // Exit
8008
+ brushLines.exit()
8009
+ .transition(this.transition)
8010
+ .style('stroke-opacity', 1e-6)
8011
+ .remove()
8012
+ // Update
8013
+ brushLines
8014
+ .style('stroke-width', 1)
8015
+ // .attr('id', `line_${series.key}`)
8016
+ // .attr('transform', 'translate('+ (that.bandWidth/2) +',0)')
8017
+ .attr('stroke', series.color)
8018
+ .attr('fill', 'transparent')
8019
+ .transition(this.transition)
8020
+ .attr('d', d => drawLine(xBrushAxis, yBrushAxis, series.curveStyle)(d))
8021
+ // Enter
8022
+ brushLines.enter().append('path')
8023
+ .attr('d', d => drawLine(xBrushAxis, yBrushAxis, series.curveStyle)(d))
8024
+ .attr('class', `line_${series.key}`)
8025
+ .attr('id', `line_${series.key}`)
8026
+ // .attr('transform', 'translate('+ (that.bandWidth/2) +',0)')
8027
+ .style('stroke-width', 1)
8028
+ .attr('stroke', series.color)
8029
+ .attr('fill', 'transparent')
8030
+ // .transition(this.transition)
8031
+ .style('stroke-opacity', 1)
8032
+ }
8033
+
7695
8034
  if (series.showArea === true) {
7696
8035
  this.renderarea(series, index)
7697
8036
  }
@@ -7895,6 +8234,44 @@ if (el) {
7895
8234
  }
7896
8235
 
7897
8236
  }
8237
+ hideError () {
8238
+ const el = document.getElementById(`${this.elementId}`)
8239
+ if (el) {
8240
+ el.classList.remove('has-error')
8241
+ }
8242
+ // const chartEl = document.getElementById(`${this.elementId}_chartContainer`)
8243
+ // chartEl.classList.remove('hidden')
8244
+ this.svg.classed('hidden', false)
8245
+ const containerEl = document.getElementById(`${this.elementId}_errorContainer`)
8246
+ if (containerEl) {
8247
+ containerEl.classList.remove('active')
8248
+ }
8249
+ }
8250
+ showError (options) {
8251
+ const el = document.getElementById(`${this.elementId}`)
8252
+ if (el) {
8253
+ el.classList.add('has-error')
8254
+ }
8255
+ // const chartEl = document.getElementById(`${this.elementId}_chartContainer`)
8256
+ // chartEl.classList.add('hidden')
8257
+ this.svg.classed('hidden', true)
8258
+ const containerEl = document.getElementById(`${this.elementId}_errorContainer`)
8259
+ if (containerEl) {
8260
+ containerEl.classList.add('active')
8261
+ }
8262
+ if (options.title) {
8263
+ const titleEl = document.getElementById(`${this.elementId}_errorTitle`)
8264
+ if (titleEl) {
8265
+ titleEl.innerHTML = options.title
8266
+ }
8267
+ }
8268
+ if (options.message) {
8269
+ const messageEl = document.getElementById(`${this.elementId}_errorMessage`)
8270
+ if (messageEl) {
8271
+ messageEl.innerHTML = options.message
8272
+ }
8273
+ }
8274
+ }
7898
8275
  }
7899
8276
 
7900
8277
  class WebsyLegend {