This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-09-26
Channels
- # 100-days-of-code (3)
- # announcements (2)
- # beginners (237)
- # bitcoin (2)
- # boot (5)
- # cider (15)
- # cljs-dev (9)
- # cljsrn (6)
- # clojure (75)
- # clojure-estonia (1)
- # clojure-italy (8)
- # clojure-losangeles (1)
- # clojure-nl (1)
- # clojure-spec (68)
- # clojure-uk (80)
- # clojurescript (89)
- # cursive (31)
- # datomic (22)
- # emacs (2)
- # events (3)
- # figwheel-main (184)
- # fulcro (28)
- # graphql (1)
- # hyperfiddle (2)
- # jobs (1)
- # jobs-discuss (64)
- # luminus (5)
- # off-topic (16)
- # om (2)
- # onyx (1)
- # pedestal (12)
- # portkey (1)
- # re-frame (13)
- # reagent (56)
- # reitit (13)
- # ring-swagger (13)
- # shadow-cljs (145)
- # slack-help (2)
- # specter (6)
has anyone had to deal with a customising an audio tag/player in reagent? I'm having a bit of trouble translating standard js ways into anything clojureish
yeah I'm not that well versed in it, since I can't find any cljs examples that don't use an extern I'm trying to translate myself and it's getting a bit dicey
thanks, each page has multiple audio files and I need to style a very generic audio player - show duration, playback position etc
I've not dealt with extracting multiple values from eventlisteners before, mainly just simple on-clicks
so I'm passing into a component an array of maps which contains general view data (title/url etc) then for each need to build a player
hang on, is the audio player all reagent code around an audio
tag or is this a npm library?
first off, you should just use a ref callback and assign it to a regular atom rather than looking the element up. this is how you would do it even in javascript with plain react
in the js examples I'm using they use event listeners to get feedback from the file of duration and current time
as a general matter, when you’re dealing with the dom apis that require you to make a side effect when something changes (i.e. start playback), the cleanest strategy is to separate all of that code from the presentation of the buttons and so forth. you make a component that has no dom representation and just looks to see when its props change using a form-3 component and causes the proper side effects in the dom
then you render the side-effecting component as a sibling to the presentation and hook it all up with some kind of atom.
ok, I'll have to look into this as I'm not sure I completely understand, the js example is quite long
var music = document.getElementById('music'); // id for audio element var duration = music.duration; // Duration of audio clip, calculated here for embedding purposes var pButton = document.getElementById('pButton'); // play button var playhead = document.getElementById('playhead'); // playhead var timeline = document.getElementById('timeline'); // timeline // timeline width adjusted for playhead var timelineWidth = timeline.offsetWidth - playhead.offsetWidth; // play button event listenter pButton.addEventListener("click", play); // timeupdate event listener music.addEventListener("timeupdate", timeUpdate, false); // makes timeline clickable timeline.addEventListener("click", function(event) { moveplayhead(event); music.currentTime = duration * clickPercent(event); }, false); // returns click as decimal (.77) of the total timelineWidth function clickPercent(event) { return (event.clientX - getPosition(timeline)) / timelineWidth; } // makes playhead draggable playhead.addEventListener('mousedown', mouseDown, false); window.addEventListener('mouseup', mouseUp, false); // Boolean value so that audio position is updated only when the playhead is released var onplayhead = false; // mouseDown EventListener function mouseDown() { onplayhead = true; window.addEventListener('mousemove', moveplayhead, true); music.removeEventListener('timeupdate', timeUpdate, false); } // mouseUp EventListener // getting input from all mouse clicks function mouseUp(event) { if (onplayhead == true) { moveplayhead(event); window.removeEventListener('mousemove', moveplayhead, true); // change current time music.currentTime = duration * clickPercent(event); music.addEventListener('timeupdate', timeUpdate, false); } onplayhead = false; } // mousemove EventListener // Moves playhead as user drags function moveplayhead(event) { var newMargLeft = event.clientX - getPosition(timeline); if (newMargLeft >= 0 && newMargLeft <= timelineWidth) { playhead.style.marginLeft = newMargLeft + "px"; } if (newMargLeft < 0) { playhead.style.marginLeft = "0px"; } if (newMargLeft > timelineWidth) { playhead.style.marginLeft = timelineWidth + "px"; } } // timeUpdate // Synchronizes playhead position with current point in audio function timeUpdate() { var playPercent = timelineWidth * (music.currentTime / duration); playhead.style.marginLeft = playPercent + "px"; if (music.currentTime == duration) { pButton.className = ""; pButton.className = "play"; } } //Play and Pause function play() { // start music if (music.paused) { music.play(); // remove play, add pause pButton.className = ""; pButton.className = "pause"; } else { // pause music music.pause(); // remove pause, add play pButton.className = ""; pButton.className = "play"; } } // Gets audio file duration music.addEventListener("canplaythrough", function() { duration = music.duration; }, false); // getPosition // Returns elements left position relative to top-left of viewport function getPosition(el) { return el.getBoundingClientRect().left; }
this example is a plain javascript version way of doing this. it will work, but you might have better luck importing a react library that already wraps all of this stuff up for you.
this
music.addEventListener("canplaythrough", function() {
duration = music.duration;
}, false);
turns into (.addEventListener music "canplaythrough" (fn [] (reset! duration (.-duration music))) false)
or something like thatrefs are a mechanism in react of getting the underlying dom element. useful for wrapping things like canvas
or audio
where you have to call a method on the dom element
var Timestamps = React.createClass({ render: function() { return ( <div className="Timestamps"> <div className="Time Time--current">{this.props.currentTime}</div> <div className="Time Time--total">{this.props.duration}</div> </div> )} });
That example is using a very ancient style for what it is worth. It would look something like this:
(defn timestamps [current-time duration]
[:div.Timestamps
[:div {:class "Time Time--current"} (str current-time)]
[:div {:class "Time Time--total"} (str duration)]])
the ref atom will contain the dom element. so this (some-> @!ref .focus)
is just calling the focus()
method on whatever dom element the top-level element of list-view
renders to
.focus
is a method on HTMLElement
so no matter what list-view
renders to this particular method will happen to work https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus
the way react ref callbacks work is that once the dom element mounts, the ref callback is called with the dom element as the argument. you can do whatever you want with it, but the typical approach is to use a normal atom and store it there. then in the component-did-mount
and component-did-update
lifecycle methods you can do whatever dom manipulation you want.