@websy/websy-designs 0.0.115 → 0.0.119

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,7 +15,9 @@
15
15
  WebsyMap
16
16
  WebsyKPI
17
17
  WebsyPDFButton
18
+ WebsyTemplate
18
19
  APIService
20
+ WebsyUtils
19
21
  */
20
22
 
21
23
  class WebsyPopupDialog {
@@ -156,8 +158,10 @@ class WebsyLoadingDialog {
156
158
  class WebsyNavigationMenu {
157
159
  constructor (elementId, options) {
158
160
  this.options = Object.assign({}, {
161
+ collapsable: false,
159
162
  orientation: 'horizontal',
160
- parentMap: {}
163
+ parentMap: {},
164
+ childIndentation: 10
161
165
  }, options)
162
166
  if (!elementId) {
163
167
  console.log('No element Id provided for Websy Menu')
@@ -196,15 +200,19 @@ class WebsyNavigationMenu {
196
200
  const el = document.getElementById(this.elementId)
197
201
  if (el) {
198
202
  let html = ``
199
- if (this.options.logo) {
203
+ if (this.options.collapsable === true) {
200
204
  html += `
201
205
  <div id='${this.elementId}_menuIcon' class='websy-menu-icon'>
202
- <svg viewbox="0 0 40 40" width="40" height="40">
203
- <rect x="0" y="0" width="40" height="4" rx="2"></rect>
204
- <rect x="0" y="12" width="40" height="4" rx="2"></rect>
205
- <rect x="0" y="24" width="40" height="4" rx="2"></rect>
206
+ <svg viewbox="0 0 40 40" width="30" height="40">
207
+ <rect x="0" y="0" width="30" height="4" rx="2"></rect>
208
+ <rect x="0" y="12" width="30" height="4" rx="2"></rect>
209
+ <rect x="0" y="24" width="30" height="4" rx="2"></rect>
206
210
  </svg>
207
- </div>
211
+ </div>
212
+ `
213
+ }
214
+ if (this.options.logo) {
215
+ html += `
208
216
  <div
209
217
  class='logo ${(this.options.logo.classes && this.options.logo.classes.join(' ')) || ''}'
210
218
  ${this.options.logo.attributes && this.options.logo.attributes.join(' ')}
@@ -240,10 +248,11 @@ class WebsyNavigationMenu {
240
248
  <li class='websy-${this.options.orientation}-list-item'>
241
249
  <div class='websy-menu-header ${items[i].classes && items[i].classes.join(' ')} ${selected} ${active}'
242
250
  id='${this.elementId}_${currentBlock}_label'
243
- data-id='${currentBlock}'
251
+ data-id='${currentBlock}'
252
+ data-menu-id='${this.elementId}_${currentBlock}_list'
244
253
  data-popout-id='${level > 1 ? block : currentBlock}'
245
254
  data-text='${items[i].text}'
246
- style='padding-left: ${level * this.options.menuHPadding}px'
255
+ style='padding-left: ${level * this.options.childIndentation}px'
247
256
  ${items[i].attributes && items[i].attributes.join(' ')}
248
257
  >
249
258
  `
@@ -278,6 +287,9 @@ class WebsyNavigationMenu {
278
287
  }
279
288
  html += `</ul>`
280
289
  return html
290
+ }
291
+ toggleOpen () {
292
+
281
293
  }
282
294
  toggleMobileMenu (method) {
283
295
  if (typeof method === 'undefined') {
@@ -325,6 +337,13 @@ class WebsyForm {
325
337
  this.render()
326
338
  }
327
339
  }
340
+ cancelForm () {
341
+ const formEl = document.getElementById(`${this.elementId}Form`)
342
+ formEl.reset()
343
+ if (this.options.cancelFn) {
344
+ this.options.cancelFn(this.elementId)
345
+ }
346
+ }
328
347
  checkRecaptcha () {
329
348
  return new Promise((resolve, reject) => {
330
349
  if (this.options.useRecaptcha === true) {
@@ -375,9 +394,13 @@ class WebsyForm {
375
394
  }
376
395
  }
377
396
  handleClick (event) {
397
+ event.preventDefault()
378
398
  if (event.target.classList.contains('submit')) {
379
399
  this.submitForm()
380
400
  }
401
+ else if (event.target.classList.contains('cancel')) {
402
+ this.cancelForm()
403
+ }
381
404
  }
382
405
  handleKeyDown (event) {
383
406
  if (event.key === 'enter') {
@@ -418,42 +441,56 @@ class WebsyForm {
418
441
  let html = `
419
442
  <form id="${this.elementId}Form">
420
443
  `
421
- this.options.fields.forEach(f => {
444
+ this.options.fields.forEach((f, i) => {
422
445
  if (f.component) {
423
446
  componentsToProcess.push(f)
424
447
  html += `
425
- ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
426
- <div id='${this.elementId}_input_${f.field}_component' class='form-component'></div>
448
+ ${i > 0 ? '-->' : ''}<div class='${f.classes}'>
449
+ ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
450
+ <div id='${this.elementId}_input_${f.field}_component' class='form-component'></div>
451
+ </div><!--
427
452
  `
428
453
  }
429
454
  else if (f.type === 'longtext') {
430
455
  html += `
431
- ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
432
- <textarea
433
- id="${this.elementId}_input_${f.field}"
434
- ${f.required === true ? 'required' : ''}
435
- placeholder="${f.placeholder || ''}"
436
- name="${f.field}"
437
- class="websy-input websy-textarea ${f.classes}"
438
- ></textarea>
456
+ ${i > 0 ? '-->' : ''}<div class='${f.classes}'>
457
+ ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
458
+ <textarea
459
+ id="${this.elementId}_input_${f.field}"
460
+ ${f.required === true ? 'required' : ''}
461
+ placeholder="${f.placeholder || ''}"
462
+ name="${f.field}"
463
+ class="websy-input websy-textarea"
464
+ ></textarea>
465
+ </div><!--
439
466
  `
440
467
  }
441
468
  else {
442
469
  html += `
443
- ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
444
- <input
445
- id="${this.elementId}_input_${f.field}"
446
- ${f.required === true ? 'required' : ''}
447
- type="${f.type || 'text'}"
448
- class="websy-input ${f.classes}"
449
- name="${f.field}"
450
- placeholder="${f.placeholder || ''}"
451
- value="${f.value || ''}"
452
- oninvalidx="this.setCustomValidity('${f.invalidMessage || 'Please fill in this field.'}')"
453
- />
470
+ ${i > 0 ? '-->' : ''}<div class='${f.classes}'>
471
+ ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
472
+ <input
473
+ id="${this.elementId}_input_${f.field}"
474
+ ${f.required === true ? 'required' : ''}
475
+ type="${f.type || 'text'}"
476
+ class="websy-input"
477
+ name="${f.field}"
478
+ placeholder="${f.placeholder || ''}"
479
+ value="${f.value || ''}"
480
+ oninvalidx="this.setCustomValidity('${f.invalidMessage || 'Please fill in this field.'}')"
481
+ />
482
+ </div><!--
454
483
  `
455
484
  }
456
485
  })
486
+ html += `
487
+ --><button class="websy-btn submit ${this.options.submit.classes}">${this.options.submit.text || 'Save'}</button>${this.options.cancel ? '<!--' : ''}
488
+ `
489
+ if (this.options.cancel) {
490
+ html += `
491
+ --><button class="websy-btn cancel ${this.options.cancel.classes}">${this.options.cancel.text || 'Cancel'}</button>
492
+ `
493
+ }
457
494
  html += `
458
495
  </form>
459
496
  <div id="${this.elementId}_validationFail" class="websy-validation-failure"></div>
@@ -463,9 +500,6 @@ class WebsyForm {
463
500
  <div id='${this.elementId}_recaptcha'></div>
464
501
  `
465
502
  }
466
- html += `
467
- <button class="websy-btn submit ${this.options.submit.classes}">${this.options.submit.text || 'Save'}</button>
468
- `
469
503
  el.innerHTML = html
470
504
  this.processComponents(componentsToProcess, () => {
471
505
  if (this.options.useRecaptcha === true && typeof grecaptcha !== 'undefined') {
@@ -884,6 +918,7 @@ Date.prototype.floor = function () {
884
918
  return new Date(`${this.getMonth() + 1}/${this.getDate()}/${this.getFullYear()}`)
885
919
  }
886
920
 
921
+ /* global WebsyUtils */
887
922
  class WebsyDropdown {
888
923
  constructor (elementId, options) {
889
924
  const DEFAULTS = {
@@ -893,8 +928,10 @@ class WebsyDropdown {
893
928
  style: 'plain',
894
929
  items: [],
895
930
  label: '',
931
+ disabled: false,
896
932
  minSearchCharacters: 2,
897
- showCompleteSelectedList: false
933
+ showCompleteSelectedList: false,
934
+ closeAfterSelection: true
898
935
  }
899
936
  this.options = Object.assign({}, DEFAULTS, options)
900
937
  this.tooltipTimeoutFn = null
@@ -948,6 +985,7 @@ class WebsyDropdown {
948
985
  const contentEl = document.getElementById(`${this.elementId}_content`)
949
986
  maskEl.classList.remove('active')
950
987
  contentEl.classList.remove('active')
988
+ contentEl.classList.remove('on-top')
951
989
  const searchEl = document.getElementById(`${this.elementId}_search`)
952
990
  if (searchEl) {
953
991
  if (this.options.onCancelSearch) {
@@ -957,6 +995,9 @@ class WebsyDropdown {
957
995
  }
958
996
  }
959
997
  handleClick (event) {
998
+ if (this.options.disabled === true) {
999
+ return
1000
+ }
960
1001
  if (event.target.classList.contains('websy-dropdown-header')) {
961
1002
  this.open()
962
1003
  }
@@ -1044,6 +1085,9 @@ class WebsyDropdown {
1044
1085
  const contentEl = document.getElementById(`${this.elementId}_content`)
1045
1086
  maskEl.classList.add('active')
1046
1087
  contentEl.classList.add('active')
1088
+ if (WebsyUtils.getElementPos(contentEl).bottom > window.innerHeight) {
1089
+ contentEl.classList.add('on-top')
1090
+ }
1047
1091
  if (this.options.disableSearch !== true) {
1048
1092
  const searchEl = document.getElementById(`${this.elementId}_search`)
1049
1093
  if (searchEl) {
@@ -1057,12 +1101,13 @@ class WebsyDropdown {
1057
1101
  return
1058
1102
  }
1059
1103
  const el = document.getElementById(this.elementId)
1060
- const headerValue = this.selectedItems.map(s => this.options.items[s].label).join(this.options.multiValueDelimiter)
1104
+ const headerLabel = this.selectedItems.map(s => this.options.items[s].label || this.options.items[s].value).join(this.options.multiValueDelimiter)
1105
+ const headerValue = this.selectedItems.map(s => this.options.items[s].value || this.options.items[s].label).join(this.options.multiValueDelimiter)
1061
1106
  let html = `
1062
- <div class='websy-dropdown-container ${this.options.disableSearch !== true ? 'with-search' : ''}'>
1107
+ <div class='websy-dropdown-container ${this.options.disabled ? 'disabled' : ''} ${this.options.disableSearch !== true ? 'with-search' : ''}'>
1063
1108
  <div id='${this.elementId}_header' class='websy-dropdown-header ${this.selectedItems.length === 1 ? 'one-selected' : ''} ${this.options.allowClear === true ? 'allow-clear' : ''}'>
1064
1109
  <span id='${this.elementId}_headerLabel' class='websy-dropdown-header-label'>${this.options.label}</span>
1065
- <span data-info='${headerValue}' class='websy-dropdown-header-value' id='${this.elementId}_selectedItems'>${headerValue}</span>
1110
+ <span data-info='${headerLabel}' class='websy-dropdown-header-value' id='${this.elementId}_selectedItems'>${headerLabel}</span>
1066
1111
  <input class='dropdown-input' id='${this.elementId}_input' name='${this.options.field || this.options.label}' value='${headerValue}'>
1067
1112
  <svg class='arrow' xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M23.677 18.52c.914 1.523-.183 3.472-1.967 3.472h-19.414c-1.784 0-2.881-1.949-1.967-3.472l9.709-16.18c.891-1.483 3.041-1.48 3.93 0l9.709 16.18z"/></svg>
1068
1113
  `
@@ -1142,19 +1187,21 @@ class WebsyDropdown {
1142
1187
  if (this.selectedItems.length === 1) {
1143
1188
  labelEl.innerHTML = item.label
1144
1189
  labelEl.setAttribute('data-info', item.label)
1145
- inputEl.value = item.label
1190
+ inputEl.value = item.value
1146
1191
  }
1147
1192
  else if (this.selectedItems.length > 1) {
1148
1193
  if (this.options.showCompleteSelectedList === true) {
1149
- let selectedValues = this.selectedItems.map(s => this.options.items[s].label).join(this.options.multiValueDelimiter)
1150
- labelEl.innerHTML = selectedValues
1151
- labelEl.setAttribute('data-info', selectedValues)
1194
+ let selectedLabels = this.selectedItems.map(s => this.options.items[s].label || this.options.items[s].value).join(this.options.multiValueDelimiter)
1195
+ let selectedValues = this.selectedItems.map(s => this.options.items[s].value || this.options.items[s].label).join(this.options.multiValueDelimiter)
1196
+ labelEl.innerHTML = selectedLabels
1197
+ labelEl.setAttribute('data-info', selectedLabels)
1152
1198
  inputEl.value = selectedValues
1153
1199
  }
1154
1200
  else {
1201
+ let selectedValues = this.selectedItems.map(s => this.options.items[s].value || this.options.items[s].label).join(this.options.multiValueDelimiter)
1155
1202
  labelEl.innerHTML = `${this.selectedItems.length} selected`
1156
1203
  labelEl.setAttribute('data-info', '')
1157
- inputEl.value = this.selectedItems.join(this.options.multiValueDelimiter)
1204
+ inputEl.value = selectedValues
1158
1205
  }
1159
1206
  }
1160
1207
  else {
@@ -1182,7 +1229,9 @@ class WebsyDropdown {
1182
1229
  if (item && this.options.onItemSelected) {
1183
1230
  this.options.onItemSelected(item, this.selectedItems, this.options.items)
1184
1231
  }
1185
- this.close()
1232
+ if (this.options.closeAfterSelection === true) {
1233
+ this.close()
1234
+ }
1186
1235
  }
1187
1236
  }
1188
1237
 
@@ -1390,6 +1439,149 @@ class WebsyResultList {
1390
1439
  }
1391
1440
  }
1392
1441
 
1442
+ /* global WebsyDesigns */
1443
+ class WebsyTemplate {
1444
+ constructor (elementId, options) {
1445
+ const DEFAULTS = {
1446
+ listeners: {
1447
+ click: {}
1448
+ }
1449
+ }
1450
+ this.options = Object.assign({}, DEFAULTS, options)
1451
+ this.elementId = elementId
1452
+ this.templateService = new WebsyDesigns.APIService('')
1453
+ if (!elementId) {
1454
+ console.log('No element Id provided for Websy Template')
1455
+ return
1456
+ }
1457
+ const el = document.getElementById(elementId)
1458
+ if (el) {
1459
+ el.addEventListener('click', this.handleClick.bind(this))
1460
+ }
1461
+ if (typeof options.template === 'object' && options.template.url) {
1462
+ this.templateService.get(options.template.url).then(templateString => {
1463
+ this.options.template = templateString
1464
+ this.render()
1465
+ })
1466
+ }
1467
+ else {
1468
+ this.render()
1469
+ }
1470
+ }
1471
+ buildHTML () {
1472
+ let html = ``
1473
+ if (this.options.template) {
1474
+ let template = this.options.template
1475
+ // find conditional elements
1476
+ let ifMatches = [...template.matchAll(/<\s*if[^>]*>([\s\S]*?)<\s*\/\s*if>/g)]
1477
+ ifMatches.forEach(m => {
1478
+ // get the condition
1479
+ if (m[0] && m.index > -1) {
1480
+ let conditionMatch = m[0].match(/(\scondition=["|']\w.+)["|']/g)
1481
+ if (conditionMatch && conditionMatch[0]) {
1482
+ let c = conditionMatch[0].trim().replace('condition=', '')
1483
+ if (c.split('')[0] === '"') {
1484
+ c = c.replace(/"/g, '')
1485
+ }
1486
+ else if (c.split('')[0] === '\'') {
1487
+ c = c.replace(/'/g, '')
1488
+ }
1489
+ let parts = []
1490
+ let polarity = true
1491
+ if (c.indexOf('===') !== -1) {
1492
+ parts = c.split('===')
1493
+ }
1494
+ else if (c.indexOf('!==') !== -1) {
1495
+ parts = c.split('!==')
1496
+ polarity = false
1497
+ }
1498
+ else if (c.indexOf('==') !== -1) {
1499
+ parts = c.split('==')
1500
+ }
1501
+ else if (c.indexOf('!=') !== -1) {
1502
+ parts = c.split('!=')
1503
+ polarity = false
1504
+ }
1505
+ let removeAll = true
1506
+ if (parts.length === 2) {
1507
+ if (!isNaN(parts[1])) {
1508
+ parts[1] = +parts[1]
1509
+ }
1510
+ if (parts[1] === 'true') {
1511
+ parts[1] = true
1512
+ }
1513
+ if (parts[1] === 'false') {
1514
+ parts[1] = false
1515
+ }
1516
+ if (typeof parts[1] === 'string') {
1517
+ if (parts[1].indexOf('"') !== -1) {
1518
+ parts[1] = parts[1].replace(/"/g, '')
1519
+ }
1520
+ else if (parts[1].indexOf('\'') !== -1) {
1521
+ parts[1] = parts[1].replace(/'/g, '')
1522
+ }
1523
+ }
1524
+ if (polarity === true) {
1525
+ if (typeof this.options.data[parts[0]] !== 'undefined' && this.options.data[parts[0]] === parts[1]) {
1526
+ // remove the <if> tags
1527
+ removeAll = false
1528
+ }
1529
+ else if (parts[0] === parts[1]) {
1530
+ removeAll = false
1531
+ }
1532
+ }
1533
+ else if (polarity === false) {
1534
+ if (typeof this.options.data[parts[0]] !== 'undefined' && this.options.data[parts[0]] !== parts[1]) {
1535
+ // remove the <if> tags
1536
+ removeAll = false
1537
+ }
1538
+ }
1539
+ }
1540
+ if (removeAll === true) {
1541
+ // remove the whole markup
1542
+ template = template.replace(m[0], '')
1543
+ }
1544
+ else {
1545
+ // remove the <if> tags
1546
+ let newMarkup = m[0]
1547
+ newMarkup = newMarkup.replace('</if>', '').replace(/<\s*if[^>]*>/g, '')
1548
+ template = template.replace(m[0], newMarkup)
1549
+ }
1550
+ }
1551
+ }
1552
+ })
1553
+ let tagMatches = [...template.matchAll(/(\sdata-event=["|']\w.+)["|']/g)]
1554
+ tagMatches.forEach(m => {
1555
+ if (m[0] && m.index > -1) {
1556
+ template = template.replace(m[0], `${m[0]}`)
1557
+ }
1558
+ })
1559
+ for (let key in this.options.data) {
1560
+ let rg = new RegExp(`{${key}}`, 'gm')
1561
+ if (rg) {
1562
+ template = template.replace(rg, this.options.data[key])
1563
+ }
1564
+ }
1565
+ html = template
1566
+ }
1567
+ return html
1568
+ }
1569
+ handleClick (event) {
1570
+ //
1571
+ }
1572
+ render () {
1573
+ this.resize()
1574
+ }
1575
+ resize () {
1576
+ const html = this.buildHTML()
1577
+ const el = document.getElementById(this.elementId)
1578
+ el.innerHTML = html.replace(/\n/g, '')
1579
+ if (this.options.readyCallbackFn) {
1580
+ this.options.readyCallbackFn()
1581
+ }
1582
+ }
1583
+ }
1584
+
1393
1585
  class WebsyPubSub {
1394
1586
  constructor (elementId, options) {
1395
1587
  this.options = Object.assign({}, options)
@@ -1888,7 +2080,7 @@ class APIService {
1888
2080
  if (id) {
1889
2081
  query.push(`id:${id}`)
1890
2082
  }
1891
- return `${this.baseUrl}/${entity}${query.length > 0 ? `?where=${query.join(';')}` : ''}`
2083
+ return `${this.baseUrl}/${entity}${query.length > 0 ? `${entity.indexOf('?') === -1 ? '?' : '&'}where=${query.join(';')}` : ''}`
1892
2084
  }
1893
2085
  delete (entity, id) {
1894
2086
  const url = this.buildUrl(entity, id)
@@ -2557,6 +2749,7 @@ this.plotArea = this.svg.append('g')
2557
2749
  this.areaLayer = this.svg.append('g')
2558
2750
  this.lineLayer = this.svg.append('g')
2559
2751
  this.barLayer = this.svg.append('g')
2752
+ this.labelLayer = this.svg.append('g')
2560
2753
  this.symbolLayer = this.svg.append('g')
2561
2754
  this.trackingLineLayer = this.svg.append('g')
2562
2755
  this.trackingLineLayer.append('line').attr('class', 'tracking-line')
@@ -2732,6 +2925,8 @@ else {
2732
2925
  .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
2733
2926
  this.barLayer
2734
2927
  .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
2928
+ this.labelLayer
2929
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
2735
2930
  this.symbolLayer
2736
2931
  .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
2737
2932
  this.trackingLineLayer
@@ -2924,6 +3119,7 @@ else {
2924
3119
  series.color = this.options.colors[index % this.options.colors.length]
2925
3120
  }
2926
3121
  this[`render${series.type || 'bar'}`](series, index)
3122
+ this.renderLabels(series, index)
2927
3123
  })
2928
3124
  }
2929
3125
  }
@@ -3050,6 +3246,76 @@ bars
3050
3246
  return `bar bar_${series.key}`
3051
3247
  })
3052
3248
 
3249
+ }
3250
+ renderLabels (series, index) {
3251
+ /* global series index d3 */
3252
+ let xAxis = 'bottomAxis'
3253
+ let yAxis = 'leftAxis'
3254
+ let that = this
3255
+ if (this.options.orientation === 'horizontal') {
3256
+ xAxis = 'leftAxis'
3257
+ yAxis = 'bottomAxis'
3258
+ }
3259
+ if (this.options.showLabels) {
3260
+ // need to add logic to handle positioning options
3261
+ // e.g. Inside, Outide, Auto (this will also affect the available plot space)
3262
+ // We currently only support 'Auto'
3263
+ let labels = this.labelLayer.selectAll(`.label_${series.key}`).data(series.data)
3264
+ labels
3265
+ .exit()
3266
+ .transition(this.transition)
3267
+ .style('stroke-opacity', 1e-6)
3268
+ .remove()
3269
+ labels
3270
+ .attr('x', getLabelX.bind(this))
3271
+ .attr('y', getLabelY.bind(this))
3272
+ .attr('class', `.label_${series.key}`)
3273
+ .style('font-size', `${this.options.labelSize || this.options.fontSize}px`)
3274
+ .transition(this.transition)
3275
+ .text(d => d.y.label || d.y.value)
3276
+
3277
+ labels
3278
+ .enter()
3279
+ .append('text')
3280
+ .attr('class', `.label_${series.key}`)
3281
+ .attr('x', getLabelX.bind(this))
3282
+ .attr('y', getLabelY.bind(this))
3283
+ .attr('alignment-baseline', 'central')
3284
+ .attr('text-anchor', this.options.orientation === 'horizontal' ? 'left' : 'middle')
3285
+ .style('font-size', `${this.options.labelSize || this.options.fontSize}px`)
3286
+ .text(d => d.y.label || d.y.value)
3287
+ .each(function (d, i) {
3288
+ if (that.options.orientation === 'horizontal') {
3289
+ if (that.plotWidth - getLabelX.call(that, d) < this.getComputedTextLength()) {
3290
+ this.setAttribute('text-anchor', 'end')
3291
+ this.setAttribute('x', +(this.getAttribute('x')) - 8)
3292
+ }
3293
+ }
3294
+ else {
3295
+ if (that.plotheight - getLabelX.call(that, d) < (that.options.labelSize || that.options.fontSize)) {
3296
+ this.setAttribute('y', +(this.getAttribute('y')) + 8)
3297
+ }
3298
+ }
3299
+ })
3300
+ }
3301
+
3302
+ function getLabelX (d) {
3303
+ if (this.options.orientation === 'horizontal') {
3304
+ return this[yAxis](isNaN(d.y.value) ? 0 : d.y.value) + 4
3305
+ }
3306
+ else {
3307
+ return this[xAxis](this.parseX(d.x.value)) + (this[xAxis].bandwidth() / 2)
3308
+ }
3309
+ }
3310
+ function getLabelY (d) {
3311
+ if (this.options.orientation === 'horizontal') {
3312
+ return this[xAxis](this.parseX(d.x.value)) + (this[xAxis].bandwidth() / 2)
3313
+ }
3314
+ else {
3315
+ return this[yAxis](isNaN(d.y.value) ? 0 : d.y.value) - 4
3316
+ }
3317
+ }
3318
+
3053
3319
  }
3054
3320
  renderline (series, index) {
3055
3321
  /* global series index d3 */
@@ -3135,7 +3401,7 @@ symbols
3135
3401
  .transition(this.transition)
3136
3402
  .attr('fill', 'white')
3137
3403
  .attr('stroke', series.color)
3138
- .attr('transform', d => { return `translate(${this[xAxis](this.parseX(d.x.value))}, ${this[yAxis](d.y.value)})` })
3404
+ .attr('transform', d => { return `translate(${this[xAxis](this.parseX(d.x.value))}, ${this[yAxis](isNaN(d.y.value) ? 0 : d.y.value)})` })
3139
3405
  // Enter
3140
3406
  symbols.enter()
3141
3407
  .append('path')
@@ -3145,7 +3411,7 @@ symbols.enter()
3145
3411
  .attr('stroke', series.color)
3146
3412
  .attr('class', d => { return `symbol symbol_${series.key}` })
3147
3413
  .attr('transform', d => {
3148
- return `translate(${this[xAxis](this.parseX(d.x.value))}, ${this[yAxis](d.y.value)})`
3414
+ return `translate(${this[xAxis](this.parseX(d.x.value))}, ${this[yAxis](isNaN(d.y.value) ? 0 : d.y.value)})`
3149
3415
  })
3150
3416
 
3151
3417
  }
@@ -3159,8 +3425,10 @@ if (el) {
3159
3425
  .attr('width', this.width)
3160
3426
  .attr('height', this.height)
3161
3427
  // Define the plot height
3428
+ // this.plotWidth = this.width - this.options.margin.left - this.options.margin.right - this.options.margin.axisLeft - this.options.margin.axisRight
3429
+ // this.plotHeight = this.height - this.options.margin.top - this.options.margin.bottom - this.options.margin.axisBottom
3162
3430
  this.plotWidth = this.width - this.options.margin.left - this.options.margin.right - this.options.margin.axisLeft - this.options.margin.axisRight
3163
- this.plotHeight = this.height - this.options.margin.top - this.options.margin.bottom - this.options.margin.axisBottom
3431
+ this.plotHeight = this.height - this.options.margin.top - this.options.margin.bottom - this.options.margin.axisBottom - this.options.margin.axisTop
3164
3432
  // establish the space needed for the various axes
3165
3433
  this.longestRight = 5
3166
3434
  this.longestBottom = 5
@@ -3190,24 +3458,54 @@ if (el) {
3190
3458
  }
3191
3459
  }
3192
3460
  // Translate the layers
3461
+ // this.leftAxisLayer
3462
+ // .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3463
+ // this.rightAxisLayer
3464
+ // .attr('transform', `translate(${this.options.margin.left + this.plotWidth + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3465
+ // this.bottomAxisLayer
3466
+ // .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.plotHeight})`)
3467
+ // this.plotArea
3468
+ // .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3469
+ // this.areaLayer
3470
+ // .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3471
+ // this.lineLayer
3472
+ // .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3473
+ // this.barLayer
3474
+ // .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3475
+ // this.labelLayer
3476
+ // .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3477
+ // this.symbolLayer
3478
+ // .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3479
+ // this.trackingLineLayer
3480
+ // .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3193
3481
  this.leftAxisLayer
3194
- .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3482
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3195
3483
  this.rightAxisLayer
3196
- .attr('transform', `translate(${this.options.margin.left + this.plotWidth + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3484
+ .attr('transform', `translate(${this.options.margin.left + this.plotWidth + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3197
3485
  this.bottomAxisLayer
3198
- .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.plotHeight})`)
3486
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop + this.plotHeight})`)
3487
+ this.leftAxisLabel
3488
+ .attr('transform', `translate(${this.options.margin.left}, ${this.options.margin.top + this.options.margin.axisTop})`)
3489
+ this.rightAxisLabel
3490
+ .attr('transform', `translate(${this.options.margin.left + this.plotWidth + this.options.margin.axisLeft + this.options.margin.axisRight}, ${this.options.margin.top + this.options.margin.axisTop})`)
3491
+ this.bottomAxisLabel
3492
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop + this.plotHeight})`)
3199
3493
  this.plotArea
3200
- .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3494
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3201
3495
  this.areaLayer
3202
- .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3496
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3203
3497
  this.lineLayer
3204
- .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3498
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3205
3499
  this.barLayer
3206
- .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3500
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3501
+ this.labelLayer
3502
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3207
3503
  this.symbolLayer
3208
- .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3504
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3209
3505
  this.trackingLineLayer
3210
- .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3506
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3507
+ this.eventLayer
3508
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3211
3509
  }
3212
3510
 
3213
3511
  }
@@ -3493,6 +3791,29 @@ class WebsyChartTooltip {
3493
3791
  }
3494
3792
  }
3495
3793
 
3794
+ const WebsyUtils = {
3795
+ createIdentity: (size = 6) => {
3796
+ let text = ''
3797
+ let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
3798
+
3799
+ for (let i = 0; i < size; i++) {
3800
+ text += possible.charAt(Math.floor(Math.random() * possible.length))
3801
+ }
3802
+ return text
3803
+ },
3804
+ getElementPos: el => {
3805
+ const rect = el.getBoundingClientRect()
3806
+ const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft
3807
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop
3808
+ return {
3809
+ top: rect.top + scrollTop,
3810
+ left: rect.left + scrollLeft,
3811
+ bottom: rect.top + scrollTop + el.clientHeight,
3812
+ right: rect.left + scrollLeft + el.clientWidth
3813
+ }
3814
+ }
3815
+ }
3816
+
3496
3817
 
3497
3818
  const WebsyDesigns = {
3498
3819
  WebsyPopupDialog,
@@ -3502,6 +3823,7 @@ const WebsyDesigns = {
3502
3823
  WebsyDatePicker,
3503
3824
  WebsyDropdown,
3504
3825
  WebsyResultList,
3826
+ WebsyTemplate,
3505
3827
  WebsyPubSub,
3506
3828
  WebsyRouter,
3507
3829
  WebsyTable,
@@ -3511,7 +3833,8 @@ const WebsyDesigns = {
3511
3833
  WebsyKPI,
3512
3834
  WebsyPDFButton,
3513
3835
  PDFButton: WebsyPDFButton,
3514
- APIService
3836
+ APIService,
3837
+ WebsyUtils
3515
3838
  }
3516
3839
 
3517
3840
  const GlobalPubSub = new WebsyPubSub('empty', {})