How about this?
![coordSliderView](https://us1.discourse-cdn.com/inductiveautomation/original/3X/b/6/b6e2822c36a58f75609bdd5488f8a89fca8c5f3f.gif)
The green line is generated using a label with a border width of 1 and height of 2. The main CSS trick is the transform : skewY()
.
{
"borderStyle": "solid",
"borderWidth": 1
"borderColor": "#00aa00",
"transform": "skewY(0.0deg)" <-- See the binding.
}
- I'm using a coordinate view just to make the (x, y) coordinates easy to work with.
- I have custom properties on each slider keeping track of the slider knob x and y positions.
- The skew is calculated using
atan(dy/dx) * 180 / 3.1416
to return degrees.
- My animation was recorded on my development machine so it should be best case regarding lagginess of the line component. It may look atrociously bad with a slow connection.
Try pasting the view into Project Browser | Perspective | Views.
coordSliderView
{
"custom": {},
"params": {},
"props": {
"defaultSize": {
"height": 328,
"width": 412
}
},
"root": {
"children": [
{
"meta": {
"name": "lblLine01"
},
"position": {
"height": 2
},
"propConfig": {
"custom.skew": {
"binding": {
"config": {
"expression": "atan(\r\n ({../Slider1.custom.knobY} - {../Slider0.custom.knobY})\r\n / ({../Slider1.custom.knobX} - {../Slider0.custom.knobX})\r\n)"
},
"type": "expr"
}
},
"position.width": {
"binding": {
"config": {
"expression": "{../Slider1.custom.knobX} - {../Slider0.custom.knobX}"
},
"type": "expr"
}
},
"position.x": {
"binding": {
"config": {
"path": "../Slider0.custom.knobX"
},
"type": "property"
}
},
"position.y": {
"binding": {
"config": {
"expression": "({../Slider0.custom.knobY} + {../Slider1.custom.knobY}) / 2\r\n"
},
"type": "expr"
}
},
"props.style.transform": {
"binding": {
"config": {
"expression": "\"skewY(\" + {this.custom.skew} * 180 / 3.1416 + \"deg)\""
},
"type": "expr"
}
}
},
"props": {
"style": {
"borderColor": "#00aa00",
"borderStyle": "solid",
"borderWidth": 1
}
},
"type": "ia.display.label"
},
{
"meta": {
"name": "Slider0"
},
"position": {
"height": 200,
"width": 20,
"x": 80,
"y": 40
},
"propConfig": {
"custom.knobX": {
"binding": {
"config": {
"expression": "{this.position.x} + {this.position.width} / 2"
},
"type": "expr"
}
},
"custom.knobY": {
"binding": {
"config": {
"expression": "{this.position.y} + {this.position.height} \r\n- ({this.props.value} - {this.props.min})\r\n/ ({this.props.max} - {this.props.min})\r\n* {this.position.height}"
},
"type": "expr"
}
}
},
"props": {
"orientation": "vertical",
"value": 54
},
"type": "ia.input.slider"
},
{
"meta": {
"name": "Slider1"
},
"position": {
"height": 200,
"width": 20,
"x": 280,
"y": 40
},
"propConfig": {
"custom.knobX": {
"binding": {
"config": {
"expression": "{this.position.x} + {this.position.width} / 2"
},
"type": "expr"
}
},
"custom.knobY": {
"binding": {
"config": {
"expression": "{this.position.y} + {this.position.height} \r\n- ({this.props.value} - {this.props.min})\r\n/ ({this.props.max} - {this.props.min})\r\n* {this.position.height}"
},
"type": "expr"
}
}
},
"props": {
"orientation": "vertical",
"value": 79
},
"type": "ia.input.slider"
},
{
"meta": {
"name": "Label"
},
"position": {
"height": 32,
"rotate": {
"anchor": "38% 50%"
},
"width": 50,
"x": 65,
"y": 249
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "../Slider0.props.value"
},
"type": "property"
}
}
},
"props": {
"textStyle": {
"textAlign": "center"
}
},
"type": "ia.display.label"
},
{
"meta": {
"name": "Label_0"
},
"position": {
"height": 32,
"rotate": {
"anchor": "38% 50%"
},
"width": 50,
"x": 265,
"y": 249
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "../Slider1.props.value"
},
"type": "property"
}
}
},
"props": {
"textStyle": {
"textAlign": "center"
}
},
"type": "ia.display.label"
}
],
"meta": {
"name": "root"
},
"type": "ia.container.coord"
}
}