jh-componentj 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +61 -0
  3. package/dist/tvjs-xp.js +2375 -0
  4. package/dist/tvjs-xp.min.js +5 -0
  5. package/dist/tvjs-xp.min.js.LICENSE.txt +6 -0
  6. package/package.json +69 -0
  7. package/src/Main.vue +170 -0
  8. package/src/apps/App1.vue +71 -0
  9. package/src/apps/App2.vue +155 -0
  10. package/src/components/AppTag.vue +48 -0
  11. package/src/components/Chartbox.vue +87 -0
  12. package/src/components/Codepane.vue +260 -0
  13. package/src/components/Multiselect.vue +106 -0
  14. package/src/components/MyVueComponent.vue +26 -0
  15. package/src/components/StdInput.vue +70 -0
  16. package/src/components/Window.vue +95 -0
  17. package/src/components/dragg.js +32 -0
  18. package/src/extensions/chart-link/main.js +299 -0
  19. package/src/extensions/chart-link/shared.js +10 -0
  20. package/src/extensions/chart-link/utils.js +17 -0
  21. package/src/extensions/chart-link/x.json +11 -0
  22. package/src/extensions/grid-resize/Splitter.vue +80 -0
  23. package/src/extensions/grid-resize/main.js +152 -0
  24. package/src/extensions/grid-resize/utils.js +25 -0
  25. package/src/extensions/grid-resize/x.json +11 -0
  26. package/src/extensions/legend-buttons/AddWin.vue +91 -0
  27. package/src/extensions/legend-buttons/main.js +156 -0
  28. package/src/extensions/legend-buttons/x.json +11 -0
  29. package/src/extensions/settings-win/SettingsWin.vue +76 -0
  30. package/src/extensions/settings-win/main.js +39 -0
  31. package/src/extensions/settings-win/utils.js +19 -0
  32. package/src/extensions/settings-win/x.json +11 -0
  33. package/src/index.html +19 -0
  34. package/src/index_dev.js +27 -0
  35. package/src/index_prod.js +28 -0
  36. package/src/main.js +14 -0
  37. package/src/stuff/utils.js +16 -0
@@ -0,0 +1,299 @@
1
+
2
+ /* Example:
3
+
4
+ rules: {
5
+ '* -> *': {}, // From each to each
6
+ '*': { // The same as ^
7
+ cursor: true, // bool, 'X', 'Y', 'XY'
8
+ position: 'X', // bool, 'X', 'Y', 'XY'
9
+ tools: true
10
+ },
11
+ 'trading-vue-1 -> trading-vue-2': {
12
+ data: [
13
+ 'onchart.SMA',
14
+ 'RSI4H',
15
+ {
16
+ from: 'chart.data',
17
+ to: 'datasets',
18
+ obj: {
19
+ id: 'small-tf-data',
20
+ type: 'SourceData'
21
+ }
22
+ }
23
+ ]
24
+ },
25
+ 'none': {
26
+ range: 'X', // bool, 'X', 'Y', 'XY'
27
+ }
28
+ }
29
+ */
30
+
31
+ import Shared from './shared.js'
32
+ import Utils from './utils.js'
33
+
34
+ export default class Main {
35
+
36
+ constructor(tv, dc, sett) {
37
+
38
+ if (sett.use_window) {
39
+ if (!window.xchartlink$) {
40
+ window.xchartlink$ = {}
41
+ }
42
+ this.shared = window.xchartlink$
43
+ } else {
44
+ this.shared = Shared
45
+ }
46
+
47
+ this.tv = tv
48
+ this.dc = dc
49
+ this.sett = sett
50
+ this.targets = {}
51
+
52
+ this.onsettings({'chart-link': sett})
53
+ }
54
+
55
+ onsettings(all) {
56
+ clearTimeout(this.reset_id)
57
+ this.sett = all['chart-link']
58
+ if (!this.shared.rules) {
59
+ this.shared.rules = {}
60
+ this.shared.refs = {}
61
+ this.shared.meta = {}
62
+ }
63
+
64
+ let el = document.getElementById(this.tv.id)
65
+
66
+ if (this.sett.rules && el) {
67
+ this.shared.rules[this.tv.id] = this.sett.rules
68
+ }
69
+
70
+ this.shared.refs[this.tv.id] = this.tv
71
+
72
+ this.combine()
73
+ this.reset_id = setTimeout(() => this.reset())
74
+ }
75
+
76
+ // Combine rules from different instances
77
+ combine() {
78
+ this.shared.combined = {}
79
+ for (var id in this.shared.rules) {
80
+ for (var r in this.shared.rules[id]) {
81
+ this.shared.combined[r] =
82
+ this.shared.rules[id][r]
83
+ }
84
+ }
85
+ }
86
+
87
+ // Compile rules for this instance
88
+ compile() {
89
+
90
+ let gebcn = 'getElementsByClassName'
91
+ let els = [...document[gebcn]('trading-vue')]
92
+ this.targets = {}
93
+
94
+ for (let el of els) {
95
+ if (el.id === this.tv.id) continue
96
+ this.targets[el.id] = {}
97
+ }
98
+
99
+ let rules = this.rank(this.shared.combined)
100
+
101
+ for (var r of rules) {
102
+ let dst = r.pair[1]
103
+ if (dst === '*') {
104
+ dst = Object.keys(this.targets)
105
+ }
106
+ if (Array.isArray(dst)) {
107
+ for (var d of dst) {
108
+ if (!(d in this.targets)) continue
109
+ Object.assign(this.targets[d], r.r)
110
+ }
111
+ } else {
112
+ if (!(dst in this.targets)) continue
113
+ Object.assign(this.targets[dst], r.r)
114
+ }
115
+ }
116
+ }
117
+
118
+ // Select, rank & sort the rules
119
+ rank(rules) {
120
+ let out = []
121
+ for (var r in rules) {
122
+ let pair = this.splitr(r)
123
+ if (!this.matches(pair[0])) continue
124
+ if (pair[0] === '*') {
125
+ var rank = 20
126
+ } else if (Array.isArray(pair[0]) ) {
127
+ rank = 10
128
+ } else {
129
+ rank = 0
130
+ }
131
+ if (pair[1] === '*') {
132
+ rank += 2
133
+ } else if (Array.isArray(pair[1]) ) {
134
+ rank += 1
135
+ } else {
136
+ rank += 0
137
+ }
138
+ out.push({pair, rank, r: rules[r]})
139
+ }
140
+ return out.sort((a, b) => b.rank - a.rank)
141
+ }
142
+
143
+ // Check if the source of a rule matches tv.id
144
+ matches(src) {
145
+ return src === '*' || src === this.tv.id ||
146
+ (Array.isArray(src) && src.includes(this.tv.id))
147
+ }
148
+
149
+ splitr(rule) {
150
+ if (rule.trim() === '*') return ['*', '*']
151
+ return rule.split('->').map(x => {
152
+ let tup = x.split(',')
153
+ if (tup.length > 1) {
154
+ return tup.map(y => y.trim())
155
+ }
156
+ return x.trim()
157
+ })
158
+
159
+ }
160
+
161
+ // Apply all rules for this instance
162
+ reset() {
163
+ this.compile()
164
+
165
+ // Enable some chart hook events
166
+ this.tv.$refs.chart.hooks('xchanged')
167
+
168
+
169
+ this.tv.$watch(x => this.dc.get('.')
170
+ .filter(x => x.settings.$state),
171
+ this.ontools.bind(this))
172
+
173
+ }
174
+
175
+ // Listening to the Chart.vue hooks &
176
+ // other events
177
+ update(e) {
178
+ switch (e.event) {
179
+ case '?x-changed':
180
+ let cursor = e.args[0]
181
+ if (cursor.preventDefault) return
182
+ let main = this.tv.$refs.chart._layout.grids[cursor.grid_id]
183
+ let mc = this.tv.$refs.chart.cursor
184
+ cursor.t = mc.t
185
+ cursor.$ = mc.y$
186
+ for (var id in this.targets) {
187
+ let r = this.targets[id].cursor
188
+ if (r) {
189
+ let tv = this.shared.refs[id]
190
+ let g = tv.$refs.chart._layout.grids[0]
191
+ let xx = this.isX(r)
192
+ let yy = g.id === main.id && this.isY(r)
193
+ let upd = {
194
+ preventDefault: true,
195
+ x: xx ? g.t2screen(cursor.t) : -10,
196
+ y: yy ? g.$2screen(cursor.$) : -10,
197
+ grid_id: 0
198
+ }
199
+ tv.$refs.chart.cursor_changed(upd)
200
+ tv.$refs.chart.cursor.t = xx ? cursor.t : -10
201
+ tv.$refs.chart.cursor.y$ = yy ? cursor.$ : -10
202
+ }
203
+ }
204
+ break
205
+ case 'range-changed':
206
+ let now = new Date().getTime()
207
+ let meta = this.shared.meta[this.tv.id]
208
+ if (meta && meta.position) {
209
+ if (meta.position.lock > now) return
210
+ }
211
+ let range = e.args[0]
212
+ for (var id in this.targets) {
213
+ let r = this.targets[id].position
214
+ let tv = this.shared.refs[id]
215
+ let xx = this.isX(r)
216
+ let yy = this.isY(r)
217
+ if (!this.shared.meta[id]) {
218
+ this.shared.meta[id] = {}
219
+ }
220
+ // Prevents an infinite loop
221
+ this.shared.meta[id].position = {
222
+ lock: now + 100
223
+ }
224
+ if (xx) tv.goto(range[1])
225
+ }
226
+ break
227
+ }
228
+ }
229
+
230
+ ontools(n, p) {
231
+ let rem = Utils.removed(
232
+ n.map(x => x.settings.$uuid),
233
+ p.map(x => x.settings.$uuid)
234
+ )
235
+ let now = new Date().getTime()
236
+ let meta = this.shared.meta[this.tv.id]
237
+ if (meta && meta.tools) {
238
+ if (meta.tools.lock > now) return
239
+ }
240
+ for (var id in this.targets) {
241
+ let r = this.targets[id].tools
242
+ let tv = this.shared.refs[id]
243
+ if (r) {
244
+ if (!this.shared.meta[id]) {
245
+ this.shared.meta[id] = {}
246
+ }
247
+ // Prevents an infinite loop
248
+ this.shared.meta[id].tools = {
249
+ lock: now + 100
250
+ }
251
+ this.copy_tools(n, tv)
252
+ rem.forEach(r => tv.data.del(`${r}`))
253
+ }
254
+ }
255
+ }
256
+
257
+ copy_tools(n, tv) {
258
+ for (var tool of n) {
259
+ if (tool.id.includes('offchart')) continue
260
+ let uuid = tool.settings.$uuid
261
+ let exi = tv.data.get_one(`${uuid}`)
262
+ if (exi) {
263
+ tv.$set(exi, 'settings', Utils.copy(
264
+ tool.settings,
265
+ {
266
+ $selected: false,
267
+ $state: 'finished'
268
+ })
269
+ )
270
+ // TODO: maybe add a proper method
271
+ // of accessing overlays
272
+ let ovs = tv.$refs.chart.$refs.sec[0]
273
+ .$refs.grid
274
+ .$children.filter(x => x.tool)
275
+
276
+ for (var ov of ovs) {
277
+ ov.pins.forEach(x => x.re_init())
278
+ }
279
+
280
+ } else {
281
+ let copy = Utils.copy(tool)
282
+ copy.settings.$selected = false
283
+ copy.settings.$state = 'finished'
284
+ tv.data.add('onchart', copy)
285
+ }
286
+ }
287
+ }
288
+
289
+ isX(rule) {
290
+ return rule === true ||
291
+ (typeof rule === 'string' && rule.includes('X'))
292
+ }
293
+
294
+ isY(rule) {
295
+ return rule === true ||
296
+ (typeof rule === 'string' && rule.includes('Y'))
297
+ }
298
+
299
+ }
@@ -0,0 +1,10 @@
1
+
2
+ // Object shared beetween tvjs instances
3
+
4
+ class Shared {
5
+ constructor() {
6
+ this.__id__ = Math.random()
7
+ }
8
+ }
9
+
10
+ export default new Shared()
@@ -0,0 +1,17 @@
1
+ export default {
2
+
3
+ copy(obj, mod) {
4
+ let copy = JSON.parse(JSON.stringify(obj))
5
+ return Object.assign(copy, mod)
6
+ },
7
+
8
+ removed(ids, prev) {
9
+ let list = []
10
+ for (var id of prev) {
11
+ if (!ids.includes(id)) {
12
+ list.push(id)
13
+ }
14
+ }
15
+ return list
16
+ }
17
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "chart-link",
3
+ "author": "StdSquad",
4
+ "version": "1.0.0",
5
+ "components": [],
6
+ "widgets": [],
7
+ "overlays": [],
8
+ "skins": [],
9
+ "colorpacks": [],
10
+ "deps": {}
11
+ }
@@ -0,0 +1,80 @@
1
+ <template>
2
+ <span class="h-splitter"
3
+ @mousedown="hs_mousedown" :style="hs_style">
4
+ </span>
5
+ </template>
6
+ <script>
7
+
8
+ import Utils from './utils.js'
9
+
10
+ export default {
11
+ name: 'Splitter',
12
+ props: ['id', 'main', 'dc', 'tv', 'data'],
13
+ mounted() {
14
+ this.MIN_HEIGHT = this.data.sett.min_height || 20
15
+ },
16
+ methods: {
17
+ hs_mousedown(e) {
18
+ this.drag = {
19
+ type: 'hs',
20
+ y: e.clientY,
21
+ h1: this.data.grid1.height,
22
+ h2: this.data.grid2.height
23
+ }
24
+ Utils.add_style('disable-user-select', `body * {
25
+ user-select: none;
26
+ }
27
+ .trading-vue-chart {
28
+ pointer-events: none;
29
+ }`)
30
+ },
31
+ hs_mouseup(e) {
32
+ this.drag = null
33
+ Utils.rem_style('disable-user-select')
34
+ },
35
+ hs_mousemove(e) {
36
+ if (this.drag) {
37
+ let off = e.clientY - this.drag.y
38
+ let new_h1 = this.drag.h1 + off
39
+ let new_h2 = this.drag.h2 - off
40
+ if (new_h1 > this.MIN_HEIGHT &&
41
+ new_h2 > this.MIN_HEIGHT) {
42
+ this.data.grid1.height = new_h1
43
+ this.data.grid2.height = new_h2
44
+ }
45
+ this.main.calc_heights()
46
+ }
47
+ },
48
+ hs_mouseleave(e) {
49
+ this.drag = null
50
+ Utils.rem_style('disable-user-select')
51
+ }
52
+ },
53
+ computed: {
54
+ hs_style() {
55
+ return {
56
+ drag: null,
57
+ top: this.data.grid2.offset + 'px',
58
+ //backgroundColor: this.colors.splitter
59
+ }
60
+ },
61
+ }
62
+ }
63
+ </script>
64
+ <style scoped>
65
+ .h-splitter {
66
+ position: absolute;
67
+ left: 0;
68
+ height: 5px;
69
+ margin-top: -2px;
70
+ width: 100%;
71
+ z-index: 1;
72
+ background-color: #3ee4afb5;
73
+ opacity: 0;
74
+ pointer-events: all;
75
+ }
76
+ .h-splitter:hover {
77
+ cursor: row-resize;
78
+ opacity: 1;
79
+ }
80
+ </style>
@@ -0,0 +1,152 @@
1
+
2
+ // Extension's controller
3
+
4
+ import { Utils } from 'trading-vue-js'
5
+ import Vue from 'vue'
6
+ import Splitter from './Splitter.vue'
7
+
8
+ export default class Main {
9
+
10
+ constructor(tv, dc, sett) {
11
+
12
+ this.widgets = {}
13
+ this.tv = tv
14
+ this.dc = dc
15
+ this.sett = sett
16
+
17
+ setTimeout(() => {
18
+
19
+ this.tv.$el.addEventListener(
20
+ 'mousemove', this.onmousemove.bind(this)
21
+ )
22
+
23
+ this.tv.$el.addEventListener(
24
+ 'mouseup', this.onmouseup.bind(this)
25
+ )
26
+
27
+ this.tv.$el.addEventListener(
28
+ 'mouseleave', this.onmouseleave.bind(this)
29
+ )
30
+
31
+ this.place_splitters()
32
+ this.calc_heights()
33
+
34
+ // Track changes of grids count
35
+ this.tv.$watch(x =>
36
+ this.dc.get('.').map(x => x.id),
37
+ this.ongrids.bind(this))
38
+
39
+ })
40
+
41
+ }
42
+
43
+ // Listens to all tvjs events, creates new widgets
44
+ update(e) {
45
+ switch(e.event) {
46
+
47
+ }
48
+ }
49
+
50
+ // Extension settings has changed
51
+ onsettings(sett) {}
52
+
53
+ ongrids() {
54
+ setTimeout(() => {
55
+ this.remove_widgets()
56
+ this.place_splitters()
57
+ })
58
+ }
59
+
60
+ onmousemove(e) {
61
+ // List of widgets created by this controller
62
+ let list = this.tv.$refs.widgets.$children
63
+ .filter(x => x.main === this)
64
+
65
+ for (var s of list) {
66
+ s.hs_mousemove(e)
67
+ }
68
+ }
69
+
70
+ onmouseup(e) {
71
+ // List of widgets created by this controller
72
+ let list = this.tv.$refs.widgets.$children
73
+ .filter(x => x.main === this)
74
+
75
+ for (var s of list) {
76
+ s.hs_mouseup(e)
77
+ }
78
+ }
79
+
80
+ onmouseleave(e) {
81
+ // List of widgets created by this controller
82
+ let list = this.tv.$refs.widgets.$children
83
+ .filter(x => x.main === this)
84
+
85
+ for (var s of list) {
86
+ s.hs_mouseleave(e)
87
+ }
88
+ }
89
+
90
+ place_splitters() {
91
+ let grids = this.tv.$refs.chart._layout.grids
92
+ for (var i = 1; i < grids.length; i++) {
93
+ let g1 = grids[i-1]
94
+ let g2 = grids[i]
95
+ let id = `Splitter-${g1.id}-${g2.id}-${Utils.uuid2()}`
96
+ Vue.set(this.widgets, id, {
97
+ id: id,
98
+ cls: Splitter,
99
+ data: {
100
+ grid1: g1,
101
+ grid2: g2,
102
+ sett: this.sett
103
+ }
104
+ })
105
+ }
106
+ }
107
+
108
+ calc_heights() {
109
+ let hs = []
110
+ for (var g of this.tv.$refs.chart._layout.grids) {
111
+ hs.push(g.height)
112
+ }
113
+ let sum = hs.reduce((a, b) => a + b, 0)
114
+ hs = hs.map(h => h / sum)
115
+ this.grid_ovs().forEach((ov, i) => {
116
+ if (!ov.grid) {
117
+ Vue.set(ov, 'grid', {})
118
+ }
119
+ Vue.set(ov.grid, 'height', hs[i] || 1)
120
+ })
121
+ }
122
+
123
+ // Grid defining overlays
124
+ grid_ovs() {
125
+ let list = [this.dc.data.chart]
126
+ for (var ov of this.dc.data.offchart) {
127
+ if (!ov.grid || ov.grid.id === undefined) {
128
+ list.push(ov)
129
+ }
130
+ }
131
+ return list
132
+ }
133
+
134
+ remove_widgets() {
135
+ for (var id in this.widgets) {
136
+ this.tv.$delete(this.widgets, id)
137
+ }
138
+ }
139
+
140
+ destroy() {
141
+ this.tv.$el.removeEventListener(
142
+ 'mousemove', this.onmousemove
143
+ )
144
+ this.tv.$el.removeEventListener(
145
+ 'mouseup', this.mouseup
146
+ )
147
+ this.tv.$el.removeEventListener(
148
+ 'mouseleave', this.mouseleave
149
+ )
150
+ }
151
+
152
+ }
@@ -0,0 +1,25 @@
1
+ export default {
2
+
3
+ add_style(id, style) {
4
+
5
+ var stbr = document.getElementById(id)
6
+ if (stbr) {
7
+ var sheetParent = stbr.parentNode
8
+ sheetParent.removeChild(stbr)
9
+ }
10
+
11
+ var sheet = document.createElement('style')
12
+ sheet.setAttribute("id", id)
13
+ sheet.innerHTML = style
14
+ document.body.appendChild(sheet)
15
+ },
16
+
17
+ rem_style(id, style) {
18
+ var stbr = document.getElementById(id)
19
+ if (stbr) {
20
+ var sheetParent = stbr.parentNode
21
+ sheetParent.removeChild(stbr)
22
+ }
23
+ }
24
+
25
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "grid-resize",
3
+ "author": "StdSquad",
4
+ "version": "1.0.0",
5
+ "components": [],
6
+ "widgets": [],
7
+ "overlays": [],
8
+ "skins": [],
9
+ "colorpacks": [],
10
+ "deps": {}
11
+ }
@@ -0,0 +1,91 @@
1
+ <template>
2
+ <window title="Add Overlay" class="add-win"
3
+ @close="on_close" :tv='tv'>
4
+ <div class="add-win-list">
5
+ <div v-for="ov of ovs" class="add-win-item"
6
+ @click="on_click(ov.name)">
7
+ <span>{{ov.name}}</span>
8
+ <span class="add-win-item-desc">
9
+ {{ov.methods.meta_info().desc}}
10
+ </span>
11
+ </div>
12
+ </div>
13
+ </window>
14
+ </template>
15
+ <script>
16
+
17
+ import Window from '../../components/Window.vue'
18
+
19
+ export default {
20
+ name: 'AddWin',
21
+ props: ['id', 'main', 'dc', 'tv', 'data'],
22
+ components: { Window },
23
+ mounted() {
24
+ },
25
+ methods: {
26
+ on_close() {
27
+ this.$props.main.remove_widget(this.$props.id)
28
+ },
29
+ on_click(name) {
30
+ this.on_close()
31
+ this.main.add_overlay({
32
+ side: this.data.type,
33
+ index: this.data.index,
34
+ type: name
35
+ })
36
+ }
37
+ },
38
+ computed: {
39
+ sett() {
40
+ return this.$props.data.ov.settings
41
+ }
42
+ },
43
+ data() {
44
+ return {
45
+ ovs: this.tv.overlays.filter(x => x.methods.calc)
46
+ }
47
+ }
48
+ }
49
+ </script>
50
+ <style scoped>
51
+ .tvjs-x-window.add-win {
52
+ padding-bottom: 30px;
53
+ border: 1px solid #80808011;
54
+ }
55
+ .add-win-list {
56
+ height: 300px;
57
+ overflow-x: hidden;
58
+ overflow-y: auto;
59
+ user-select: none;
60
+ }
61
+ /* Hide scrollbar for Chrome, Safari and Opera */
62
+ .add-win-list::-webkit-scrollbar {
63
+ display: none;
64
+ }
65
+
66
+ /* Hide scrollbar for IE, Edge and Firefox */
67
+ .add-win-list {
68
+ -ms-overflow-style: none; /* IE and Edge */
69
+ scrollbar-width: none; /* Firefox */
70
+ }
71
+ .add-win-item {
72
+ color: #ffffff88;
73
+ width: 100%;
74
+ padding: 5px;
75
+ cursor: pointer;
76
+ }
77
+ .add-win-item:hover {
78
+ background: #88888822;
79
+ color: #ffffffff;
80
+ }
81
+ .add-win-item-desc {
82
+ color: #ffffff33;
83
+ margin-left: 3px;
84
+ }
85
+ .add-win-item:hover .add-win-item-desc {
86
+ color: #ffffff44;
87
+ }
88
+ .add-win-empty {
89
+ opacity: 0.5;
90
+ }
91
+ </style>