如何通过画布创建创建循环搜索栏

时间:2016-01-06 21:32:08

标签: javascript jquery html5 canvas

我想创建一个圆形的玩家搜索栏。我必须有两个手柄。一个是缓冲部分(图片中的灰色),它不是拖动,而是更多可拖动的项目,表示正在播放的歌曲的当前部分。我不确定如何实现这一目标。看起来像帆布是最好的选择。但我不确定是否可以在画布中拖动物品。

var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var radius = 100;

context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.lineWidth = 25;
context.strokeStyle = '#003300';
context.stroke();

如何实现它的任何想法或例子?

enter image description here

1 个答案:

答案 0 :(得分:0)

圈控

这个答案显示了如何创建游戏类型控件。它以固定间隔运行,每隔一段时间渲染一次。它不是事件驱动的,鼠标事件不调用控件,控件只是检查当前鼠标位置。如果间隔低于鼠标事件间隔,则某些鼠标移动将丢失,但控件也可以正常工作。

通过创建自己的鼠标事件监听器并在需要时调用updatedraw(),可以轻松地将此控件调整为事件驱动。警告虽然此控件使用自定义鼠标对象来更改光标并管理哪个控件具有鼠标的所有权。鼠标需要所有权,以便当您将一个控制柄拖到另一个控件上时,您不会开始拖动另一个控件。它的工作原理是将mouse.mousePrivate值设置为控件唯一ID,如果mouse.mousePrivate不等于0(无所有者)或控件的ID

,控件将忽略鼠标

请参阅代码了解其工作原理。该演示显示了几个控件,显示了不同的行为。中心控制是一个简单的范围控制,从0到100,左上角有10个旋转,范围从0到1000,并显示两个位置弧来显示位置。右上方控件具有浮动值,即如果您正在寻找视频,则搜索位置不会立即响应,因此控件具有浮动值,该位置显示位置弧作为实际位置,而数字和拨号手柄显示实际位置

这只是一个例子,您应该只需要你想要的东西。它尚未在多个浏览器上进行测试,除了最基本的测试之外没有任何其他测试,所以不要按原样使用它。

demo = function(){

    /** fullScreenCanvas.js begin **/
    var canvas = (function(){
        var canvas = document.getElementById("canv");
        if(canvas !== null){
            document.body.removeChild(canvas);
        }
        // creates a blank image with 2d context
        canvas = document.createElement("canvas"); 
        canvas.id = "canv";    
        canvas.style.background = "#AAA";
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight; 
        canvas.style.position = "absolute";
        canvas.style.top = "0px";
        canvas.style.left = "0px";
        canvas.style.zIndex = 1000;
        canvas.ctx = canvas.getContext("2d"); 
        document.body.appendChild(canvas);
        return canvas;
    })();
    var ctx = canvas.ctx;

    /** fullScreenCanvas.js end **/
    /** MouseFull.js begin **/

    var canvasMouseCallBack = undefined;  // if needed
    var mouse = (function(){
        function cursorControl(cursor){
            if(cursor !== this.lastCursor){
                if(cursor !== "default"){
                    this.lastCursor = cursor;
                }
            }
        }
        function update(){
            if(this.element !== undefined){
                this.element.style.cursor = this.lastCursor;
                this.lastCursor = "default";
            }
        }
        var mouse = {
            x : 0, y : 0, w : 0, alt : false, shift : false, ctrl : false,
            interfaceId : 1, buttonLastRaw : 0,  buttonRaw : 0,
            over : false,  // mouse is over the element
            bm : [1, 2, 4, 6, 5, 3], // masks for setting and clearing button raw bits;
            getInterfaceId : function () { return this.interfaceId++; }, // For UI functions
            mousePrivate : 0,  
            lastCursor: "default",
            setCursor : cursorControl,
            frameEnd : update,
            startMouse:undefined,
            element : undefined,
        };
        function mouseMove(e) {
            var t = e.type, m = mouse;
            m.x = e.offsetX; m.y = e.offsetY;
            if (m.x === undefined) { m.x = e.clientX; m.y = e.clientY; }
            m.alt = e.altKey;m.shift = e.shiftKey;m.ctrl = e.ctrlKey;
            if (t === "mousedown") { m.buttonRaw |= m.bm[e.which-1];
            } else if (t === "mouseup") { m.buttonRaw &= m.bm[e.which + 2];
            } else if (t === "mouseout") { m.buttonRaw = 0; m.over = false;
            } else if (t === "mouseover") { m.over = true;
            } else if (t === "mousewheel") { m.w = e.wheelDelta;
            } else if (t === "DOMMouseScroll") { m.w = -e.detail;}
            if (canvasMouseCallBack) { canvasMouseCallBack(m.x, m.y); }
            e.preventDefault();
        }
        function startMouse(element){
            if(element === undefined){
                element = document;
            }
            mouse.element = element;
            "mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll".split(",").forEach(
            function(n){element.addEventListener(n, mouseMove);});
            element.addEventListener("contextmenu", function (e) {e.preventDefault();}, false);
        }
        mouse.mouseStart = startMouse;
        return mouse;
    })();
    if(typeof canvas !== "undefined"){
        mouse.mouseStart(canvas);
    }else{
        mouse.mouseStart();
    }
    /** MouseFull.js end **/
    /** ImageTools.js begin **/
    var imageTools = (function(){
        var iT = {
            canvas:function(w,h){var c=document.createElement("canvas");c.width=w;c.height=h;return c;},
            createImage:function(w,h){var i=iT.canvas(w,h);i.ctx=i.getContext("2d");return i;},        
            loadImage:function(url,cb){var i=new Image();i.src=url;i.addEventListener('load',cb);return i;},
            image2Canvas:function(ig){var i=iT.canvas(ig.width,ig.height);i.ctx=i.getContext("2d");i.drawImage(ig,0,0);return i;},
            imageData:function(img){return (img.ctx||(iT.image2Canvas(img).ctx)).getImageData(0,0,img.width,img.height).data;},
            saveAsPNG:function(image,filename){ // No IE <11 support. Chrome URL bug for large files may crash
                var ac,e;
                if(image.toDataURL === undefined){ image = it.image2Canvas(image);}
                ac = document.createElement('a'); ac.href = image.toDataURL(); ac.download = filename+".png";
                // need to update this as it has depreciated.
                if (document.createEvent) { 
                    (e = document.createEvent("MouseEvents")).initMouseEvent("click", true, true, window,0, 0, 0, 0, 0, false, false, false,false, 0, null);
                    ac.dispatchEvent(e);
                }       
            }
        };
        return iT;
    })();

    /** ImageTools.js end **/

    var w = canvas.width;
    var h = canvas.height;
    var ix = Math.ceil(Math.min(w, h) / 20);
    const PI2 = Math.PI * 2;



    // following three function are for drawing, updating, and on to set floating value

    // draw circular control needs to be bound to a circular control object 
    function drawCirControl(){
        var c, r, r1, r2, x, y, w, a;
        c = this.ctx;
        r = this.radius1;
        r1 = this.radius2;
        
        c.lineWidth = w = Math.abs(r - r1);
        r2 = Math.min(r, r1) + w / 2;
        c.strokeStyle = this.borderColour;
        c.beginPath();
        c.arc(this.x, this.y, r2, 0, Math.PI * 2)
        c.stroke();
        c.strokeStyle = this.colour;
        c.lineWidth = w - this.border * 2;
        c.beginPath();
        c.arc(this.x, this.y, r2, 0, Math.PI * 2)
        c.stroke();
        // if more than one turn between min and max then also display progress as one turn
        if(Math.abs(this.startAng - this.endAng) > PI2){
            c.lineCap = "round";
            c.strokeStyle = this.lineColour;
            c.lineWidth = (w - this.border * 6)/2;
            c.beginPath();
            a = (this.floatingRaw - this.startAng) % PI2 + this.startAng;
            c.arc(this.x, this.y, r2 + (w - this.border * 6)/4, this.startAng, a)
            c.stroke();
            
            a = this.startAng + ((this.floatingValue - this.min) / (this.max - this.min)) * PI2;
            c.lineCap = "round";
            c.strokeStyle = this.lineInnerColour;
            c.lineWidth = (w - this.border * 6)/2;
            c.beginPath();
            c.arc(this.x, this.y, r2 - (w - this.border * 6)/4, this.startAng, a)
            c.stroke();
            
            
        }else{
            c.lineCap = "round";
            c.strokeStyle = this.lineColour;
            c.lineWidth = w - this.border * 6;
            c.beginPath();
            c.arc(this.x, this.y, r2, this.startAng, this.floatingRaw)
            c.stroke();
        }
        
        
        x = Math.cos(this.raw) * r2 + this.x;
        y = Math.sin(this.raw) * r2 + this.y;
        
        c.lineWidth = this.border;
        c.strokeStyle = this.borderColour;
        c.fillStyle = this.colour;
        c.beginPath();
        c.arc(x, y, (w * this.handleSize)/2, 0, Math.PI * 2);
        c.fill();
        c.stroke();
        
        c.font = this.font;
        c.textAlign = "center";
        c.textBaseline = "middle";
        c.fillText(Math.round(this.value), this.x, this.y);
    }

    // Update by checking mouse position and setting cursor and controling the dragging 
    // circular control needs to be bound to a circular control object 
    function updateCircularControl(){
        var r, r1, r2, x, y, dist, ang, a, w, h, mouseOver;
        r = this.radius1;
        r1 = this.radius2;
        w = Math.abs(r - r1);
        r2 = Math.min(r, r1) + w / 2;
        if(!this.floating){
            this.floatingValue = this.value;
        }
        this.raw = (this.value / (this.max - this.min)) * (this.endAng - this.startAng) + this.startAng;
        this.floatingRaw = (this.floatingValue / (this.max - this.min)) * (this.endAng - this.startAng) + this.startAng;
        x = Math.cos(this.raw) * r2 + this.x;
        y = Math.sin(this.raw) * r2 + this.y;
        mouseOver = false;
        dist = Math.sqrt(Math.pow(x - mouse.x, 2) + Math.pow(y - mouse.y, 2));
        if(this.mouse.mousePrivate === 0 || this.mouse.mousePrivate === this.id){
            if(dist < w * this.handleSize || this.dragging){
                this.mouse.setCursor("pointer");
                mouseOver = true;
                this.mouse.mousePrivate = this.id;
                if((this.mouse.buttonRaw & 1) === 1 && !this.dragging){
                    this.dragging = true;
                        this.lastAng = (this.raw + PI2) % PI2;
                    
                }else{
                    if((this.mouse.buttonRaw & 1) === 0){
                        this.dragging = false;
                    }else{
                        // get the angle to the mouse
                        ang = ((Math.atan2(mouse.y - this.y, mouse.x - this.x)) + PI2) % PI2;
                        // get the delta from last angle
                        a = (ang - this.lastAng);
                        // check that is has not cycled and adjust acordingly
                        if(a < -Math.PI * (3/2)){
                            a += PI2
                        }
                        if(a > Math.PI * (3/2)){
                            a -= PI2
                        }
                        // set last angle
                        this.lastAng = ang;
                        // set the raw vale
                        this.raw += a;
                        this.value =  ((this.raw - this.startAng) / (this.endAng - this.startAng)) * (this.max - this.min) + this.min
                        this.value = Math.min(this.max, Math.max(this.min, this.value));
                        if(!this.floating){
                            this.floatingValue = this.value;
                        }
                        // recalculate the raw value
                        this.raw = (this.value / (this.max - this.min)) * (this.endAng - this.startAng) + this.startAng;
                        this.floatingRaw = (this.floatingValue / (this.max - this.min)) * (this.endAng - this.startAng) + this.startAng;
                    }
                }
            }
        }
        if(! mouseOver && this.mouse.mousePrivate === this.id ){
            this.mouse.mousePrivate = 0;
        }
    }
    // set circular control floating value needs to be bound to a circular control object 

    function setCirciularFloatingValue(v){
        this.floatingValue = v;
        this.floatingRaw = (this.floatingValue / (this.max - this.min)) * (this.endAng - this.startAng) + this.startAng;
    }



    // create a circular control
    // x, y is the center pos;
    // min max is the min max values
    // r1 r2 are inner and outer radius
    // ctx is the canvas context to draw to
    // mouse is the mouse object. This is a custom mouse object provided 
    //       in the demo.

    function createCircularControl(x,y,min,max,r1,r2,ctx,mouse){
        var s, fontSize;
        s = Math.min(r1,r2);
        fontSize = Math.ceil(s/2);            
        var control = {
            raw : 0,                    // the raw angle to draw the control handle ar
            floatingRaw : 0,            // if the actuale value floats independent of control position
            lastAng : 0,
            x : x,                      // center of control
            y : y,
            min : min,                  // min and max values 
            max : max, 
            value : 0,                  // value of control
            floatingValue : 0,
            startAng : -Math.PI/2,      // start angle
            endAng : Math.PI * (3/2),   // end angle
            radius1 : r1,               // inner and outer angles
            radius2 : r2, 
            border : 1,                 // border radius
            colour : "white",           // inner colour
            borderColour : "black",     // border colour
            lineColour : "#5AF",
            lineInnerColour : "#5AF",
            font : fontSize + "px Arial Black",  // font for center display
            handleSize : 1.5,           // handle size aas ratio to control width
            floating : false,
            draw : drawCirControl,      // function to draw control
            ctx : ctx,                  // get the context to draw to 
            mouse : mouse,              // set the mouse
            id : mouse.getInterfaceId(), // get an ID for this control
            update : updateCircularControl,  // updates the control
            setFloatingValue : setCirciularFloatingValue,
        }
        return control;
    }


    // create the controls
    var cont = createCircularControl(w/2, h/2, 0, 100, ix*5, ix*6, ctx, mouse);
    var cont1 = createCircularControl(w/6, h/4, 0, 1000, ix*2, ix*3, ctx, mouse);
    var cont2 = createCircularControl(w - w/6, h/4, 0, 1000, ix*2, ix*3, ctx, mouse);

    // set up top left control extra attributes
    // It has 10 rotations between min and max
    cont1.startAng =  -Math.PI/2;
    cont1.endAng =  -Math.PI/2 + PI2 * 10;
    cont1.handleSize = 1.0;
    cont1.lineInnerColour = "#8C5";


    // set up top left control extra attributes
    cont2.startAng =  0;
    cont2.endAng =  PI2 * 5;
    cont2.handleSize = 1.5;
    cont2.lineInnerColour = "#C85";
    cont2.colour = "black";
    cont2.borderColour = "Green";
    cont2.border = 3;
    cont2.floating = true;
    var fValue = 0;
    var fdValue = 0



    // Updates all 
    function update(){
        ctx.setTransform(1,0,0,1,0,0);
        ctx.clearRect(0, 0, w, h);
        fdValue += (cont2.value - fValue) * 0.01;
        fdValue *=  0.6;
        fValue += fdValue;
        cont2.setFloatingValue(fValue);
        cont.update();
        cont1.update();
        cont2.update();
        cont.draw();
        cont1.draw();
        cont2.draw();
        if(!STOP){
            requestAnimationFrame(update);
        }else{
            var canv = document.getElementById("canv");
            if(canv !== null){
                document.body.removeChild(canv);
            }            
            STOP = false;
        }
        mouse.frameEnd();
        
    }

    update();
    
}
var STOP = false;
function resizeEvent(){
    var waitForStopped = function(){
        if(!STOP){  // wait for stop to return to false
            demo();
            return;
        }
        setTimeout(waitForStopped,200);
    }
    STOP = true;
    setTimeout(waitForStopped,100);
}
window.addEventListener("resize",resizeEvent);
demo();