Skip to content

Commit

Permalink
feat: Support custom user commands, loading animations
Browse files Browse the repository at this point in the history
The new `command` action accepts two parameters, like macros, so that commands
can be identified either by title or (more efficiently) by the cncjs ID assigned
to them.
When a command runs, the button which triggered it (and all other buttons with
the same action) will be put into a loading state, which will end when the command
completes,
whether successfully or unsuccessfully.

In both the web and Stream Deck version, this loading animation is a simple
rotating ring, using the configured progress color. This animation and color
configuration may change in the future

issue #8
  • Loading branch information
Billiam committed Aug 25, 2022
1 parent c8a560e commit 889ba37
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 52 deletions.
33 changes: 13 additions & 20 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 55 additions & 2 deletions src/components/Cell.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { computed, inject, ref } from 'vue'
import { useText } from '@/lib/cell/text'
import { useColor } from '@/lib/cell/color'
import { useVisibility } from '@/lib/cell/visibility'
import { useLoading } from '@/lib/cell/loading'
</script>
<script setup>
const cnc = useCncStore()
Expand Down Expand Up @@ -48,6 +49,7 @@ const {
textString,
} = useText(props.config)
const { show, enabled } = useVisibility(props.config, buttonActions)
const { loading } = useLoading(props.config)
const gridPosition = computed(() => {
return {
Expand Down Expand Up @@ -85,6 +87,14 @@ const gridPosition = computed(() => {
>
<span class="button-text" v-text="textString"></span>
</span>

<svg
v-if="loading"
class="loading-animation centered-decoration"
viewBox="0 0 100 100"
>
<circle class="loading-circle" cx="50" cy="50" r="40" />
</svg>
</cell-button>
</div>
</template>
Expand Down Expand Up @@ -165,7 +175,26 @@ const gridPosition = computed(() => {
text-align: center;
}
}
.loading {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
margin: auto;
aspect-ratio: 1/1;
}
.loading-circle {
animation: loading-animation 5s linear infinite;
fill: none;
stroke-width: 5px;
stroke-linecap: round;
stroke-dasharray: 360;
stroke-dashoffset: 360;
transform-origin: 50% 50%;
transform: rotate(-90deg);
filter: drop-shadow(0 0 10px black);
}
.button {
position: relative;
border: 0;
Expand Down Expand Up @@ -203,7 +232,28 @@ const gridPosition = computed(() => {
stroke-dashoffset: 0;
}
}
@keyframes loading-animation {
0% {
stroke-dashoffset: 360;
transform: rotate(0);
}
25% {
stroke-dashoffset: 235;
transform: rotate(360deg);
}
50% {
stroke-dashoffset: 110;
transform: rotate(720deg);
}
75% {
stroke-dashoffset: 235;
transform: rotate(1080deg);
}
100% {
stroke-dashoffset: 360;
transform: rotate(1440deg);
}
}
.centered-decoration {
position: absolute;
margin: 0 auto;
Expand All @@ -226,6 +276,9 @@ const gridPosition = computed(() => {
:deep(.progress-bar-meter) {
stroke: v-bind(cellProgressColor);
}
.loading-circle {
stroke: v-bind(cellProgressColor);
}
.cell {
background-color: v-bind(cellBgColor);
grid-row-start: v-bind(gridPosition.startRow);
Expand Down
44 changes: 23 additions & 21 deletions src/lib/cli/button-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,27 +120,29 @@ const getRender = async (config, canvas, directory) => {
const holdBuffer = Buffer.from(svg)
finalComposite.push({ input: holdBuffer, top: 0, left: 0 })
}
// if (config.holdPercent) {
// // if (config.holdPercent === 1) {
// // console.log({ config })
// // }
// const radius = Math.min(outputHeight, outputWidth) * 0.4
// const circ = radius * 2 * Math.PI
// const svg = `<svg width="${outputWidth}px" height="${outputHeight}px">
// <circle
// stroke="${config.cellProgressColor}"
// fill="none"
// stroke-width="25px"
// stroke-linecap="round"
// stroke-dasharray="${circ}"
// stroke-dashoffset="${circ - config.holdPercent * circ}"
// cx="${outputWidth / 2}"
// cy="${outputHeight / 2}"
// r="${radius}" />
// </svg>`
// const holdBuffer = Buffer.from(svg)
// finalComposite.push({ input: holdBuffer, top: 0, left: 0 })
// }

if (config.loadingPercent != null) {
const radius = Math.min(outputHeight, outputWidth) * 0.4
const circ = radius * 2 * Math.PI
const rotation = 360 * config.loadingPercent * 3
const dashOffset = ((config.loadingPercent + 0.5) % 1) * 2 - 1

const svg = `<svg width="${outputWidth}px" height="${outputHeight}px">
<circle
stroke="${config.cellProgressColor}"
fill="none"
stroke-width="8px"
stroke-linecap="round"
stroke-dasharray="${circ}"
stroke-dashoffset="${circ - dashOffset * circ}"
transform="rotate(${rotation} ${outputWidth / 2} ${outputHeight / 2})"
cx="${outputWidth / 2}"
cy="${outputHeight / 2}"
r="${radius}" />
</svg>`
const holdBuffer = Buffer.from(svg)
finalComposite.push({ input: holdBuffer, top: 0, left: 0 })
}

if (!config.enabled) {
finalComposite.push({
Expand Down
33 changes: 31 additions & 2 deletions src/lib/cli/button.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useLoading } from '@/lib/cell/loading'
import { useText } from '@/lib/cell/text'
import { useVisibility } from '@/lib/cell/visibility'
import CliButtonHandler from '@/lib/cli/button-handler'
Expand Down Expand Up @@ -47,8 +48,8 @@ export default class CliButton {
})
}

watch(key, callback) {
this.watchers.push(watch(key, callback))
watch(key, callback, options = {}) {
this.watchers.push(watch(key, callback, options))
}

watchEffect(callback) {
Expand Down Expand Up @@ -79,6 +80,8 @@ export default class CliButton {
)
const { renderGcode, gcodeColors } = useGcode(this.config)
const { show, enabled } = useVisibility(this.config, this.buttonActions)
const { loading } = useLoading(this.config)

this.show = show
this.enabled = enabled

Expand Down Expand Up @@ -114,6 +117,31 @@ export default class CliButton {
}
})

const loadingPercent = ref(null)
let loadingAnimation
this.watch(
loading,
(current) => {
if (loadingAnimation) {
loadingAnimation.cancel()
loadingAnimation = null
loadingPercent.value = null
}
if (current) {
loadingAnimation = animation({
duration: 5000,
fps: 60,
loop: true,
callback: (percent) => {
loadingPercent.value = percent
},
})
loadingAnimation.start()
}
},
{ immediate: !!loading.value }
)

const gcodeLine = ref()
const updateGcodeLine = (index) => {
gcodeLine.value = index
Expand Down Expand Up @@ -188,6 +216,7 @@ export default class CliButton {
fontSize,
gcodeLine,
holdPercent,
loadingPercent,
renderGcode,
textSvgAlignment,
textSvgVerticalAlignment,
Expand Down
18 changes: 14 additions & 4 deletions src/lib/cnc-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,28 @@ if (import.meta.env.SSR) {
}

export default (token, host, port) => {
const apiFetch = async (path, params) => {
const fetchParams = new URLSearchParams({
const url = (path, params) => {
const queryParams = new URLSearchParams({
token,
...params,
})
const apiUrl = `http://${host}:${port}/api/${path}?${fetchParams}`
return `http://${host}:${port}/api/${path}?${queryParams}`
}

const apiFetch = async (path, params) => {
const fetchUrl = url(path, params)
const results = await fetchImplementation(fetchUrl)
return results.json()
}

const results = await fetchImplementation(apiUrl)
const apiPost = async (path, params) => {
const postUrl = url(path, params)
const results = await fetchImplementation(postUrl, { method: 'POST' })
return results.json()
}

return {
fetch: apiFetch,
post: apiPost,
}
}
3 changes: 3 additions & 0 deletions src/lib/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ proto.debug = function () {
socket.on('connecting', (a) => {
console.debug('Connecting')
})
socket.on('connect', (data) => {
console.log('connected', data)
})
socket.on('connect_error', (err) => {
console.debug(`connect_error due to ${err.message}`, err)
})
Expand Down
6 changes: 6 additions & 0 deletions src/lib/state-feeder.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ export default (socket, ackBus) => {
cnc.setError(msg)
}
},
'task:finish': (task, code) => {
cnc.clearActiveCommand(task)
},
'feeder:status': (status) => {
if (!status.hold) {
cnc.clearFeedHold()
Expand All @@ -91,6 +94,9 @@ export default (socket, ackBus) => {
cnc.setConnected(false)
}
},
connect: () => {
cnc.clearActiveCommands()
},
}
const workerListeners = {
message: (e) => {
Expand Down
12 changes: 12 additions & 0 deletions src/services/button-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,17 @@ export default (actionBus, connectionBus) => {
}
}

const userCommand = async (commandId, commandName) => {
if (!commandId && commandName) {
commandId = await store.cnc.getCommandId(commandName)
if (!commandId) {
console.error(`Requested command "${commandName}" could not be found`)
return
}
}
store.cnc.runCommand(commandId)
}

const macro = async (macroId, macroName) => {
if (!macroId && macroName) {
macroId = await store.cnc.getMacroId(macroName)
Expand Down Expand Up @@ -334,6 +345,7 @@ export default (actionBus, connectionBus) => {
brightness,
clearGcode,
clearUserFlag,
command: userCommand,
completeInput,
connect,
decreaseFeedrate,
Expand Down
Loading

0 comments on commit 889ba37

Please sign in to comment.