@websy/websy-designs 1.7.19 → 1.8.0

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.
@@ -15,6 +15,7 @@
15
15
  WebsyIcons
16
16
  WebsyChart
17
17
  WebsyChartTooltip
18
+ WebsyPie
18
19
  WebsyLegend
19
20
  WebsyMap
20
21
  WebsyKPI
@@ -2174,8 +2175,8 @@ class WebsyDragDrop {
2174
2175
  el.innerHTML = html
2175
2176
  this.options.items.forEach((item, i) => {
2176
2177
  if (item.component) {
2177
- if (item.isQlikPlugin && WebsyDesigns.QlikPlugin[item.component]) {
2178
- item.instance = new WebsyDesigns.QlikPlugin[item.component](`${item.id}_component`, item.options)
2178
+ if (item.isQlikPlugin && WebsyDesigns.QlikPlugins[item.component]) {
2179
+ item.instance = new WebsyDesigns.QlikPlugins[item.component](`${item.id}_component`, item.options)
2179
2180
  }
2180
2181
  else if (WebsyDesigns[item.component]) {
2181
2182
  item.instance = new WebsyDesigns[item.component](`${item.id}_component`, item.options)
@@ -5065,11 +5066,21 @@ class Switch {
5065
5066
  }
5066
5067
  disable () {
5067
5068
  this.options.enabled = false
5068
- this.render()
5069
+ let method = this.options.enabled === true ? 'add' : 'remove'
5070
+ const el = document.getElementById(`${this.elementId}_switch`)
5071
+ el.classList[method]('enabled')
5072
+ if (this.options.onToggle) {
5073
+ this.options.onToggle(this.options.enabled)
5074
+ }
5069
5075
  }
5070
5076
  enable () {
5071
5077
  this.options.enabled = true
5072
- this.render()
5078
+ let method = this.options.enabled === true ? 'add' : 'remove'
5079
+ const el = document.getElementById(`${this.elementId}_switch`)
5080
+ el.classList[method]('enabled')
5081
+ if (this.options.onToggle) {
5082
+ this.options.onToggle(this.options.enabled)
5083
+ }
5073
5084
  }
5074
5085
  handleClick (event) {
5075
5086
  this.options.enabled = !this.options.enabled
@@ -6456,7 +6467,7 @@ class WebsyTable3 {
6456
6467
  const el = document.getElementById(this.elementId)
6457
6468
  if (el) {
6458
6469
  let html = `
6459
- <div id='${this.elementId}_tableContainer' class='websy-vis-table-3 ${this.options.paging === 'pages' ? 'with-paging' : ''} ${this.options.virtualScroll === true ? 'with-virtual-scroll' : ''}'>
6470
+ <div id='${this.elementId}_tableContainer' class='websy-vis-table-3 ${this.options.paging === 'pages' ? 'with-paging' : ''} ${this.options.virtualScroll === true ? 'with-virtual-scroll' : ''} ${this.isTouchDevice === true && this.options.virtualScroll === true ? 'touch-device' : ''}'>
6460
6471
  <!--<div class="download-button">
6461
6472
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M16 11h5l-9 10-9-10h5v-11h8v11zm1 11h-10v2h10v-2z"/></svg>
6462
6473
  </div>-->
@@ -6886,8 +6897,8 @@ class WebsyTable3 {
6886
6897
  }
6887
6898
  this.sizes.rowsToRender = Math.ceil(this.sizes.bodyHeight / this.sizes.cellHeight)
6888
6899
  this.sizes.rowsToRenderPrecise = this.sizes.bodyHeight / this.sizes.cellHeight
6889
- this.startRow = 0
6890
- this.endRow = this.sizes.rowsToRender
6900
+ // this.startRow = 0
6901
+ this.endRow = this.startRow + this.sizes.rowsToRender
6891
6902
  this.startCol = 0
6892
6903
  this.endCol = this.options.columns[this.options.columns.length - 1].length
6893
6904
  if (this.sizes.rowsToRender < this.totalRowCount) {
@@ -6976,11 +6987,11 @@ class WebsyTable3 {
6976
6987
  }
6977
6988
  }
6978
6989
  }
6979
- handleMouseDown (event) {
6980
- if (this.isTouchDevice === true) {
6990
+ handleMouseDown (event) {
6991
+ if (this.isTouchDevice) {
6981
6992
  return
6982
6993
  }
6983
- if (event.target.classList.contains('websy-scroll-handle-y')) {
6994
+ if (event.target.classList.contains('websy-scroll-handle-y')) {
6984
6995
  // set up the scroll start values
6985
6996
  this.scrollDragging = true
6986
6997
  this.scrollDirection = 'y'
@@ -6991,6 +7002,9 @@ class WebsyTable3 {
6991
7002
  // console.log(scrollHandleEl.offsetTop)
6992
7003
  }
6993
7004
  else if (event.target.classList.contains('websy-scroll-handle-x')) {
7005
+ if (this.isTouchDevice) {
7006
+ event.preventDefault()
7007
+ }
6994
7008
  this.scrollDragging = true
6995
7009
  this.scrollDirection = 'x'
6996
7010
  const scrollHandleEl = document.getElementById(`${this.elementId}_hScrollHandle`)
@@ -6998,9 +7012,12 @@ class WebsyTable3 {
6998
7012
  this.mouseXStart = event.pageX
6999
7013
  }
7000
7014
  }
7001
- handleMouseMove (event) {
7015
+ handleMouseMove (event) {
7002
7016
  // event.preventDefault()
7003
7017
  if (this.scrollDragging === true) {
7018
+ if (this.isTouchDevice) {
7019
+ event.preventDefault()
7020
+ }
7004
7021
  if (this.scrollDirection === 'y') {
7005
7022
  const diff = event.pageY - this.mouseYStart
7006
7023
  this.scrollY(diff)
@@ -7060,12 +7077,18 @@ class WebsyTable3 {
7060
7077
  }
7061
7078
  handleTouchEnd (event) {
7062
7079
  // console.log('touch end fired')
7080
+ this.scrollDragging = false
7081
+ this.cellDragging = false
7082
+ this.handleYStart = null
7083
+ this.mouseYStart = null
7084
+ this.handleXStart = null
7085
+ this.mouseXStart = null
7063
7086
  if (typeof event.targetTouches !== 'undefined') {
7064
7087
  this.isTouchScrolling = false
7065
- this.touchEndTime = (new Date()).getTime()
7066
- this.isPerpetual = true
7088
+ // this.touchEndTime = (new Date()).getTime()
7089
+ // this.isPerpetual = true
7067
7090
  // this.perpetualScroll()
7068
- this.touchStartTime = null
7091
+ // this.touchStartTime = null
7069
7092
  // const touchScrollEl = document.getElementById(`${this.elementId}_touchScroller`)
7070
7093
  // touchScrollEl.classList.add('hidden')
7071
7094
  }
@@ -7076,47 +7099,68 @@ class WebsyTable3 {
7076
7099
  event.preventDefault()
7077
7100
  event.stopPropagation()
7078
7101
  if (typeof event.targetTouches !== 'undefined' && event.targetTouches.length > 0) {
7079
- let deltaX = (this.mouseXStart - event.targetTouches[0].pageX)
7080
- let deltaY = (this.mouseYStart - event.targetTouches[0].pageY)
7081
- const hScrollContainerEl = document.getElementById(`${this.elementId}_hScrollContainer`)
7082
- const vScrollContainerEl = document.getElementById(`${this.elementId}_vScrollContainer`)
7083
- const hScrollHandleEl = document.getElementById(`${this.elementId}_hScrollHandle`)
7084
- const vScrollHandleEl = document.getElementById(`${this.elementId}_vScrollHandle`)
7085
- let translatedDeltaX = deltaX * (hScrollHandleEl.getBoundingClientRect().width / vScrollContainerEl.getBoundingClientRect().width)
7086
- let translatedDeltaY = deltaY * (vScrollHandleEl.getBoundingClientRect().height / vScrollContainerEl.getBoundingClientRect().height)
7087
- // need to adjust the delta so that it scrolls at a reasonable speed/distance
7088
- const scrollHandleXEl = document.getElementById(`${this.elementId}_hScrollHandle`)
7089
- const scrollHandleYEl = document.getElementById(`${this.elementId}_vScrollHandle`)
7090
- // if (Math.abs(deltaY) > this.sizes.cellHeight) {
7091
- // this.isTouchScrolling = true
7092
- // }
7093
- // else {
7094
- // this.isTouchScrolling = false
7095
- // }
7096
- // console.log('delta', this.mouseYStart, event.targetTouches[0].pageY, deltaY)
7097
- // deltaX = deltaX * (scrollHandleXEl.offsetWidth / this.sizes.scrollableWidth)
7098
- // deltaY = deltaY * (scrollHandleYEl.offsetHeight / this.sizes.bodyHeight)
7099
- // console.log('delta', deltaY)
7100
- // NW
7101
- // else if (Math.abs(deltaX) > 50) {
7102
- // this.isTouchScrolling = false
7103
- // }
7104
- this.currentClientY = event.targetTouches[0].pageY
7105
- this.currentTouchtime = (new Date()).getTime()
7106
- // end
7107
- // delta = Math.min(10, delta)
7108
- // delta = Math.max(-10, delta)
7109
- if (this.isTouchScrolling === true) {
7110
- // this.$scope.scrollTop += (delta / (this.$scope.layout.qHyperCube.qSize.qcy / this.$scope.rowsToLoad / (this.$scope.totalSpaceAvailable / 250)))
7111
- if (Math.abs(deltaX) > Math.abs(deltaY) && deltaX > 20) {
7112
- // this.scrollX(Math.max(-5, Math.min(5, translatedDeltaX)))
7113
- this.scrollX(translatedDeltaX)
7114
- }
7115
- else if (deltaY > 20) {
7116
- // this.scrollY(Math.max(-5, Math.min(5, translatedDeltaY)))
7117
- this.scrollY(translatedDeltaY)
7118
- }
7119
- }
7102
+ event.deltaX = this.touchXStart - event.targetTouches[0].pageX
7103
+ event.deltaY = this.touchYStart - event.targetTouches[0].pageY
7104
+ if (Math.abs(event.deltaY) > 50) {
7105
+ event.deltaX = 0
7106
+ this.handleScrollWheel(event)
7107
+ }
7108
+ else if (Math.abs(event.deltaX) > 50) {
7109
+ event.deltaY = 0
7110
+ this.handleScrollWheel(event)
7111
+ }
7112
+ // let deltaX = (this.mouseXStart - event.targetTouches[0].pageX)
7113
+ // let deltaY = (this.mouseYStart - event.targetTouches[0].pageY)
7114
+ // const hScrollContainerEl = document.getElementById(`${this.elementId}_hScrollContainer`)
7115
+ // const vScrollContainerEl = document.getElementById(`${this.elementId}_vScrollContainer`)
7116
+ // const hScrollHandleEl = document.getElementById(`${this.elementId}_hScrollHandle`)
7117
+ // const vScrollHandleEl = document.getElementById(`${this.elementId}_vScrollHandle`)
7118
+ // let translatedDeltaX = deltaX * (hScrollHandleEl.getBoundingClientRect().width / vScrollContainerEl.getBoundingClientRect().width)
7119
+ // let translatedDeltaY = deltaY * (vScrollHandleEl.getBoundingClientRect().height / vScrollContainerEl.getBoundingClientRect().height)
7120
+ // // need to adjust the delta so that it scrolls at a reasonable speed/distance
7121
+ // const scrollHandleXEl = document.getElementById(`${this.elementId}_hScrollHandle`)
7122
+ // const scrollHandleYEl = document.getElementById(`${this.elementId}_vScrollHandle`)
7123
+ // // if (Math.abs(deltaY) > this.sizes.cellHeight) {
7124
+ // // this.isTouchScrolling = true
7125
+ // // }
7126
+ // // else {
7127
+ // // this.isTouchScrolling = false
7128
+ // // }
7129
+ // // console.log('delta', this.mouseYStart, event.targetTouches[0].pageY, deltaY)
7130
+ // // deltaX = deltaX * (scrollHandleXEl.offsetWidth / this.sizes.scrollableWidth)
7131
+ // // deltaY = deltaY * (scrollHandleYEl.offsetHeight / this.sizes.bodyHeight)
7132
+ // // console.log('delta', deltaY)
7133
+ // // NW
7134
+ // // else if (Math.abs(deltaX) > 50) {
7135
+ // // this.isTouchScrolling = false
7136
+ // // }
7137
+ // this.currentClientY = event.targetTouches[0].pageY
7138
+ // this.currentTouchtime = (new Date()).getTime()
7139
+ // // end
7140
+ // // delta = Math.min(10, delta)
7141
+ // // delta = Math.max(-10, delta)
7142
+ // if (this.isTouchScrolling === true) {
7143
+ // // this.$scope.scrollTop += (delta / (this.$scope.layout.qHyperCube.qSize.qcy / this.$scope.rowsToLoad / (this.$scope.totalSpaceAvailable / 250)))
7144
+ // if (Math.abs(deltaX) > Math.abs(deltaY) && deltaX > 20) {
7145
+ // // this.scrollX(Math.max(-5, Math.min(5, translatedDeltaX)))
7146
+ // this.scrollX(translatedDeltaX)
7147
+ // }
7148
+ // else if (deltaY > 20) {
7149
+ // // this.scrollY(Math.max(-5, Math.min(5, translatedDeltaY)))
7150
+ // this.scrollY(translatedDeltaY)
7151
+ // }
7152
+ // }
7153
+ }
7154
+ }
7155
+ if (this.scrollDragging === true) {
7156
+ event.preventDefault()
7157
+ if (this.scrollDirection === 'y') {
7158
+ const diff = event.targetTouches[0].pageY - this.mouseYStart
7159
+ this.scrollY(diff)
7160
+ }
7161
+ else if (this.scrollDirection === 'x') {
7162
+ const diff = event.targetTouches[0].pageX - this.mouseXStart
7163
+ this.scrollX(diff)
7120
7164
  }
7121
7165
  }
7122
7166
  }
@@ -7128,19 +7172,42 @@ class WebsyTable3 {
7128
7172
  return
7129
7173
  }
7130
7174
  // console.log(event.target.classList)
7131
- if (this.options.virtualScroll === true) {
7132
- this.touchStartTime = (new Date()).getTime()
7133
- this.isTouchScrolling = true
7134
- this.isPerpetual = false
7175
+ if (event.target.classList.contains('websy-table-touch-scroller')) {
7176
+ if (this.options.virtualScroll === true) {
7177
+ // this.touchStartTime = (new Date()).getTime()
7178
+ this.isTouchScrolling = true
7179
+ // this.isPerpetual = false
7180
+ this.touchYStart = event.targetTouches[0].pageY
7181
+ this.touchXStart = event.targetTouches[0].pageX
7182
+ }
7183
+ }
7184
+ if (event.target.classList.contains('websy-scroll-handle-y')) {
7185
+ // set up the scroll start values
7186
+ this.scrollDragging = true
7187
+ this.scrollDirection = 'y'
7188
+ const scrollHandleEl = document.getElementById(`${this.elementId}_vScrollHandle`)
7189
+ this.handleYStart = scrollHandleEl.offsetTop
7135
7190
  this.mouseYStart = event.targetTouches[0].pageY
7136
- this.mouseXStart = event.targetTouches[0].pageX
7137
- // const touchScrollEl = document.getElementById(`${this.elementId}_touchScroller`)
7138
- // touchScrollEl.classList.remove('hidden')
7139
- const handleYEl = document.getElementById(`${this.elementId}_vScrollHandle`)
7140
- this.handleYStart = handleYEl.offsetTop
7141
- const handleXEl = document.getElementById(`${this.elementId}_hScrollHandle`)
7142
- this.handleXStart = handleXEl.offsetLeft
7143
- }
7191
+ // console.log('mouse down', this.handleYStart, this.mouseYStart)
7192
+ // console.log(scrollHandleEl.offsetTop)
7193
+ }
7194
+ else if (event.target.classList.contains('websy-scroll-handle-x')) {
7195
+ if (this.isTouchDevice) {
7196
+ event.preventDefault()
7197
+ }
7198
+ this.scrollDragging = true
7199
+ this.scrollDirection = 'x'
7200
+ const scrollHandleEl = document.getElementById(`${this.elementId}_hScrollHandle`)
7201
+ this.handleXStart = scrollHandleEl.offsetLeft
7202
+ this.mouseXStart = event.targetTouches[0].pageX
7203
+ }
7204
+ // // const touchScrollEl = document.getElementById(`${this.elementId}_touchScroller`)
7205
+ // // touchScrollEl.classList.remove('hidden')
7206
+ // const handleYEl = document.getElementById(`${this.elementId}_vScrollHandle`)
7207
+ // this.handleYStart = handleYEl.offsetTop
7208
+ // const handleXEl = document.getElementById(`${this.elementId}_hScrollHandle`)
7209
+ // this.handleXStart = handleXEl.offsetLeft
7210
+ // }
7144
7211
  }
7145
7212
  hideError () {
7146
7213
  const el = document.getElementById(`${this.elementId}_tableContainer`)
@@ -7241,6 +7308,10 @@ class WebsyTable3 {
7241
7308
  vScrollEl.style.top = `${this.sizes.header.height + this.sizes.total.height}px`
7242
7309
  vScrollEl.style.height = `${this.sizes.bodyHeight}px`
7243
7310
  vHandleEl.style.height = Math.max(this.options.minHandleSize, this.sizes.bodyHeight * (this.sizes.rowsToRenderPrecise / this.totalRowCount)) + 'px'
7311
+ if (this.startRow !== 0) {
7312
+ const scrollableSpace = vScrollEl.getBoundingClientRect().height - vHandleEl.getBoundingClientRect().height
7313
+ vHandleEl.style.top = Math.round(this.startRow / (this.totalRowCount - this.sizes.rowsToRender) * (scrollableSpace)) + 'px'
7314
+ }
7244
7315
  }
7245
7316
  else {
7246
7317
  vHandleEl.style.height = '0px'
@@ -7249,7 +7320,7 @@ class WebsyTable3 {
7249
7320
  let hHandleEl = document.getElementById(`${this.elementId}_hScrollHandle`)
7250
7321
  if (this.hScrollRequired === true) {
7251
7322
  hScrollEl.style.left = `${this.sizes.table.width - this.sizes.scrollableWidth}px`
7252
- hScrollEl.style.width = `${this.sizes.scrollableWidth - 20}px`
7323
+ hScrollEl.style.width = `${this.sizes.scrollableWidth - (this.isTouchDevice ? 30 : 20)}px`
7253
7324
  hHandleEl.style.width = Math.max(this.options.minHandleSize, this.sizes.scrollableWidth * (this.sizes.scrollableWidth / this.sizes.totalNonPinnedWidth)) + 'px'
7254
7325
  }
7255
7326
  else {
@@ -7397,7 +7468,7 @@ class WebsyTable3 {
7397
7468
  if (this.endRow === this.totalRowCount) {
7398
7469
  this.startRow += 1
7399
7470
  }
7400
- this.options.onScroll('y', this.startRow, this.endRow, this.startCol - this.pinnedColumns, this.endCol - this.pinnedColumns)
7471
+ this.options.onScroll('y', this.startRow, this.endRow, Math.max(0, this.startCol - this.pinnedColumns), this.endCol - this.pinnedColumns)
7401
7472
  }
7402
7473
  }
7403
7474
  showLoading (options) {
@@ -9087,7 +9158,12 @@ if (!this.brushBarsInitialized[series.key]) {
9087
9158
  }
9088
9159
  removebar (key) {
9089
9160
  /* global key d3 */
9090
- let bars = this.barLayer.selectAll(`.bar_${key}`)
9161
+ this.barLayer.selectAll(`.bar_${key}`)
9162
+ .transition(this.transition)
9163
+ .style('fill-opacity', 1e-6)
9164
+ .remove()
9165
+ // remove from the brush as well
9166
+ this.brushArea.selectAll(`.bar_${key}`)
9091
9167
  .transition(this.transition)
9092
9168
  .style('fill-opacity', 1e-6)
9093
9169
  .remove()
@@ -9669,6 +9745,434 @@ if (el) {
9669
9745
  }
9670
9746
  }
9671
9747
 
9748
+ /* global include */
9749
+ class WebsyPie {
9750
+ constructor (elementId, options) {
9751
+ this.elementId = elementId
9752
+ const DEFAULTS = {
9753
+ labelMode: 'auto',
9754
+ labelLocs: [],
9755
+ showLabels: false,
9756
+ segments: [
9757
+ '#9dbca6',
9758
+ '#e3c080',
9759
+ '#fd7336',
9760
+ '#b12737',
9761
+ '#50424b'
9762
+ ],
9763
+ label: {
9764
+ value: {
9765
+ size: '12px',
9766
+ colour: '#BBB',
9767
+ family: 'arial',
9768
+ weight: 'normal'
9769
+ },
9770
+ label: {
9771
+ size: '10px',
9772
+ colour: '#888',
9773
+ family: 'arial',
9774
+ weight: 'normal'
9775
+ }
9776
+ },
9777
+ kpi: {
9778
+ background: '#555',
9779
+ value: {
9780
+ size: '60px',
9781
+ colour: '#CCC',
9782
+ family: 'arial',
9783
+ weight: 'bold'
9784
+ },
9785
+ label: {
9786
+ size: '20px',
9787
+ colour: '#FFF',
9788
+ family: 'arial',
9789
+ weight: 'normal'
9790
+ }
9791
+ }
9792
+ }
9793
+ this.options = Object.assign({}, DEFAULTS, options)
9794
+ this.listening = true
9795
+ if (!elementId) {
9796
+ console.log('No element Id provided for Websy Chart')
9797
+ return
9798
+ }
9799
+ const el = document.getElementById(this.elementId)
9800
+ if (el) {
9801
+ el.classList.add('websy-pie')
9802
+ }
9803
+ else {
9804
+ console.error(`No element found with ID ${this.elementId}`)
9805
+ }
9806
+ }
9807
+ calculateArcAngle (arcLength, radius) {
9808
+ return this.convertRadiansToDegrees(arcLength / (Math.PI * (2 * radius)))
9809
+ }
9810
+ calculateCircumference (perc) {
9811
+ return (Math.PI * 2) * (perc)
9812
+ }
9813
+ close () {
9814
+
9815
+ }
9816
+ convertDegreesToRadians (degrees) {
9817
+ return degrees * (Math.PI / 180)
9818
+ }
9819
+ convertRadiansToDegrees (radians) {
9820
+ return radians * (180 / Math.PI)
9821
+ }
9822
+ createCanvases (element) {
9823
+ /* global element */
9824
+ if (element && !element.target) {
9825
+ if (!this.listening) {
9826
+ // add event listeners to help with responsiveness
9827
+ element.addEventListener('resize', this.render.bind(this), false)
9828
+ window.addEventListener('resize', this.render.bind(this), false)
9829
+ this.listening = true
9830
+ }
9831
+ let height = element.clientHeight
9832
+ let width = element.clientWidth
9833
+ this.width = width
9834
+ this.height = height
9835
+ this.center = {
9836
+ x: (width / 2),
9837
+ y: (height / 2)
9838
+ }
9839
+ this.outerRadius = (Math.min(this.height, this.width) / 2) - 20
9840
+ console.log('radius is ' + this.outerRadius)
9841
+ // segment canvas
9842
+ const segmentCanvas = document.createElement('canvas')
9843
+ this.segmentPaper = {
9844
+ canvas: segmentCanvas,
9845
+ pen: segmentCanvas.getContext('2d')
9846
+ }
9847
+ this.segmentPaper.canvas.style.position = 'absolute'
9848
+ this.segmentPaper.canvas.style.top = '0px'
9849
+ this.segmentPaper.canvas.style.left = '0px'
9850
+ this.segmentPaper.canvas.style.zIndex = '5'
9851
+ this.segmentPaper.canvas.style.width = width + 'px'
9852
+ this.segmentPaper.canvas.style.height = height + 'px'
9853
+ // make the canvase size double to accommodate for retina displays
9854
+ this.segmentPaper.canvas.width = width * 2
9855
+ this.segmentPaper.canvas.height = height * 2
9856
+ this.segmentPaper.pen.scale(2, 2)
9857
+ element.appendChild(this.segmentPaper.canvas)
9858
+
9859
+ // label canvas
9860
+ const labelCanvas = document.createElement('canvas')
9861
+ this.labelPaper = {
9862
+ canvas: labelCanvas,
9863
+ pen: labelCanvas.getContext('2d')
9864
+ }
9865
+ this.labelPaper.canvas.style.position = 'absolute'
9866
+ this.labelPaper.canvas.style.top = '0px'
9867
+ this.labelPaper.canvas.style.left = '0px'
9868
+ this.labelPaper.canvas.style.zIndex = '5'
9869
+ this.labelPaper.canvas.style.width = width + 'px'
9870
+ this.labelPaper.canvas.style.height = height + 'px'
9871
+ // make the canvase size double to accommodate for retina displays
9872
+ this.labelPaper.canvas.width = width * 2
9873
+ this.labelPaper.canvas.height = height * 2
9874
+ this.labelPaper.pen.scale(2, 2)
9875
+ element.appendChild(this.labelPaper.canvas)
9876
+
9877
+ // kpi canvas
9878
+ const kpiCanvas = document.createElement('canvas')
9879
+ this.kpiPaper = {
9880
+ canvas: kpiCanvas,
9881
+ pen: kpiCanvas.getContext('2d')
9882
+ }
9883
+ this.kpiPaper.canvas.style.position = 'absolute'
9884
+ this.kpiPaper.canvas.style.top = '0px'
9885
+ this.kpiPaper.canvas.style.left = '0px'
9886
+ this.kpiPaper.canvas.style.zIndex = '5'
9887
+ this.kpiPaper.canvas.style.width = width + 'px'
9888
+ this.kpiPaper.canvas.style.height = height + 'px'
9889
+ // make the canvase size double to accommodate for retina displays
9890
+ this.kpiPaper.canvas.width = width * 2
9891
+ this.kpiPaper.canvas.height = height * 2
9892
+ this.kpiPaper.pen.scale(2, 2)
9893
+ element.appendChild(this.kpiPaper.canvas)
9894
+ }
9895
+ else {
9896
+ // clear the canvases
9897
+ this.segmentPaper.canvas.width = this.width * 2
9898
+ this.labelPaper.canvas.width = this.width * 2
9899
+ this.kpiPaper.canvas.width = this.width * 2
9900
+ }
9901
+
9902
+ }
9903
+ drawKPI () {
9904
+ let kpiStyleDefaults = this.options.kpi
9905
+ if (this.kpi) {
9906
+ // draw the circle for the background colour if one has been specified
9907
+ if (!this.kpi.background || this.kpi.background !== 'transparent') {
9908
+ this.kpiPaper.pen.beginPath()
9909
+ this.kpiPaper.pen.fillStyle = this.kpi.background || kpiStyleDefaults.background
9910
+ this.kpiPaper.pen.moveTo(this.center.x, this.center.y)
9911
+ this.kpiPaper.pen.arc(this.center.x, this.center.y, this.innerRadiusPixels + (5 * !this.addShading) + 1, 0, Math.PI * 2)
9912
+ this.kpiPaper.pen.fill()
9913
+ this.kpiPaper.pen.closePath()
9914
+ }
9915
+ // draw the kpi value
9916
+ if (this.kpi.value) {
9917
+ this.kpiPaper.pen.save()
9918
+ this.kpiPaper.pen.beginPath()
9919
+ this.kpiPaper.pen.moveTo(this.center.x, this.center.y)
9920
+ this.kpiPaper.pen.font = (this.kpi.value.weight || kpiStyleDefaults.value.weight) + ' ' + (this.kpi.value.size || kpiStyleDefaults.value.size) + ' ' + (this.kpi.value.family || kpiStyleDefaults.value.family)
9921
+ this.kpiPaper.pen.textAlign = 'center'
9922
+ if (this.kpi.label) {
9923
+ this.kpiPaper.pen.textBaseline = 'text-bottom'
9924
+ }
9925
+ else {
9926
+ this.kpiPaper.pen.textBaseline = 'middle'
9927
+ }
9928
+ this.kpiPaper.pen.fillStyle = this.kpi.value.colour || kpiStyleDefaults.value.colour
9929
+ this.kpiPaper.pen.fillText(this.kpi.value.text, this.center.x, this.center.y)
9930
+ this.kpiPaper.pen.closePath()
9931
+ this.kpiPaper.pen.restore()
9932
+ }
9933
+ // draw the kpi label
9934
+ if (this.kpi.label) {
9935
+ this.kpiPaper.pen.save()
9936
+ this.kpiPaper.pen.beginPath()
9937
+ this.kpiPaper.pen.moveTo(this.center.x, this.center.y)
9938
+ this.kpiPaper.pen.font = (this.kpi.label.weight || kpiStyleDefaults.label.weight) + ' ' + (this.kpi.label.size || kpiStyleDefaults.label.size) + ' ' + (this.kpi.label.family || kpiStyleDefaults.label.family)
9939
+ this.kpiPaper.pen.textAlign = 'center'
9940
+ if (this.kpi.value) {
9941
+ this.kpiPaper.pen.textBaseline = 'top'
9942
+ }
9943
+ else {
9944
+ this.kpiPaper.pen.textBaseline = 'middle'
9945
+ }
9946
+ this.kpiPaper.pen.fillStyle = this.kpi.label.colour || kpiStyleDefaults.label.colour
9947
+ this.kpiPaper.pen.fillText(this.kpi.label.text, this.center.x, this.center.y + 10)
9948
+ this.kpiPaper.pen.closePath()
9949
+ this.kpiPaper.pen.restore()
9950
+ }
9951
+ }
9952
+
9953
+ }
9954
+ drawLabels () {
9955
+ // this.labelPaper.pen.translate(this.center.x, this.center.y)
9956
+ if (this.options.showLabels) {
9957
+ for (let s in this.data.segments) {
9958
+ this.labelPaper.pen.beginPath()
9959
+ this.labelPaper.pen.font = '20px arial'
9960
+ this.labelPaper.pen.textAlign = 'center'
9961
+ this.labelPaper.pen.textBaseline = 'text-bottom'
9962
+ this.labelPaper.pen.fillStyle = 'black'
9963
+ // calculate the nearest 90 degrees to the mid point and reduce to within 360 degrees
9964
+ let midAngleDeg = this.data.segments[s].midAngleDeg % 360
9965
+ let nearest90Deg = (Math.round(midAngleDeg / 90) * 90) % 360
9966
+ console.log(Math.abs(nearest90Deg - midAngleDeg))
9967
+ let missingAngleDeg = 270 - (Math.abs(nearest90Deg - midAngleDeg))
9968
+ console.log(nearest90Deg)
9969
+ let oppLength = (this.outerRadius * Math.sin(this.convertDegreesToRadians(Math.abs(nearest90Deg - midAngleDeg)))) / Math.sin(this.convertDegreesToRadians(missingAngleDeg))
9970
+ oppLength = Math.abs(oppLength)
9971
+ let moveLength = this.outerRadius + 5
9972
+ let slopeMultiplier = 1.2
9973
+ let flatMultiplier = 1.3
9974
+ if (midAngleDeg > 0 && midAngleDeg <= 45) {
9975
+ this.labelPaper.pen.moveTo(this.center.x + moveLength, this.center.y + oppLength)
9976
+ this.labelPaper.pen.lineTo(this.center.x + (moveLength * slopeMultiplier), this.center.y + (oppLength * slopeMultiplier))
9977
+ this.labelPaper.pen.lineTo(this.center.x + (moveLength * flatMultiplier), this.center.y + (oppLength * slopeMultiplier))
9978
+ }
9979
+ else if (midAngleDeg > 45 && midAngleDeg <= 90) {
9980
+ this.labelPaper.pen.moveTo(this.center.x + oppLength, this.center.y + moveLength)
9981
+ this.labelPaper.pen.lineTo(this.center.x + (oppLength * slopeMultiplier), this.center.y + (moveLength * slopeMultiplier))
9982
+ this.labelPaper.pen.lineTo(this.center.x + (oppLength * flatMultiplier), this.center.y + (moveLength * slopeMultiplier))
9983
+ }
9984
+ else if (midAngleDeg > 90 && midAngleDeg <= 135) {
9985
+ this.labelPaper.pen.moveTo(this.center.x - oppLength, this.center.y + moveLength)
9986
+ this.labelPaper.pen.lineTo(this.center.x - (oppLength * slopeMultiplier), this.center.y + (moveLength * slopeMultiplier))
9987
+ this.labelPaper.pen.lineTo(this.center.x - (oppLength * flatMultiplier), this.center.y + (moveLength * slopeMultiplier))
9988
+ }
9989
+ else if (midAngleDeg > 135 && midAngleDeg <= 180) {
9990
+ this.labelPaper.pen.moveTo(this.center.x - moveLength, this.center.y + oppLength)
9991
+ this.labelPaper.pen.lineTo(this.center.x - (moveLength * slopeMultiplier), this.center.y + (oppLength * slopeMultiplier))
9992
+ this.labelPaper.pen.lineTo(this.center.x - (moveLength * flatMultiplier), this.center.y + (oppLength * slopeMultiplier))
9993
+ }
9994
+ else if (midAngleDeg > 180 && midAngleDeg <= 225) {
9995
+ this.labelPaper.pen.moveTo(this.center.x - moveLength, this.center.y - oppLength)
9996
+ this.labelPaper.pen.lineTo(this.center.x - (moveLength * slopeMultiplier), this.center.y - (oppLength * slopeMultiplier))
9997
+ this.labelPaper.pen.lineTo(this.center.x - (moveLength * flatMultiplier), this.center.y - (oppLength * slopeMultiplier))
9998
+ }
9999
+ else if (midAngleDeg > 225 && midAngleDeg <= 270) {
10000
+ this.labelPaper.pen.moveTo(this.center.x - oppLength, this.center.y - moveLength)
10001
+ this.labelPaper.pen.lineTo(this.center.x - (oppLength * slopeMultiplier), this.center.y - (moveLength * slopeMultiplier))
10002
+ this.labelPaper.pen.lineTo(this.center.x - (oppLength * flatMultiplier), this.center.y - (moveLength * slopeMultiplier))
10003
+ }
10004
+ else if (midAngleDeg > 270 && midAngleDeg <= 315) {
10005
+ this.labelPaper.pen.moveTo(this.center.x + oppLength, this.center.y - moveLength)
10006
+ this.labelPaper.pen.lineTo(this.center.x + (oppLength * slopeMultiplier), this.center.y - (moveLength * slopeMultiplier))
10007
+ this.labelPaper.pen.lineTo(this.center.x + (oppLength * flatMultiplier), this.center.y - (moveLength * slopeMultiplier))
10008
+ }
10009
+ else {
10010
+ this.labelPaper.pen.moveTo(this.center.x + moveLength, this.center.y - oppLength)
10011
+ this.labelPaper.pen.lineTo(this.center.x + (moveLength * slopeMultiplier), this.center.y - (oppLength * slopeMultiplier))
10012
+ this.labelPaper.pen.lineTo(this.center.x + (moveLength * flatMultiplier), this.center.y - (oppLength * slopeMultiplier))
10013
+ }
10014
+ this.labelPaper.pen.strokeStyle = '#cccccc'
10015
+ this.labelPaper.pen.stroke()
10016
+
10017
+ this.labelPaper.pen.fillText(this.center.x + this.data.segments[s].label.x, this.center.y + this.data.segments[s].label.y, s)
10018
+ this.labelPaper.pen.closePath()
10019
+ }
10020
+ }
10021
+
10022
+ }
10023
+ drawSegments () {
10024
+ let originalStartPoint = this.convertDegreesToRadians(270)
10025
+ let startPoint = originalStartPoint
10026
+ let colourIndex = 0
10027
+ for (let s in this.data.segments) {
10028
+ if (colourIndex >= this.options.colors.length) {
10029
+ colourIndex = 0
10030
+ }
10031
+ let segmentColour = this.options.colors[colourIndex]
10032
+ let endPoint = startPoint + this.data.segments[s].circumference
10033
+ let midAngle = (startPoint + endPoint) / 2
10034
+
10035
+ this.data.segments[s].labelCanvasRotation = startPoint
10036
+ this.data.segments[s].startAngle = startPoint
10037
+ this.data.segments[s].midAngle = midAngle
10038
+ this.data.segments[s].endAngle = endPoint
10039
+ this.data.segments[s].startAngleDeg = this.convertRadiansToDegrees(startPoint)
10040
+ this.data.segments[s].midAngleDeg = this.convertRadiansToDegrees(midAngle)
10041
+ this.data.segments[s].endAngleDeg = this.convertRadiansToDegrees(endPoint)
10042
+ this.segmentPaper.pen.beginPath()
10043
+ this.segmentPaper.pen.moveTo(this.center.x, this.center.y)
10044
+ this.segmentPaper.pen.fillStyle = segmentColour
10045
+ this.segmentPaper.pen.arc(this.center.x, this.center.y, this.outerRadius, startPoint, endPoint)
10046
+ console.log(this.segmentPaper.pen)
10047
+ this.segmentPaper.pen.fill()
10048
+ this.segmentPaper.pen.closePath()
10049
+ startPoint = endPoint
10050
+ colourIndex++
10051
+ }
10052
+ // cut out the center of the pie if an inner radius has been set
10053
+ if (this.innerRadius && this.innerRadius !== 0) {
10054
+ // inner radius is a percentage so we compare it against outerRadius (px) to calculate the pixel value
10055
+ this.innerRadiusPixels = Math.round(this.outerRadius * (this.innerRadius / 100))
10056
+ this.segmentPaper.pen.save()
10057
+ this.segmentPaper.pen.beginPath()
10058
+ this.segmentPaper.pen.moveTo(this.center.x, this.center.y)
10059
+ this.segmentPaper.pen.arc(this.center.x, this.center.y, (this.innerRadiusPixels + 5), 0, Math.PI * 2)
10060
+ this.segmentPaper.pen.clip()
10061
+ this.segmentPaper.pen.clearRect(0, 0, this.width * 2, this.height * 2)
10062
+ this.segmentPaper.pen.closePath()
10063
+ this.segmentPaper.pen.restore()
10064
+
10065
+ // add shading if required
10066
+ if (this.addShading === true) {
10067
+ startPoint = originalStartPoint
10068
+ colourIndex = 0
10069
+ for (let s in this.data.segments) {
10070
+ if (colourIndex >= this.options.colors.length) {
10071
+ colourIndex = 0
10072
+ }
10073
+ let segmentColour = this.hexToRGBA(this.options.colors[colourIndex], 0.8)
10074
+ let endPoint = startPoint + this.data.segments[s].circumference
10075
+ this.segmentPaper.pen.beginPath()
10076
+ this.segmentPaper.pen.moveTo(this.center.x, this.center.y)
10077
+ this.segmentPaper.pen.fillStyle = segmentColour
10078
+ this.segmentPaper.pen.arc(this.center.x, this.center.y, (this.innerRadiusPixels + 6), startPoint, endPoint)
10079
+ this.segmentPaper.pen.fill()
10080
+ this.segmentPaper.pen.closePath()
10081
+ startPoint = endPoint
10082
+ colourIndex++
10083
+ }
10084
+ // cut out the center again
10085
+ this.segmentPaper.pen.save()
10086
+ this.segmentPaper.pen.beginPath()
10087
+ this.segmentPaper.pen.moveTo(this.center.x, this.center.y)
10088
+ this.segmentPaper.pen.arc(this.center.x, this.center.y, this.innerRadiusPixels, 0, Math.PI * 2)
10089
+ this.segmentPaper.pen.clip()
10090
+ this.segmentPaper.pen.clearRect(0, 0, this.width * 2, this.height * 2)
10091
+ this.segmentPaper.pen.closePath()
10092
+ this.segmentPaper.pen.restore()
10093
+ }
10094
+ }
10095
+ console.log(this.data)
10096
+
10097
+ }
10098
+ hexToRGBA (hex, opacity) {
10099
+ if (!opacity) {
10100
+ opacity = 1
10101
+ }
10102
+ let c
10103
+ if (/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)) {
10104
+ c = hex.substring(1).split('')
10105
+ if (c.length === 3) {
10106
+ c = [c[0], c[0], c[1], c[1], c[2], c[2]]
10107
+ }
10108
+ c = '0x' + c.join('')
10109
+ return 'rgba(' + [(c >> 16) & 255, (c >> 8) & 255, c & 255, opacity].join(',') + ')'
10110
+ }
10111
+ console.error(`Unable to convert hex (${hex}) to RGBA`)
10112
+ return 'rgba(0, 0, 0, 1)'
10113
+ }
10114
+ render (data) {
10115
+ /* global data */
10116
+ const el = document.getElementById(this.elementId)
10117
+ if (el && !el.target) {
10118
+ this.createCanvases(el)
10119
+ }
10120
+ if (data && !data.target) {
10121
+ this.originalData = [...data]
10122
+ }
10123
+ this.processData(data)
10124
+ this.drawSegments()
10125
+ this.drawLabels()
10126
+ this.drawKPI()
10127
+
10128
+ }
10129
+ resize () {
10130
+
10131
+ }
10132
+ processData (data) {
10133
+ /* global data */
10134
+ let tempData = {}
10135
+ let tempTotal = 0
10136
+ for (let i = 0; i < data.length; i++) {
10137
+ // if the dimension does not exists as a property on tempData, add it
10138
+ if (!tempData[data[i][0].label]) {
10139
+ tempData[data[i][0].label] = {
10140
+ segmentValue: 0,
10141
+ drill: []
10142
+ }
10143
+ }
10144
+ // add the value to the relevent segmentValue
10145
+ tempData[data[i][0].label].segmentValue += data[i][1].value
10146
+ // add the value to the total
10147
+ tempTotal += data[i][1].value
10148
+ // if a drill has been specified add the data to the drill property
10149
+ if (this.drill && this.drill !== '') {
10150
+ tempData[data[i][0].label].drill.push({
10151
+ label: data[i][0].label,
10152
+ value: data[i][1].value
10153
+ })
10154
+ }
10155
+ }
10156
+ // loop through the full data set to calculate the percentages
10157
+ for (let s in tempData) {
10158
+ tempData[s].percValue = tempData[s].segmentValue / tempTotal
10159
+ tempData[s].circumference = this.calculateCircumference(tempData[s].percValue)
10160
+ tempData[s].labelAngle = 360 * (tempData[s].percValue / 2)
10161
+ // calculate where the label should be for that segment
10162
+ tempData[s].label = {
10163
+ x: ((this.outerRadius + 5) / Math.sin(this.convertDegreesToRadians(90)) * Math.sin(this.convertDegreesToRadians(180 - 90 - tempData[s].labelAngle)))
10164
+ }
10165
+ tempData[s].label.y = ((this.outerRadius + 5) / Math.sin(this.convertDegreesToRadians(90)) * Math.sin(this.convertDegreesToRadians(tempData[s].labelAngle)))
10166
+ }
10167
+ this.data = {
10168
+ segments: tempData,
10169
+ total: tempTotal
10170
+ }
10171
+ console.log(this.data)
10172
+
10173
+ }
10174
+ }
10175
+
9672
10176
  class WebsyLegend {
9673
10177
  constructor (elementId, options) {
9674
10178
  const DEFAULTS = {
@@ -10141,6 +10645,8 @@ const WebsyDesigns = {
10141
10645
  Chart: WebsyChart,
10142
10646
  WebsyChartTooltip,
10143
10647
  ChartTooltip: WebsyChartTooltip,
10648
+ Pie: WebsyPie,
10649
+ WebsyPie,
10144
10650
  Legend: WebsyLegend,
10145
10651
  WebsyMap,
10146
10652
  Map: WebsyMap,