xinnks / xns-seek-bar

A seekable progress bar component for Vue.js

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Suggestion - tweek the mouse move behaviour

reppair opened this issue · comments

Hi @xinnks, first of all thanks for that medium article it was very helpful to me. Then I decided to give this one a go due to it's simplicity and I could not use it due to just one small issue that I found - it does not account for mouse move outside of the wrapper div.

For example if you have a really slim wrapper div like mine,

Screenshot from 2020-12-03 12-46-47

then it is hard to keep the mouse pointer in it, so I needed a way of updating the progress during mousemove event outside the wrapper div.

I ended up doing component on my own based on your article with some small changes to it for handling this. Here is my local component:

<template>
    <div class="h-8 flex items-center cursor-pointer" ref="slider">
        <div class="w-full h-1 bg-white-25 rounded-full">
            <div class="rounded-full h-1 bg-white-75" :style="'width: '+ progress +'%'"></div>
        </div>
    </div>
</template>
<script>
export default {
    name: 'Slider',

    data: () => ({
        progress: 0,
        wrapperWidth: 0,
        seekOffsetLeft: 0,
    }),

    watch: {
        wrapperWidth() {
            this.seekOffsetLeft = 0
        },
    },

    mounted(){
        this.$refs.slider.addEventListener("click", this.getClickPosition, false)
        window.addEventListener('resize', e => this.wrapperWidth = this.$refs.slider.offsetWidth, false)
        this.$refs.slider.addEventListener("mousedown", this.detectMouseDown, false)
        this.$refs.slider.addEventListener("mousedown", this.detectMouseDown, false)
        document.addEventListener("mouseup", this.detectMouseUp, false)
    },

    methods: {
        getClickPosition(e) {
            if (e.target.nodeType === 3) e.target = e.target.parentNode // fix for a safari bug
            this.wrapperWidth = this.wrapperWidth || e.target.offsetWidth // set initial wrapper width
            let seekWidth = e.offsetX
            this.progress = (seekWidth / this.wrapperWidth) * 100
        },
        mouseMove(e) {
            if (e.target.nodeType === 3) e.target = e.target.parentNode // fix for a safari bug
            this.wrapperWidth = this.wrapperWidth || e.target.offsetWidth // set initial wrapper width
            if (!this.seekOffsetLeft) this.seekOffsetLeft = e.target.offsetLeft // set the offset left (document -> seek el left side)

            let x = e.pageX,
                seekRight = this.seekOffsetLeft + this.wrapperWidth,
                progress

            if (x < this.seekOffsetLeft) progress = 0
            else if (x > seekRight) progress = 100
            else progress = ((x - this.seekOffsetLeft) / this.wrapperWidth) * 100

            this.progress = progress
        },
        detectMouseDown(e) {
            e.preventDefault()
            document.addEventListener("mousemove", this.mouseMove, false)
        },
        detectMouseUp(e) {
            document.removeEventListener("mousemove", this.mouseMove, false)
        },
    },
}
</script>

The result should be obvious by reading the code it think, but still:

  • able to control the progress on mouse move event outside the wrapper div
  • going to the left of the wrapper div will result in setting progress to 0,
  • going to the right of it - set progress to 100
  • default - set progress 0-100

If you like the idea maybe you will add it to your component in some form or I can try to fit it into your component in a more consistent way and do a PR for it :) would be happy to contribute tiny little bit :)

BTW I'm also thinking of adding mouse wheel scroll event listener too..

@reppair It's a sound feature. What about making it optional based on the height of the wrapper, say below a certain optional height limit then it's applicable. Because having it on wrappers width large widths will almost seem unnecessary a feature. What do you think?

Hi @xinnks, nice idea, for the height that you are using by default it is OK this way, however slim sliders it is much needed.

@reppair The default height is 60px which I can say is OK, you can this as an optionally activated feature, applicable from a wrapper height of 20px and below. Just submit a PR on the dev branch.

Kind of really busy this and next month, feel free to close this issue and I will do a PR when I have a little free time, have to get familiar with your build tool first etc.. if needed you can re-open the issue later, cheers! Happy holidays!

Happy holidays.