HTML5 segment color?

HTML5 segment color?

本文关键字:color segment HTML5      更新时间:2023-09-26

我正在使用这个JSFiddle中的代码来创建命运之轮类型的游戏。 我想做的是让用户选择自己的颜色,而不是生成随机的颜色。

我将其添加到 HTML 代码中:

<select id="colour" name="colour" class="colour">
    <option value=""></option>
    <option value="db0000">Red</option>
    <option value="171515">Black</option>
    <option value="008c0a">Green</option>
</select>

我只编辑了Javascript的这一部分:

 for (i = 0; i < 1; i++) {
     digit[i] = colors[Math.round(Math.random() * 1)];
     //color = color+digit[i];
     color = document.getElementById("colour").value;
     //color = color+digit[i];     
 }

我添加了color = document.getElementById("colour").value;.

问题是颜色无法正常工作。它将正确创建具有所选颜色的第一和第二段,但从第三段开始,它将在轮子中添加一个额外的黑色段。

我几乎更改了Javascript中的每个数字以查明问题所在,但仍然无法弄清楚。

编辑:

为了确保我不会引起任何混淆,我试图做的是对于添加到车轮中的每个新段,我需要选择一种新的颜色。

这段代码是一个很好的例子,说明了为什么原型模式比功能模式好得多。这个插件被定义为一个事实上的工厂函数,它声明了各种各样的函数局部状态变量(startAnglearcpplArray等),这些变量被实现插件的各种方法封闭,最重要的是,一些方法被定义为使用对象文字语法的函数局部(methods)上的表达式化函数文字, 一种方法被定义为一个表达式化的函数文字,并分配给一个一次性的函数局部(var rotateWheel),它被提升到作用域的顶部,并通过各种其他方法闭合,其余的(genHex()stopRotateWheel()等)被定义为被提升到作用域顶部并被各种其他方法闭包的函数语句。真是一团糟!

此外,并非所有闭包

变量都需要是闭包,因为它们实际上不需要在方法调用之间维护状态; arc就是一个很好的例子。

这里可以提出的另一个批评是,某些状态实际上存储在 DOM 树中,这是荒谬和不必要的。我特指的是 params.participants ,它是一个 jQuery 选择器,它可以在 DOM 中的某个地方定位一个<ul>元素(在哪里并不重要),它的子元素<li>元素被迭代以从他们的 innerHTML 构建轮段文本。此数据不需要存储在 DOM 上;它可以很容易地存储在类实例上的数组中。

当然,还有

对函数模式的经典批评,它会导致为构造函数/工厂函数的每次调用定义新的函数对象(在这种情况下$.fn.spinwheel()),而原型模式将涉及在定义类时类原型上每个函数的单个定义。

无论如何,我使用原型模式重写了整个插件。该小部件现在被定义为window.SpinWheel上的全局构造函数(当然,如果需要,可以将其移动到命名空间中)。所有实例方法都是使用统一的语法定义的,方法是将表达式化函数文本分配给类原型,SpinWheel.prototype .

在状态数据方面,在构造函数上静态定义了一点默认配置数据(基本上我在原始代码中获取了$.fn.spinwheel.default_options对象并将其分配给SpinWheel.config,但修复了一个拼写错误并删除了params.participants),然后捕获作为参数传递给构造函数的配置对象(以及画布节点的$canvas jQuery包装器, 及其上下文对象)作为实例本身this.config .最后,实际的可变实例状态存储为实例上的属性,例如this.segmentTexts(每个段的文本)、this.colors(当前选定的段颜色)和this.curAngle(滚轮的当前角度)。就是这样,实际上只有三种数据:静态默认(回退)配置、实例配置和实例属性。所有方法的定义风格都是统一的,并且对所有对象数据具有相同的访问权限。

jQuery插件现在只是SpinWheel类的薄包装器;基本上,它实例化它,将其附加到目标画布(除非外部代码想要在创建后访问它,否则不是真正必要的),并初始化它。插件接口与原始代码相同,但使用新代码,如果你愿意,你也可以独立于 jQuery 插件框架实例化SpinWheel(当然,应该说,实现仍然取决于加载的 jQuery)。

另外,为了解决这个问题,我添加了DeleteClearReset按钮来演示对方向盘的更多控制。您现在可以通过正则表达式与文本匹配来删除片段,清除整个轮子,以便您可以从头开始构建它,并将其重置为初始配置(尽管如果您没有通过初始配置配置颜色,它们将再次随机生成,这肯定会与初始显示中的不同;但如果需要,您可以配置初始颜色)。

这是新的 HTML:

<div id="main">
    <div id="left-column">
        <form class="iform" action="#" method="get">
            <label for="joiner"></label>
            <input id="joiner" name="joiner" class="joiner" placeholder="Please Enter your name" />
            <select id="colorer" name="colorer" class="colorer">
                <option value="">auto</option>
                <option value="db0000">Red</option>
                <option value="171515">Black</option>
                <option value="008c0a">Green</option>
            </select>
            <button class="add">Add</button>
            <button class="delete">Delete</button>
            <button class="spin-trigger">Spin</button>
            <button class="clear">Clear</button>
            <button class="reset">Reset</button>
        </form>
        <canvas class="canvas" width="500" height="500"></canvas>
    </div>
    <div id="right-column">
        <p class="winner">The Winner is ... <span>&nbsp;</span></p>
    </div>
    <div style="clear:both"></div>
</div>

下面是定义SpinWheel类的新 IIFE:

(function($) {
    // define main SpinWheel constructor function
    var SpinWheel = function($canvas, config ) {
        // validate config
        // 1: reject invalids
        for (configKey in config) {
            if (!config.hasOwnProperty(configKey)) continue;
            if (!SpinWheel.config.hasOwnProperty(configKey)) throw 'error: invalid config key "'+configKey+'" in SpinWheel instantiation.';
        } // end for
        // 2: check for requireds
        var requiredParams = ['segmentTexts'];
        for (var i = 0; i < requiredParams.length; ++i) {
            var requiredParam = requiredParams[i];
            if (!config.hasOwnProperty(requiredParam)) throw 'error: missing required config key '''+requiredParam+''' in SpinWheel instantiation.';
        } // end for
        // store the per-instance config on the "this" object
        this.config = config;
        // capture the canvas jQuery object and init the canvas context
        // note: there should only ever be one SpinWheel instantiated per canvas, and there's only one canvas manipulated by a single SpinWheel instance
        this.$canvas = $canvas;
        this.canvasCtx = this.$canvas[0].getContext("2d");
        // initialize the segments, colors, and curAngle -- wrap this in a function for reusability
        this.reset();
    }; // end SpinWheel()
    // SpinWheel statics
    /*  ---  please look at the index.html source in order to understand what they do ---
        *  outerRadius : the big circle border
        *  innerRadius  : the inner circle border
        *  textRadius   : How far the the text on the wheel locate from the center point
        *  spinTrigger  : the element that trigger the spin action
        *  wheelBorderColor : what is the wheel border color
        *  wheelBorderWidth : what is the "thickness" of the border of the wheel
        *  wheelTextFont : what is the style of the text on the wheel
        *  wheelTextColor : what is the color of the tet on the wheel
        *  wheelTextShadow : what is the shadow for the text on the wheel
        *  resultTextFont : it is not being used currently
        *  arrowColor : what is the color of the arrow on the top
        *  joiner : usually a form input where user can put in their name
        *  addTrigger : what element will trigger the add participant
        *  winnerDiv : the element you want to display the winner
        */
    SpinWheel.config = {
        'segmentTexts':['1','2','3','4','5','6'],
        'colors':[], // we'll allow omitted config colors; will just generate unspecifieds randomly on-the-fly whenever the wheel is reset
        'outerRadius':200,
        'innerRadius':3,
        'textRadius':160,
        'spinTrigger':'.spin-trigger',
        'wheelBorderColor':'black',
        'wheelBorderWidth':3,
        'wheelTextFont': 'bold 15px sans-serif',
        'wheelTextColor':'black',
        'wheelTextShadowColor':'rgb(220,220,220)',
        'resultTextFont':'bold 30px sans-serif',
        'arrowColor':'black',
        'addTrigger':'.add',
        'deleteTrigger':'.delete',
        'clearTrigger':'.clear',
        'resetTrigger':'.reset',
        'joiner':'.joiner',
        'colorer':'.colorer',
        'winnerDiv':'.winner'
    };
    // SpinWheel instance methods
    SpinWheel.prototype.getConfig = function(key) {
        if (this.config.hasOwnProperty(key)) return this.config[key]; // per-instance config
        if (SpinWheel.config.hasOwnProperty(key)) return SpinWheel.config[key]; // default static config
        throw 'error: invalid config key "'+key+'" requested from SpinWheel::getConfig().';
    } // end SpinWheel::getConfig()
    SpinWheel.prototype.init = function() {
        this.setup();
        this.drawWheel();
    }; // end SpinWheel::init()
    SpinWheel.prototype.setup = function() {
        var thisClosure = this; // necessary to allow callback functions to access the SpinWheel instance
        $(this.getConfig('spinTrigger')).bind('click', function(ev) { (function(ev, target ) {
            ev.preventDefault();
            this.spin();
        }).call(thisClosure, ev, this ); } );
        $(this.getConfig('addTrigger')).bind('click', function(ev) { (function(ev, target ) {
            ev.preventDefault();
            //var item = $('<li/>').append($(this.getConfig('joiner')).val());
            //$(params.paricipants).append(item);
            var $joiner = $(this.getConfig('joiner'));
            var text = $joiner.val();
            if (text) { // don't add a segment with empty text
                var $color = $(this.getConfig('colorer'));
                var color = $color.find('option:selected').text();
                this.add(text, color );
                this.drawWheel();
            } // end if
        }).call(thisClosure, ev, this ); } );
        $(this.getConfig('deleteTrigger')).bind('click', function(ev) { (function(ev, target ) {
            ev.preventDefault();
            var $joiner = $(this.getConfig('joiner')); // reuse joiner input box
            var text = $joiner.val();
            if (text) { // don't delete with empty pattern
                this.del(new RegExp(text));
                this.drawWheel();
            } // end if
        }).call(thisClosure, ev, this ); } );
        $(this.getConfig('clearTrigger')).bind('click', function(ev) { (function(ev, target ) {
            ev.preventDefault();
            this.clear();
            this.drawWheel();
        }).call(thisClosure, ev, this ); } );
        $(this.getConfig('resetTrigger')).bind('click', function(ev) { (function(ev, target ) {
            ev.preventDefault();
            this.reset();
            this.drawWheel();
        }).call(thisClosure, ev, this ); } );
    }; // end SpinWheel::setup()
    SpinWheel.prototype.clear = function() {
        // clear primary wheel state data
        this.segmentTexts = [];
        this.colors = [];
        this.curAngle = 0;
        // also, in case there was a spin in-progress, stop it
        this.stopRotateWheel();
    }; // end SpinWheel::clear()
    SpinWheel.prototype.reset = function() {
        // precomputations
        var segmentTexts = this.getConfig('segmentTexts');
        var colors = this.getConfig('colors');
        // copy the configured segment texts to an instance attribute; this distinction is necessary, since we allow the user to manipulate the segments after initial configuration / resetting
        this.segmentTexts = segmentTexts.slice();
        // generate initial colors
        this.colors = [];
        for (var i = 0; i < this.segmentTexts.length; ++i)
            this.colors.push(colors.length > i ? colors[i] : this.genHexColor());
        // initialize curAngle, which must always exist and track the current angle of the wheel
        this.curAngle = 0;
        // also, in case there was a spin in-progress, stop it
        this.stopRotateWheel();
    }; // end SpinWheel::reset()
    SpinWheel.prototype.add = function(text, color ) {
        // translate color 'auto' to a generated color
        // also take anything invalid as auto
        if (!color || color === 'auto')
            color = this.genHexColor();
        // we just store the text of each segment on the segmentTexts array
        this.segmentTexts.push(text);
        this.colors.push(color);
    }; // end SpinWheel::add()
    SpinWheel.prototype.del = function(pattern) {
        for (var i = 0; i < this.segmentTexts.length; ++i) {
            if (this.segmentTexts[i].match(pattern)) {
                this.segmentTexts.splice(i, 1 );
                if (this.colors.length > i) this.colors.splice(i, 1 ); // colors array can be short
                --i;
            } // end if
        } // end for
    }; // end SpinWheel::del()
    SpinWheel.prototype.spin = function() {
        // the following are per-spin ad hoc state vars that are initialized for each spin, thus there's no point in storing values for them on the config struct
        this.spinAngleStart = Math.random()*10 + 10;
        this.spinTimeTotal = Math.random()*3 + 4*1000;
        this.spinTime = 0;
        this.rotateWheel();
    }; // end SpinWheel::spin()
    SpinWheel.prototype.genHexColor = function() {
        var hexDigits = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'];
        // 6 digits in a hex color spec
        var hexColor = '#';
        for (var i = 0; i < 6; ++i)
            hexColor = hexColor+hexDigits[Math.round(Math.random()*15)];
        return hexColor;
    }; // end SpinWheel::genHexColor()
    SpinWheel.prototype.rotateWheel = function() {
        // advance time
        this.spinTime += 30;
        // check for completion
        if (this.spinTime >= this.spinTimeTotal) {
            this.finishSpin();
            return;
        } // end if
        // advance angle
        var x = this.spinAngleStart - this.easeOut(this.spinTime, 0, this.spinAngleStart, this.spinTimeTotal );
        this.curAngle += (x*Math.PI/180);
        // redraw
        this.drawWheel();
        // schedule next rotation
        this.spinTimeout = setTimeout(this.rotateWheel.bind(this), 30 );
    }; // end SpinWheel::rotateWheel()
    SpinWheel.prototype.finishSpin = function() {
        // stop the rotation timeout chain
        this.stopRotateWheel();
        // precomputations
        var segmentNum = this.segmentTexts.length;
        var arc = 2*Math.PI/segmentNum;
        // hit segment calc
        var degrees = this.curAngle*180/Math.PI + 90;
        var arcd = arc*180/Math.PI;
        var index = Math.floor((360 - degrees%360)/arcd);
        // update the display
        this.canvasCtx.save();
        this.canvasCtx.font = this.getConfig('resultTextFont');
        var text = this.segmentTexts[index];
        $(this.getConfig('winnerDiv')).html(text).show();
        //canvasCtx.fillText(text, 250 - canvasCtx.measureText(text).width / 2, 250 + 10);
        this.canvasCtx.restore();
    }; // end SpinWheel::finishSpin()
    SpinWheel.prototype.stopRotateWheel = function() {
        // clear any existing timeout
        if (this.spinTimeout) {
            clearTimeout(this.spinTimeout);
            this.spinTimeout = null;
        } // end if
    }; // end SpinWheel::stopRotateWheel()
    SpinWheel.prototype.drawArrow = function() {
        this.canvasCtx.fillStyle = this.getConfig('arrowColor');
        var outerRadius = this.getConfig('outerRadius');
        this.canvasCtx.beginPath();
        this.canvasCtx.moveTo(250-4, 250-(outerRadius+15) );
        this.canvasCtx.lineTo(250+4, 250-(outerRadius+15) );
        this.canvasCtx.lineTo(250+4, 250-(outerRadius-15) );
        this.canvasCtx.lineTo(250+9, 250-(outerRadius-15) );
        this.canvasCtx.lineTo(250+0, 250-(outerRadius-23) );
        this.canvasCtx.lineTo(250-9, 250-(outerRadius-15) );
        this.canvasCtx.lineTo(250-4, 250-(outerRadius-15) );
        this.canvasCtx.lineTo(250-4, 250-(outerRadius+15) );
        this.canvasCtx.fill();
    }; // end SpinWheel::drawArrow()
    SpinWheel.prototype.drawWheel = function() {
        // precomputations
        var outerRadius = this.getConfig('outerRadius');
        var innerRadius = this.getConfig('innerRadius');
        var textRadius = this.getConfig('textRadius');
        var segmentNum = this.segmentTexts.length;
        var arc = 2*Math.PI/segmentNum;
        // init canvas
        this.canvasCtx.strokeStyle = this.getConfig('wheelBorderColor');
        this.canvasCtx.lineWidth = this.getConfig('wheelBorderWidth');
        this.canvasCtx.font = this.getConfig('wheelTextFont');
        this.canvasCtx.clearRect(0,0,500,500);
        // draw each segment
        for (var i = 0; i < segmentNum; ++i) {
            var text = this.segmentTexts[i];
            var angle = this.curAngle + i*arc;
            this.canvasCtx.fillStyle = this.colors[i];
            this.canvasCtx.beginPath();
            // ** arc(centerX, centerY, radius, startingAngle, endingAngle, antiClockwise);
            this.canvasCtx.arc(250, 250, outerRadius, angle, angle + arc, false );
            this.canvasCtx.arc(250, 250, innerRadius, angle + arc, angle, true );
            this.canvasCtx.stroke();
            this.canvasCtx.fill();
            this.canvasCtx.save();
            this.canvasCtx.shadowOffsetX = -1;
            this.canvasCtx.shadowOffsetY = -1;
            this.canvasCtx.shadowBlur    = 1;
            this.canvasCtx.shadowColor   = this.getConfig('wheelTextShadowColor');
            this.canvasCtx.fillStyle     = this.getConfig('wheelTextColor');
            this.canvasCtx.translate(250 + Math.cos(angle + arc/2)*textRadius, 250 + Math.sin(angle + arc/2)*textRadius );
            this.canvasCtx.rotate(angle + arc/2 + Math.PI/2);
            this.canvasCtx.fillText(text, -this.canvasCtx.measureText(text).width/2, 0 );
            this.canvasCtx.restore();
            this.canvasCtx.closePath();
        } // end for
        this.drawArrow();
    }; // end SpinWheel::drawWheel()
    SpinWheel.prototype.easeOut = function(t,b,c,d) {
        var ts = (t/=d)*t;
        var tc = ts*t;
        return b+c*(tc + -3*ts + 3*t);
    }; // end SpinWheel::easeOut()
    // export the class
    window.SpinWheel = SpinWheel;
})(jQuery);

这是提供jQuery插件接口的精简包装器:

(function($) {
    // spinwheel() jQuery plugin loader
    $.fn.spinwheel = function(config) {
        var $canvas = this; // the "this" object is the jQuery object that wraps the canvas HTML DOM object
        // create a new SpinWheel instance and store it on the canvas DOM object, which is attached to the DOM tree, so it will be accessible by external code
        var spinWheel = new SpinWheel($canvas, config );
        $canvas[0].spinWheel = spinWheel;
        // initialize it
        spinWheel.init();
    }; // end $.fn.spinwheel()
})(jQuery);
实例

化 by-jQuery-plugin 代码不会改变(除了我重命名了主配置参数):

$(document).ready(function() {
    $('.canvas').spinwheel({'segmentTexts':['♈','♉','♊','♋','♌','♍','♎','♏','♐','♑','♒','♓']});
});

演示:

http://jsfiddle.net/kYvzd/212/

如果您有任何问题,请告诉我。

尝试添加类似拉斐尔色轮的东西,并将其绑定到表单输入字段(甚至可能是隐藏的)

然后有这样的颜色代码:

 function genHex(){
        // change #colorcode to the id of your input field
        var value = $('#colorcode').val();
        // if no code has been selected by user return a generated colour code
        if(value === '') {
            var colors=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"], color = "", digit = [], i;
            for (i=0;i<6;i++){
                digit[i]=colors[Math.round(Math.random()*14)];             
                color = color+digit[i];     
            }   
            if($.inArray(color, colorCache) > -1){
                genHex();
            } else {
                colorCache.push('#'+color);
                return '#'+color;
            }
        }
        else {
            return value;
        }