summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJules Laplace <julescarbon@gmail.com>2020-06-08 00:53:10 +0200
committerJules Laplace <julescarbon@gmail.com>2020-06-08 00:53:10 +0200
commit734c19347e5ff307c2412289248f95dc66db94f1 (patch)
tree11dfa40e49275f54154bc46212d5078df843209f
parent084333904ab589788a121b44461f242006545594 (diff)
slider component
-rw-r--r--frontend/common/index.js1
-rw-r--r--frontend/common/slider.component.js98
-rw-r--r--frontend/views/graph/components/graph.editor.js28
3 files changed, 114 insertions, 13 deletions
diff --git a/frontend/common/index.js b/frontend/common/index.js
index 6f9747a..3647203 100644
--- a/frontend/common/index.js
+++ b/frontend/common/index.js
@@ -19,6 +19,7 @@ export { default as CopyToClipboardButton } from './copyToClipboardButton.compon
export { default as ImageCrop } from './imageCrop.component'
export { Modal } from './modal.component'
export { default as UploadImage } from './uploadImage.component'
+export { default as Slider } from './slider.component'
import './fonts.css'
import './app.css'
diff --git a/frontend/common/slider.component.js b/frontend/common/slider.component.js
new file mode 100644
index 0000000..70a4abd
--- /dev/null
+++ b/frontend/common/slider.component.js
@@ -0,0 +1,98 @@
+import { React, Component } from 'preact'
+
+const SLIDER_THROTTLE_TIME = 100
+
+export default class Slider extends Component {
+ constructor(props){
+ super(props)
+ this.timeout = 0
+ this.state = {
+ value: props.value
+ }
+ this.handleInput = this.handleInput.bind(this)
+ this.handleRange = this.handleRange.bind(this)
+ }
+ UNSAFE_componentWillReceiveProps(nextProps) {
+ let next_value = nextProps.value || nextProps.opt[nextProps.name]
+ if (next_value !== this.state.value) {
+ if (this.props.type === 'int') {
+ next_value = parseInt(next_value)
+ }
+ this.setState({ value: next_value })
+ }
+ }
+ handleInput(e){
+ let { name, opt } = this.props
+ let old_value = opt[name]
+ let new_value = e.target.value
+ if (new_value === '') {
+ new_value = this.props.defaultValue || (this.props.max - this.props.min) / 2
+ }
+ else if (this.props.type === 'int') {
+ new_value = parseInt(new_value)
+ }
+ else if (this.props.type === 'odd') {
+ new_value = parseInt(Math.floor(new_value / 2) * 2 + 1)
+ }
+ if (old_value !== new_value) {
+ this.setState({ value: new_value })
+ this.props.onChange && this.props.onChange(new_value)
+ }
+ clearTimeout(this.timeout)
+ }
+ handleRange(e){
+ clearTimeout(this.timeout)
+ let new_value = e.target.value
+ if (this.props.type === 'int') {
+ new_value = parseInt(new_value)
+ }
+ if (this.props.type === 'odd') {
+ new_value = parseInt(Math.floor(new_value / 2) * 2 + 1)
+ }
+ if (this.props.type === 'list') {
+ new_value = this.props.options[new_value] || this.props.options[0]
+ }
+ this.setState({ value: new_value })
+ this.timeout = setTimeout(() => {
+ this.props.onChange && this.props.onChange(new_value)
+ }, SLIDER_THROTTLE_TIME)
+ }
+ render(){
+ let { name, title } = this.props
+ let value = this.state.value
+ if (typeof value === 'undefined') {
+ value = this.props.min
+ }
+ let text_value = value
+ let step;
+ let min = this.props.min || 0
+ let max = this.props.max || 0
+ if (this.props.type === 'int') {
+ step = 1
+ } else if (this.props.type === 'list') {
+ min = 0
+ max = this.props.options.length-1
+ step = 1
+ value = this.props.options.indexOf(value)
+ } else {
+ step = (this.props.max - this.props.min) / 100
+ text_value = parseFloat(value).toFixed(2)
+ }
+ return (
+ <div className='slider param'>
+ <label>
+ <span>{title || name.replace(/_/g, ' ')}</span>
+ <input type='text' value={text_value} onBlur={this.handleInput} />
+ </label>
+ <input
+ type='range'
+ min={min}
+ max={max}
+ step={step}
+ value={value}
+ onInput={this.handleRange}
+ />
+ </div>
+ )
+ }
+}
diff --git a/frontend/views/graph/components/graph.editor.js b/frontend/views/graph/components/graph.editor.js
index f8b45f9..87109bf 100644
--- a/frontend/views/graph/components/graph.editor.js
+++ b/frontend/views/graph/components/graph.editor.js
@@ -182,6 +182,10 @@ class GraphEditor extends Component {
}
const DEFAULT_MEASUREMENT = { width: 16, height: 16 }
+const BACKLINK_SPACING = 10
+const ARROWHEAD_LENGTH = 10
+const GRAPH_LINK_COLOR = "#ff88ff"
+const GRAPH_BACKLINK_COLOR = "#88ffff"
class GraphCanvas extends Component {
constructor(props) {
@@ -207,7 +211,6 @@ class GraphCanvas extends Component {
canvas.width = width
canvas.height = height
}
- console.log(measurements)
const ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, width, height)
ctx.lineWidth = 2
@@ -234,11 +237,11 @@ class GraphCanvas extends Component {
const targetCoord = coordsLookup[tile.page_id]
let tile_measurement = measurements[tile.page_id] || DEFAULT_MEASUREMENT
let target_measurement = measurements[tile.target_page_id] || DEFAULT_MEASUREMENT
- let x1_offset = tile_measurement.width / 2
+ let theta = angle(targetCoord.x, targetCoord.y, sourceCoord.x, sourceCoord.y)
+ let x1_offset = tile_measurement.width / 2 // * (0.5 - Math.cos(theta))
let y1_offset = tile_measurement.height / 2
- let x2_offset = target_measurement.width / 2
+ let x2_offset = target_measurement.width / 2 // (0.5 - Math.cos(theta))
let y2_offset = target_measurement.height / 2
- let theta = angle(targetCoord.x, targetCoord.y, sourceCoord.x, sourceCoord.y)
// skip duplicate links
if (sourceCoord.backlinks.has(tile.page_id)) {
return
@@ -246,13 +249,13 @@ class GraphCanvas extends Component {
// if this is the first time encountering this link...
if (!targetCoord.backlinks.has(tile.target_page_id)) {
sourceCoord.backlinks.add(tile.page_id)
- ctx.strokeStyle = "#ff88ff"
+ ctx.strokeStyle = GRAPH_LINK_COLOR
} else { // otherwise this is a two-way link
- x1_offset += 10 * Math.cos(theta + Math.PI /2)
- y1_offset += 10 * Math.sin(theta + Math.PI /2)
- x2_offset += 10 * Math.cos(theta + Math.PI /2)
- y2_offset += 10 * Math.sin(theta + Math.PI /2)
- ctx.strokeStyle = "#88ffff"
+ x1_offset += BACKLINK_SPACING * Math.cos(theta + Math.PI /2)
+ y1_offset += BACKLINK_SPACING * Math.sin(theta + Math.PI /2)
+ x2_offset += BACKLINK_SPACING * Math.cos(theta + Math.PI /2)
+ y2_offset += BACKLINK_SPACING * Math.sin(theta + Math.PI /2)
+ ctx.strokeStyle = GRAPH_BACKLINK_COLOR
}
ctx.beginPath()
const x1 = targetCoord.x * width + x1_offset
@@ -266,7 +269,6 @@ class GraphCanvas extends Component {
}
arrow(ctx, x1, y1, x2, y2) {
- const headlen = 10 // length of head in pixels
const farOffset = 20
const endOffset = 1
const theta = angle(x1, y1, x2, y2)
@@ -281,9 +283,9 @@ class GraphCanvas extends Component {
ctx.moveTo(x1, y1)
ctx.lineTo(xEnd, yEnd)
ctx.moveTo(x2, y2)
- ctx.lineTo(x2 - headlen * Math.cos(leftAngle), y2 - headlen * Math.sin(leftAngle))
+ ctx.lineTo(x2 - ARROWHEAD_LENGTH * Math.cos(leftAngle), y2 - ARROWHEAD_LENGTH * Math.sin(leftAngle))
ctx.moveTo(x2, y2)
- ctx.lineTo(x2 - headlen * Math.cos(rightAngle), y2 - headlen * Math.sin(rightAngle))
+ ctx.lineTo(x2 - ARROWHEAD_LENGTH * Math.cos(rightAngle), y2 - ARROWHEAD_LENGTH * Math.sin(rightAngle))
}
render() {