Skip to content

Commit

Permalink
Merge pull request #57 from positlabs/preview
Browse files Browse the repository at this point in the history
Webcam preview #50 control for each field
  • Loading branch information
positlabs authored Jul 6, 2019
2 parents b45b728 + 1ed27c5 commit c257865
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 91 deletions.
119 changes: 80 additions & 39 deletions examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@
GET_DEF: 0x87,
}

const FIELD_TYPE = {
BOOLEAN: 'BOOLEAN',
BITMAP: 'BITMAP',
NUMBER: 'NUMBER',
}

const video = document.querySelector('video')
const camSelector = document.querySelector('select')
const camControls = document.querySelector('.cam-controls')
Expand Down Expand Up @@ -93,65 +99,100 @@
console.log(controlDescriptions)

const camControlsHTML = await Promise.all(controlDescriptions.map(async ctrl => {
// TODO support controls with multiple fields

let currentVal = await fetch(`/get/${ctrl.name}`).then(res => res.json())
console.log('currentVal', ctrl.name, currentVal)

currentVal = Object.values(currentVal)[0]
// console.log(ctrl.fields[0].type)
const fieldControlsHTML = await Promise.all(ctrl.fields.map(async (field, i) => {
// console.log(field)
const fieldVal = currentVal[field.name]
const id = `${ctrl.name}-${field.name}`

if (ctrl.requests.indexOf(REQUEST.GET_MIN) !== -1) {
try {
const minMax = await fetch(`/range/${ctrl.name}`).then(res => res.json())
return `<div class='range ctrl'><label for='${id}'>${field.name}</label><input id='${id}' type='range' min='${minMax.min}' max='${minMax.max}' value='${fieldVal}'></input></div>`
} catch (e) {
return ''
}
} else if (field.options) {

if (ctrl.requests.indexOf(REQUEST.GET_MIN) !== -1) {
// range
// console.log('range', ctrl.name)
try {
const minMax = await fetch(`/range/${ctrl.name}`).then(res => res.json())
return `<div class='range ctrl'><label for='${ctrl.name}'>${ctrl.name}</label><input id='${ctrl.name}' type='range' min='${minMax.min}' max='${minMax.max}' value='${currentVal}'></input></div>`
} catch (e) {
let options = Object.entries(field.options).map(([key, val]) => {
const selected = fieldVal === val ? 'selected' : ''
return `<option value='${val}' ${selected}>${key}</option>`
})
return `<div class='select ctrl'><label for='${id}'>${field.name}</label><select id='${id}'>${options}</select></input></div>`

} else if (field.type === FIELD_TYPE.BOOLEAN) {
return `<div class='bool ctrl'><label for='${id}'>${field.name}</label><input type='checkbox' id='${id}' checked='${fieldVal}'></div>`
} else {
return ''
}
} else if (ctrl.fields[0].options) {

let options = Object.entries(ctrl.fields[0].options).map(([key, val]) =>
`<option value='${val}'>${key}</option>`)
// TODO set selected index
return `<div class='select ctrl'><label for='${ctrl.name}'>${ctrl.name}</label><select id='${ctrl.name}'>${options}</select></input></div>`
}))
return `<div id='${ctrl.name}'><h3>${ctrl.name}</h3>${fieldControlsHTML.join('')}</div>`

} else if (ctrl.fields[0].type === 'Boolean') {
return `<div class='bool ctrl'><label for='${ctrl.name}'>${ctrl.name}</label><input type='checkbox' id='${ctrl.name}' checked='${currentVal}'></div>`
} else {
return ''
}
}))
camControls.innerHTML += camControlsHTML.join('')

document.querySelectorAll('.range.ctrl input').forEach(ctrlEl => {
const listenForFieldControlChanges = (ctrlEl) => {
ctrlEl.addEventListener('change', (e) => {
console.log(ctrlEl.id, ctrlEl.value)
fetch(`/set/${ctrlEl.id}/${ctrlEl.value}`, {
const [controlId] = ctrlEl.id.split('-')
const values = getSiblingFieldValues(controlId).join()
fetch(`/set/${controlId}/${values}`, {
method: 'POST'
})
})
})
}
document.querySelectorAll('.range.ctrl input').forEach(listenForFieldControlChanges)
document.querySelectorAll('.select.ctrl select').forEach(listenForFieldControlChanges)
document.querySelectorAll('.bool.ctrl input').forEach(listenForFieldControlChanges)

// document.querySelectorAll('.range.ctrl input').forEach(ctrlEl => {
// ctrlEl.addEventListener('change', (e) => {
// console.log(ctrlEl.id, ctrlEl.value)
// const [controlId] = ctrlEl.id.split('-')
// const values = getSiblingFieldValues(controlId).join()
// fetch(`/set/${controlId}/${values}`, {
// method: 'POST'
// })
// })
// })

// document.querySelectorAll('.select.ctrl select').forEach(ctrlEl => {
// ctrlEl.addEventListener('change', (e) => {
// console.log(ctrlEl.id, ctrlEl.value)
// const [controlId] = ctrlEl.id.split('-')
// const values = getSiblingFieldValues(controlId).join()
// fetch(`/set/${controlId}/${values}`, {
// method: 'POST'
// })
// })
// })

// document.querySelectorAll('.bool.ctrl input').forEach(ctrlEl => {
// ctrlEl.addEventListener('change', (e) => {
// console.log(ctrlEl.checked)
// const [controlId] = ctrlEl.id.split('-')
// const values = getSiblingFieldValues(controlId).join()
// fetch(`/set/${controlId}/${values}`, {
// method: 'POST'
// })
// })
// })

document.querySelectorAll('.select.ctrl select').forEach(ctrlEl => {
ctrlEl.addEventListener('change', (e) => {
console.log(ctrlEl.id, ctrlEl.value)
fetch(`/set/${ctrlEl.id}/${ctrlEl.value}`, {
method: 'POST'
})
})
})
}

document.querySelectorAll('.bool.ctrl input').forEach(ctrlEl => {
ctrlEl.addEventListener('change', (e) => {
console.log(ctrlEl.checked)
fetch(`/set/${ctrlEl.id}/${ctrlEl.checked ? 1 : 0}`, {
method: 'POST'
})
})
function getSiblingFieldValues(controlId) {
const controlDiv = document.querySelector(`#${controlId}`)
const values = []
controlDiv.querySelectorAll('.ctrl').forEach(ctrl => {
const input = ctrl.querySelector('input, select')
if (input.type === 'checkbox') values.push(input.checked ? 1 : 0)
else values.push(input.value)
})

return values
}
setup()
</script>
Expand Down
5 changes: 0 additions & 5 deletions examples/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,6 @@ app.get('/range/:control', (req, res) => {

app.post('/set/:control/:values', (req, res) => {
let values = req.params.values.split(',')
// values = values.map(val => {
// if (val === 'true') return 1
// else if (val === 'false') return 0
// else return val
// })
console.log('setting', req.params.control, values)
cam.set(req.params.control, ...values).then(vals => {
res.send('ok')
Expand Down
3 changes: 2 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const {
// VS,
// VS_DESCRIPTOR_SUBTYPE,
BM_REQUEST_TYPE,
FIELD_TYPE,
REQUEST,
KEY,
} = require('./lib/constants')
Expand Down Expand Up @@ -181,7 +182,7 @@ class UVCControl extends EventEmitter {
// NOTE min fixes out of bounds error, but this approach doesn't account for multiple fields...
let int = buffer.readIntLE(field.offset, Math.min(buffer.byteLength, field.size))
let result = int
if (field.type === 'Boolean') {
if (field.type === FIELD_TYPE.BOOLEAN) {
result = Boolean(int)
}
const results = {
Expand Down
7 changes: 7 additions & 0 deletions lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ const KEY = {
PAL_525_60: 'PAL_525_60',
}

const FIELD_TYPE = {
BOOLEAN: 'BOOLEAN',
BITMAP: 'BITMAP',
NUMBER: 'NUMBER',
}

const BM_REQUEST_TYPE = {
GET: 0b10100001,
SET: 0b00100001,
Expand Down Expand Up @@ -183,4 +189,5 @@ module.exports = {
REQUEST,
BM_REQUEST_TYPE,
VS_DESCRIPTOR_SUBTYPE,
FIELD_TYPE,
}
Loading

0 comments on commit c257865

Please sign in to comment.