HTML5 segment color?
HTML5 segment color?
我正在使用这个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中的每个数字以查明问题所在,但仍然无法弄清楚。
编辑:
为了确保我不会引起任何混淆,我试图做的是对于添加到车轮中的每个新段,我需要选择一种新的颜色。
这段代码是一个很好的例子,说明了为什么原型模式比功能模式好得多。这个插件被定义为一个事实上的工厂函数,它声明了各种各样的函数局部状态变量(startAngle
、arc
、pplArray
等),这些变量被实现插件的各种方法封闭,最重要的是,一些方法被定义为使用对象文字语法的函数局部(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)。
另外,为了解决这个问题,我添加了Delete
、Clear
和Reset
按钮来演示对方向盘的更多控制。您现在可以通过正则表达式与文本匹配来删除片段,清除整个轮子,以便您可以从头开始构建它,并将其重置为初始配置(尽管如果您没有通过初始配置配置颜色,它们将再次随机生成,这肯定会与初始显示中的不同;但如果需要,您可以配置初始颜色)。
这是新的 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> </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;
}
- 为什么 .focus() 不起作用,而 .css(“color”,“red”) 在同一个选择器上起作用
- CKJustify和Color Button插件之间的不兼容
- 如何在php中创建一个函数,该函数与文本区域一起工作,通过输入类似[color:red]的内容来打印具有等效颜色的文本
- 如何使主体采用等同于 style=“background-color: returnBlue()” 的样式属性,其中 r
- 如何在刷新浏览器地址栏时重置css(a:visited{color:green})
- 如何使用segment.io's analystics.js在一个敲除自定义绑定中
- 如何设置'样式:color'淘汰赛中的颜色选择器.JS
- jQuery-backgroundColor动画未运行(包含color-lib)
- JS:“data-background-color”和.data(“background-color”)之间的关系
- jQueryUI animate(color) 不起作用
- 尝试在 JavaScript 中将 Color Hex 作为参数传递
- Segment.io 和 mixpanel 实现配置文件,适用于生产和非生产环境
- 使用 jQuery 选择在 CSS 中具有 color:lightGreen 的元素
- HTML5 segment color?
- 使用 JavaScript 更改
- 在firefox中使用element.style.color
- 在easelJS中,有一种方法可以说如果(object==color red)那么就做一些事情
- Three.js WebGL渲染器未更新面上的Color属性
- Google Chart API - Pie legend.textStyle color
- Segment.IO请求失败,状态为“已取消”