rrweb-player
Version:
rrweb's replayer UI
16 lines • 23.8 kB
Source Map (JSON)
{
"version": 3,
"file": "bundle.css",
"sources": [
"../Controller.svelte",
"../Player.svelte",
"../Switch.svelte"
],
"sourcesContent": [
"<script lang=\"ts\">import { EventType } from 'rrweb';\n;\n;\n;\nimport { onMount, onDestroy, createEventDispatcher, afterUpdate, } from 'svelte';\nimport { formatTime } from './utils';\nimport Switch from './components/Switch.svelte';\nconst dispatch = createEventDispatcher();\nexport let replayer;\nexport let showController;\nexport let autoPlay;\nexport let skipInactive;\nexport let speedOption;\nexport let speed = speedOption.length ? speedOption[0] : 1;\nexport let tags = {};\nlet currentTime = 0;\n$: {\n dispatch('ui-update-current-time', { payload: currentTime });\n}\nlet timer = null;\nlet playerState;\n$: {\n dispatch('ui-update-player-state', { payload: playerState });\n}\nlet speedState;\nlet progress;\nlet step;\nlet finished;\nlet meta;\n$: meta = replayer.getMetaData();\nlet percentage;\n$: {\n const percent = Math.min(1, currentTime / meta.totalTime);\n percentage = `${100 * percent}%`;\n dispatch('ui-update-progress', { payload: percent });\n}\nlet customEvents;\n$: customEvents = (() => {\n const { context } = replayer.service.state;\n const totalEvents = context.events.length;\n const start = context.events[0].timestamp;\n const end = context.events[totalEvents - 1].timestamp;\n const customEvents = [];\n // calculate tag position.\n const position = (startTime, endTime, tagTime) => {\n const sessionDuration = endTime - startTime;\n const eventDuration = endTime - tagTime;\n const eventPosition = 100 - (eventDuration / sessionDuration) * 100;\n return eventPosition.toFixed(2);\n };\n // loop through all the events and find out custom event.\n context.events.forEach((event) => {\n /**\n * we are only interested in custom event and calculate it's position\n * to place it in player's timeline.\n */\n if (event.type === EventType.Custom) {\n const customEvent = {\n name: event.data.tag,\n background: tags[event.data.tag] || 'rgb(73, 80, 246)',\n position: `${position(start, end, event.timestamp)}%`,\n };\n customEvents.push(customEvent);\n }\n });\n return customEvents;\n})();\nconst loopTimer = () => {\n stopTimer();\n function update() {\n currentTime = replayer.getCurrentTime();\n if (currentTime < meta.totalTime) {\n timer = requestAnimationFrame(update);\n }\n }\n timer = requestAnimationFrame(update);\n};\nconst stopTimer = () => {\n if (timer) {\n cancelAnimationFrame(timer);\n timer = null;\n }\n};\nexport const toggle = () => {\n switch (playerState) {\n case 'playing':\n pause();\n break;\n case 'paused':\n play();\n break;\n default:\n break;\n }\n};\nexport const play = () => {\n if (playerState !== 'paused') {\n return;\n }\n if (finished) {\n replayer.play();\n finished = false;\n }\n else {\n replayer.play(currentTime);\n }\n};\nexport const pause = () => {\n if (playerState !== 'playing') {\n return;\n }\n replayer.pause();\n};\nexport const goto = (timeOffset) => {\n currentTime = timeOffset;\n const isPlaying = playerState === 'playing';\n replayer.pause();\n replayer.play(timeOffset);\n if (!isPlaying) {\n replayer.pause();\n }\n};\nconst handleProgressClick = (event) => {\n if (speedState === 'skipping') {\n return;\n }\n const progressRect = progress.getBoundingClientRect();\n const x = event.clientX - progressRect.left;\n let percent = x / progressRect.width;\n if (percent < 0) {\n percent = 0;\n }\n else if (percent > 1) {\n percent = 1;\n }\n const timeOffset = meta.totalTime * percent;\n goto(timeOffset);\n};\nexport const setSpeed = (newSpeed) => {\n let needFreeze = playerState === 'playing';\n speed = newSpeed;\n if (needFreeze) {\n replayer.pause();\n }\n replayer.setConfig({ speed });\n if (needFreeze) {\n replayer.play(currentTime);\n }\n};\nexport const toggleSkipInactive = () => {\n skipInactive = !skipInactive;\n};\nonMount(() => {\n playerState = replayer.service.state.value;\n speedState = replayer.speedService.state.value;\n replayer.on('state-change', (states) => {\n const { player, speed } = states;\n if ((player === null || player === void 0 ? void 0 : player.value) && playerState !== player.value) {\n playerState = player.value;\n switch (playerState) {\n case 'playing':\n loopTimer();\n break;\n case 'paused':\n stopTimer();\n break;\n default:\n break;\n }\n }\n if ((speed === null || speed === void 0 ? void 0 : speed.value) && speedState !== speed.value) {\n speedState = speed.value;\n }\n });\n replayer.on('finish', () => {\n finished = true;\n });\n if (autoPlay) {\n replayer.play();\n }\n});\nafterUpdate(() => {\n if (skipInactive !== replayer.config.skipInactive) {\n replayer.setConfig({ skipInactive });\n }\n});\nonDestroy(() => {\n replayer.pause();\n stopTimer();\n});\n</script>\n\n<style>\n.rr-controller {\n width: 100%;\n height: 80px;\n background: #fff;\n display: flex;\n flex-direction: column;\n justify-content: space-around;\n align-items: center;\n border-radius: 0 0 5px 5px;\n}\n\n.rr-timeline {\n width: 80%;\n display: flex;\n align-items: center;\n}\n\n.rr-timeline__time {\n display: inline-block;\n width: 100px;\n text-align: center;\n color: #11103e;\n}\n\n.rr-progress {\n flex: 1;\n height: 12px;\n background: #eee;\n position: relative;\n border-radius: 3px;\n cursor: pointer;\n box-sizing: border-box;\n border-top: solid 4px #fff;\n border-bottom: solid 4px #fff;\n}\n\n.rr-progress.disabled {\n cursor: not-allowed;\n}\n\n.rr-progress__step {\n height: 100%;\n position: absolute;\n left: 0;\n top: 0;\n background: #e0e1fe;\n}\n\n.rr-progress__handler {\n width: 20px;\n height: 20px;\n border-radius: 10px;\n position: absolute;\n top: 2px;\n transform: translate(-50%, -50%);\n background: rgb(73, 80, 246);\n}\n\n.rr-controller__btns {\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 13px;\n}\n\n.rr-controller__btns button {\n width: 32px;\n height: 32px;\n display: flex;\n padding: 0;\n align-items: center;\n justify-content: center;\n background: none;\n border: none;\n border-radius: 50%;\n cursor: pointer;\n}\n\n.rr-controller__btns button:active {\n background: #e0e1fe;\n}\n\n.rr-controller__btns button.active {\n color: #fff;\n background: rgb(73, 80, 246);\n}\n\n.rr-controller__btns button:disabled {\n cursor: not-allowed;\n}</style>\n\n{#if showController}\n <div class=\"rr-controller\">\n <div class=\"rr-timeline\">\n <span class=\"rr-timeline__time\">{formatTime(currentTime)}</span>\n <div\n class=\"rr-progress\"\n class:disabled={speedState === 'skipping'}\n bind:this={progress}\n on:click={(event) => handleProgressClick(event)}>\n <div\n class=\"rr-progress__step\"\n bind:this={step}\n style=\"width: {percentage}\" />\n {#each customEvents as event}\n <div\n title={event.name}\n style=\"width: 10px;height: 5px;position: absolute;top:\n 2px;transform: translate(-50%, -50%);background: {event.background};left:\n {event.position};\" />\n {/each}\n\n <div class=\"rr-progress__handler\" style=\"left: {percentage}\" />\n </div>\n <span class=\"rr-timeline__time\">{formatTime(meta.totalTime)}</span>\n </div>\n <div class=\"rr-controller__btns\">\n <button on:click={toggle}>\n {#if playerState === 'playing'}\n <svg\n class=\"icon\"\n viewBox=\"0 0 1024 1024\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n width=\"16\"\n height=\"16\">\n <path\n d=\"M682.65984 128q53.00224 0 90.50112 37.49888t37.49888 90.50112l0\n 512q0 53.00224-37.49888 90.50112t-90.50112\n 37.49888-90.50112-37.49888-37.49888-90.50112l0-512q0-53.00224\n 37.49888-90.50112t90.50112-37.49888zM341.34016 128q53.00224 0\n 90.50112 37.49888t37.49888 90.50112l0 512q0 53.00224-37.49888\n 90.50112t-90.50112\n 37.49888-90.50112-37.49888-37.49888-90.50112l0-512q0-53.00224\n 37.49888-90.50112t90.50112-37.49888zM341.34016 213.34016q-17.67424\n 0-30.16704 12.4928t-12.4928 30.16704l0 512q0 17.67424 12.4928\n 30.16704t30.16704 12.4928 30.16704-12.4928\n 12.4928-30.16704l0-512q0-17.67424-12.4928-30.16704t-30.16704-12.4928zM682.65984\n 213.34016q-17.67424 0-30.16704 12.4928t-12.4928 30.16704l0 512q0\n 17.67424 12.4928 30.16704t30.16704 12.4928 30.16704-12.4928\n 12.4928-30.16704l0-512q0-17.67424-12.4928-30.16704t-30.16704-12.4928z\" />\n </svg>\n {:else}\n <svg\n class=\"icon\"\n viewBox=\"0 0 1024 1024\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n width=\"16\"\n height=\"16\">\n <path\n d=\"M170.65984 896l0-768 640 384zM644.66944\n 512l-388.66944-233.32864 0 466.65728z\" />\n </svg>\n {/if}\n </button>\n {#each speedOption as s}\n <button\n class:active={s === speed && speedState !== 'skipping'}\n on:click={() => setSpeed(s)}\n disabled={speedState === 'skipping'}>\n {s}x\n </button>\n {/each}\n <Switch\n id=\"skip\"\n bind:checked={skipInactive}\n disabled={speedState === 'skipping'}\n label=\"skip inactive\" />\n <button on:click={() => dispatch('fullscreen')}>\n <svg\n class=\"icon\"\n viewBox=\"0 0 1024 1024\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n width=\"16\"\n height=\"16\">\n <defs>\n <style type=\"text/css\"></style>\n </defs>\n <path\n d=\"M916 380c-26.4 0-48-21.6-48-48L868 223.2 613.6 477.6c-18.4\n 18.4-48.8 18.4-68 0-18.4-18.4-18.4-48.8 0-68L800 156 692 156c-26.4\n 0-48-21.6-48-48 0-26.4 21.6-48 48-48l224 0c26.4 0 48 21.6 48 48l0\n 224C964 358.4 942.4 380 916 380zM231.2 860l108.8 0c26.4 0 48 21.6 48\n 48s-21.6 48-48 48l-224 0c-26.4 0-48-21.6-48-48l0-224c0-26.4 21.6-48\n 48-48 26.4 0 48 21.6 48 48L164 792l253.6-253.6c18.4-18.4 48.8-18.4\n 68 0 18.4 18.4 18.4 48.8 0 68L231.2 860z\"\n p-id=\"1286\" />\n </svg>\n </button>\n </div>\n </div>\n{/if}\n",
"<script lang=\"ts\">import { onMount, onDestroy } from 'svelte';\nimport { Replayer, unpack, mirror } from 'rrweb';\n;\nimport { inlineCss, openFullscreen, exitFullscreen, isFullscreen, onFullscreenChange, typeOf, } from './utils';\nimport Controller from './Controller.svelte';\nexport let width = 1024;\nexport let height = 576;\nexport let events = [];\nexport let skipInactive = true;\nexport let autoPlay = true;\nexport let speedOption = [1, 2, 4, 8];\nexport let speed = 1;\nexport let showController = true;\nexport let tags = {};\nexport const getMirror = () => mirror;\nconst controllerHeight = 80;\nlet player;\nlet frame;\nlet replayer;\nlet fullscreenListener;\nlet _width = width;\nlet _height = height;\nlet controller;\nlet style;\n$: style = inlineCss({\n width: `${width}px`,\n height: `${height}px`,\n});\nlet playerStyle;\n$: playerStyle = inlineCss({\n width: `${width}px`,\n height: `${height + (showController ? controllerHeight : 0)}px`,\n});\nconst updateScale = (el, frameDimension) => {\n const widthScale = width / frameDimension.width;\n const heightScale = height / frameDimension.height;\n el.style.transform =\n `scale(${Math.min(widthScale, heightScale, 1)})` +\n 'translate(-50%, -50%)';\n};\nexport const triggerResize = () => {\n updateScale(replayer.wrapper, {\n width: replayer.iframe.offsetWidth,\n height: replayer.iframe.offsetHeight,\n });\n};\nexport const toggleFullscreen = () => {\n if (player) {\n isFullscreen() ? exitFullscreen() : openFullscreen(player);\n }\n};\nexport const addEventListener = (event, handler) => {\n replayer.on(event, handler);\n switch (event) {\n case 'ui-update-current-time':\n case 'ui-update-progress':\n case 'ui-update-player-state':\n controller.$on(event, ({ detail }) => handler(detail));\n default:\n break;\n }\n};\nexport const addEvent = (event) => {\n replayer.addEvent(event);\n};\nexport const getMetaData = () => replayer.getMetaData();\nexport const getReplayer = () => replayer;\n// by pass controller methods as public API\nexport const toggle = () => {\n controller.toggle();\n};\nexport const setSpeed = (speed) => {\n controller.setSpeed(speed);\n};\nexport const toggleSkipInactive = () => {\n controller.toggleSkipInactive();\n};\nexport const play = () => {\n controller.play();\n};\nexport const pause = () => {\n controller.pause();\n};\nexport const goto = (timeOffset) => {\n controller.goto(timeOffset);\n};\nonMount(() => {\n // runtime type check\n if (speedOption !== undefined && typeOf(speedOption) !== 'array') {\n throw new Error('speedOption must be array');\n }\n speedOption.forEach((item) => {\n if (typeOf(item) !== 'number') {\n throw new Error('item of speedOption must be number');\n }\n });\n if (speedOption.indexOf(speed) < 0) {\n throw new Error(`speed must be one of speedOption,\n current config:\n {\n ...\n speed: ${speed},\n speedOption: [${speedOption.toString()}]\n ...\n }\n `);\n }\n replayer = new Replayer(events, Object.assign({ speed, root: frame, unpackFn: unpack }, $$props));\n replayer.on('resize', (dimension) => {\n updateScale(replayer.wrapper, dimension);\n });\n fullscreenListener = onFullscreenChange(() => {\n if (isFullscreen()) {\n setTimeout(() => {\n _width = width;\n _height = height;\n width = player.offsetWidth;\n height = player.offsetHeight;\n updateScale(replayer.wrapper, {\n width: replayer.iframe.offsetWidth,\n height: replayer.iframe.offsetHeight,\n });\n }, 0);\n }\n else {\n width = _width;\n height = _height;\n updateScale(replayer.wrapper, {\n width: replayer.iframe.offsetWidth,\n height: replayer.iframe.offsetHeight,\n });\n }\n });\n});\nonDestroy(() => {\n fullscreenListener && fullscreenListener();\n});\n</script>\n\n<style global>:global(.replayer-wrapper){position:relative}:global(.replayer-mouse){position:absolute;width:20px;height:20px;transition:.05s linear;background-size:contain;background-position:50%;background-repeat:no-repeat;background-image:url(\"data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjMwMCIgd2lkdGg9IjMwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBkYXRhLW5hbWU9IkxheWVyIDEiIHZpZXdCb3g9IjAgMCA1MCA1MCI+PHBhdGggZD0iTTQ4LjcxIDQyLjkxTDM0LjA4IDI4LjI5IDQ0LjMzIDE4YTEgMSAwIDAwLS4zMy0xLjYxTDIuMzUgMS4wNmExIDEgMCAwMC0xLjI5IDEuMjlMMTYuMzkgNDRhMSAxIDAgMDAxLjY1LjM2bDEwLjI1LTEwLjI4IDE0LjYyIDE0LjYzYTEgMSAwIDAwMS40MSAwbDQuMzgtNC4zOGExIDEgMCAwMC4wMS0xLjQyem0tNS4wOSAzLjY3TDI5IDMyYTEgMSAwIDAwLTEuNDEgMGwtOS44NSA5Ljg1TDMuNjkgMy42OWwzOC4xMiAxNEwzMiAyNy41OEExIDEgMCAwMDMyIDI5bDE0LjU5IDE0LjYyeiIvPjwvc3ZnPg==\")}:global(.replayer-mouse:after){content:\"\";display:inline-block;width:20px;height:20px;border-radius:10px;background:#4950f6;transform:translate(-10px,-10px);opacity:.3}:global(.replayer-mouse.active:after){animation:click .2s ease-in-out 1}:global(.replayer-mouse-tail){position:absolute;pointer-events:none}@keyframes -global-click{0%{opacity:.3;width:20px;height:20px;border-radius:10px;transform:translate(-10px,-10px)}50%{opacity:.5;width:10px;height:10px;border-radius:5px;transform:translate(-5px,-5px)}}:global(.rr-player) {\n position: relative;\n background: white;\n float: left;\n border-radius: 5px;\n box-shadow: 0 24px 48px rgba(17, 16, 62, 0.12);\n}:global(.rr-player__frame) {\n overflow: hidden;\n}:global(.replayer-wrapper) {\n float: left;\n clear: both;\n transform-origin: top left;\n left: 50%;\n top: 50%;\n}:global(.replayer-wrapper) > :global(iframe) {\n border: none;\n}</style>\n\n<div class=\"rr-player\" bind:this={player} style={playerStyle}>\n <div class=\"rr-player__frame\" bind:this={frame} {style} />\n {#if replayer}\n <Controller\n bind:this={controller}\n {replayer}\n {showController}\n {autoPlay}\n {speedOption}\n {skipInactive}\n {tags}\n on:fullscreen={() => toggleFullscreen()} />\n {/if}\n</div>\n",
"<script lang=\"ts\">export let disabled;\nexport let checked;\nexport let id;\nexport let label;\n</script>\n\n<style>\n.switch {\n height: 1em;\n display: flex;\n align-items: center;\n}\n\n.switch.disabled {\n opacity: 0.5;\n}\n\n.label {\n margin: 0 8px;\n}\n\n.switch input[type='checkbox'] {\n position: absolute;\n opacity: 0;\n}\n\n.switch label {\n width: 2em;\n height: 1em;\n position: relative;\n cursor: pointer;\n display: block;\n}\n\n.switch.disabled label {\n cursor: not-allowed;\n}\n\n.switch label:before {\n content: '';\n position: absolute;\n width: 2em;\n height: 1em;\n left: 0.1em;\n transition: background 0.1s ease;\n background: rgba(73, 80, 246, 0.5);\n border-radius: 50px;\n}\n\n.switch label:after {\n content: '';\n position: absolute;\n width: 1em;\n height: 1em;\n border-radius: 50px;\n left: 0;\n transition: all 0.2s ease;\n box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.3);\n background: #fcfff4;\n animation: switch-off 0.2s ease-out;\n z-index: 2;\n}\n\n.switch input[type='checkbox']:checked + label:before {\n background: rgb(73, 80, 246);\n}\n\n.switch input[type='checkbox']:checked + label:after {\n animation: switch-on 0.2s ease-out;\n left: 1.1em;\n}</style>\n\n<div class=\"switch\" class:disabled>\n <input type=\"checkbox\" {id} bind:checked {disabled} />\n <label for={id} />\n <span class=\"label\">{label}</span>\n</div>\n"
],
"names": [],
"mappings": "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"
}