7

这项工作的目标是理解和发挥我听说过的一些对象概念的含义。

关于赏金

有很多不同的方式/方法可以做到这一点。

我的尝试不是很干净:为了添加第二个时钟,另一个时区,我必须编辑 3 个不同的地方。这不好(见答案底部)。

我怎样才能做一些更有的事情?

一开始:

后期编辑:最初的问题是关于在 jquery 和 mootools 之间进行选择,现在已经做出了选择;目标是通过使用mootools来改进这一点。

我写了一个小样本/演示来玩javascript和svg:

var cx  =128;
var cy  =128;
var slen=120;
var mlen=116;
var hlen= 80;
var selem;
var melem;
var helem;
function setvars() {
    selem=document.getElementById("seconds");
    melem=document.getElementById("minutes");
    helem=document.getElementById("hours");
    drawtime();
};
function drawtime() {
    var now=new Date();
    var nows=now.getTime()%60000;
    var nowm=now.getMinutes()*1.0+1.0*nows/60000;
    var nowh=now.getHours()*1.0+1.0*nowm/60;
    var sposx=cx + slen * Math.sin( nows / 30000 * Math.PI );
    var sposy=cy - slen * Math.cos( nows / 30000 * Math.PI );
    var mposx=cx + mlen * Math.sin( nowm / 30 * Math.PI );
    var mposy=cy - mlen * Math.cos( nowm / 30 * Math.PI );
    var hposx=cx + hlen * Math.sin( nowh / 6 * Math.PI );
    var hposy=cy - hlen * Math.cos( nowh / 6 * Math.PI );
    selem.setAttribute("x1",sposx);
    selem.setAttribute("y1",sposy);
    selem.setAttribute("x2",sposx);
    selem.setAttribute("y2",sposy);
    melem.setAttribute("x2",mposx);
    melem.setAttribute("y2",mposy);
    helem.setAttribute("x2",hposx);
    helem.setAttribute("y2",hposy);
    window.setTimeout(drawtime,80)
};
setvars();
#box1    { stroke: black; }
#minutes { stroke: #2266AA; }
#hours   { stroke: #3388CC; }
#seconds { stroke: #CCCC22; }
line,circle {
    opacity:0.65;
    fill:none;
    stroke-width:8;
    stroke-linecap:round;
    stroke-linejoin:round;
    marker:none;
    stroke-miterlimit:4;
    stroke-dasharray:none;
    stroke-opacity:1;
    visibility:visible;
    display:inline;
    overflow:visible;
    enable-background:accumulate
}
<svg xmlns="http://www.w3.org/2000/svg" id="svg2" width="100%"
     height="100%" viewBox="0 0 900 256" version="1.0">
    <title  id="title1">Clock</title>
    <circle id="box1"    cy="128" cx="128"  r="124" />
    <line   id="hours"   x1="128" y1="128" x2="128"  y2="48" />
    <line   id="minutes" x1="128" y1="128" x2="244" y2="128" />
    <line   id="seconds" x1="128"   y1="8" x2="128"   y2="8" />
</svg>

(最初发布在jsfiddle)因为我对 javascript jquery 和/或 mootools 不是很有经验,所以我想知道是否存在一些更简单的方法,也许是以不同的方式编写它。

如何使用 jquery 或 mootools 围绕固定中心进行简单旋转:

var hposx=cx + hlen * Math.sin( nowh / 6 * Math.PI );
var hposy=cy - hlen * Math.cos( nowh / 6 * Math.PI );
helem.setAttribute("x2",hposx);
helem.setAttribute("y2",hposy);

如何客观化这段代码?(如果这可能是一件好事)......

欢迎所有使用面向对象、特定库或其他示例的示例!

4

4 回答 4

4

您的代码简单明了。如果没有 jQuery 或 MooTools,您的任务很简单,我认为您不应该尝试使用它。

对于旋转,我认为 jQuery 或 MooTools 中没有内置工具,但是您可以在 svg 对象上使用矩阵转换,请阅读:http: //msdn.microsoft.com/en-us/library/ie/hh535760 %28v=vs.85%29.aspx

或者检查这个问题:SVG 旋转变换矩阵

至于制作一个对象:

您当然可以将代码分割成更多功能,或者创建一个表示当前小时/分钟/秒的对象

var clock = {
    time: {
        s: 0,
        m: 0,
        h: 0    
    },
    pos: {
        x: 128,
        y: 128
    },

   .... anything else you might want to add
};

您首先在一组函数中设置它的属性

clock.setTime = function (date) {
    this.time.s = date.getTime()%60000;
    this.time.m = date.getMinutes()*1.0+1.0*nows/60000;
    this.time.h = date.getHours()*1.0+1.0*nowm/60;
};

并在另一组函数中阅读它们:

clock.getMinPos = function () {
    var x = ...;// Sine is ok.
    var y = ...;// Cosine is ok.
    // I don't like matrices anyway.
    return [x, y];
};

真的只是尝试将您的代码划分为功能性任务。一个功能应该只做一件事。

于 2012-11-03T12:22:36.353 回答
3

从赏金编辑:转到底部!

第一个答案

在阅读了pete(非常感谢!你给了我很好的研究方法)和SoonDead(也感谢转换的第一步)的第一条评论之后,我环顾了一下jquerymootools代码,最后我选择了mootools为了减少我的代码,因为mootools让我提交一个arrayforobject.get和一个hash(关联数组) for objet.set

(function () {
    "use strict";
    var Point = function(x,y) {
         this.x=x;
         this.y=y;
    };
    var Path = function(center,length,both) {
        this.center = center;
        this.length = length;
        this.both   = both;
        this.end    = function(alpha) {
            var retx = 1.0*this.center.x +
                this.length*Math.sin(alpha);
            var rety = 1.0*this.center.y -
                this.length*Math.cos(alpha);
            if (typeof(this.both)!=='undefined')
              return { x1:retx, x2:retx, y1:rety, y2:rety }
            else return { x2:retx, y2:rety };
        };
    };
    var Hand = function(svgline,both) {
        this.elem = document.id(svgline);
        var p     = this.elem.get(['x1','y1','x2','y2']);
        this.path = new Path (
          new Point(p.x1,p.y1),Math.sqrt(
            Math.pow(1.0*p.x2-1.0*p.x1,2) +
            Math.pow(1.0*p.y2-1.0*p.y1,2)) ,both);
        this.setPos = function(angle) {
            this.elem.set(this.path.end(angle));
        };
    };
    var Clock = function(hour,minute,second,refresh) {
        this.hour    = new Hand(hour);
        this.minute  = new Hand(minute);
        this.second  = new Hand(second,true);
        this.refresh = refresh;
        this.setTime = function(timePos) {
            var self= this;
            var tps = 1.0*timePos.getTime() % 60000;
            var tpm = timePos.getMinutes()*1.0 +
                1.0* tps/60000;
            var tph = timePos.getHours()*1.0   + 1.0* tpm/60;
            this.second.setPos(tps / 30000 * Math.PI);
            this.minute.setPos(tpm / 30    * Math.PI);
            this.hour  .setPos(tph / 6     * Math.PI);
            setTimeout(function() {
              self.setTime(new Date())},this.refresh) };
    };
    var clock=new Clock('hours','minutes','seconds',120);
    clock.setTime(new Date());
}());
#box1    { stroke: black; fill:#ccc }
#minutes { stroke: #2288AA; }
#hours   { stroke: #3388CC; }
#seconds { stroke: #CCCC22; }
line,circle {
    opacity:0.65;
    fill:none;
    stroke-width:8;
    stroke-linecap:round;
    stroke-linejoin:round;
    marker:none;
    stroke-miterlimit:4;
    stroke-dasharray:none;
    stroke-opacity:1;
    visibility:visible;
    display:inline;
    overflow:visible;
    enable-background:accumulate
}
<script
  src="http://ajax.googleapis.com/ajax/libs/mootools/1.4.5/mootools-nocompat.js"
  ></script>
<svg xmlns="http://www.w3.org/2000/svg" id="svg2" width="100%"
     height="100%" viewBox="0 0 900 256" version="1.0">
    <title  id="title1">Clock</title>
    <circle id="box1"    cy="128" cx="128"  r="124" />
    <line   id="hours"   x1="128" y1="128" x2="128"  y2="48" />
    <line   id="minutes" x1="128" y1="128" x2="244" y2="128" />
    <line   id="seconds" x1="128" y1="128" x2="128"   y2="8" />
</svg>

好吧,现在我的新代码小了 8 行,甚至总是可读的。

这是一个步骤,但objectization意味着将其作为一个对象......

  1. 保持可重复使用
  2. 保持高效(不要进行无用的操作或两次相同的操作)
  3. 使其可重用(作为一个对象,将所有固定变量排除在外......)

一个中间人的结果

但现在代码看起来像:

(function () {
    "use strict";
    var Point = function(x,y) {
         this.x=x;
         this.y=y;
    };
    var Path = function(center,length,both) {
        this.center = center;
        this.length = length;
        this.both   = both;
        this.end    = function(alpha) {
            var retx=1.0*this.center.x+this.length*Math.sin(alpha);
            var rety=1.0*this.center.y-this.length*Math.cos(alpha);
            if (typeof(this.both)!=='undefined')
                 return { x1:retx, x2:retx, y1:rety, y2:rety }
            else return { x2:retx, y2:rety };
        };
    };
    var Hand = function(svgline,both) {
        this.elem   = document.id(svgline);
        var p=this.elem.get(['x1','y1','x2','y2']);
        this.path   = new Path ( new Point(p.x1,p.y1),
                                Math.sqrt(Math.pow(1.0*p.x2-1.0*p.x1,2)+
                                          Math.pow(1.0*p.y2-1.0*p.y1,2)),
                                 both);
        this.setPos = function(angle) {
            this.elem.set(this.path.end(angle));
        };
    };
    var Clock = function(hour,minute,second,refresh) {
        this.hour    = new Hand(hour);
        this.minute  = new Hand(minute);
        this.second  = new Hand(second,true);
        this.setTime = function(timePos) {
            var self= this;
            var tps = 1.0*timePos.getTime() % 60000;
            var tpm = timePos.getMinutes()*1.0 + 1.0* tps/60000;
            var tph = timePos.getHours()*1.0   + 1.0* tpm/60;
            this.second.setPos(tps / 30000 * Math.PI);
            this.minute.setPos(tpm / 30    * Math.PI);
            this.hour  .setPos(tph / 6     * Math.PI);
        };
    };
    var RefreshLoop = function(refresh) {
        var newdate=new Date();
        clock1.setTime(newdate);
        newdate=newdate.getTime()+newdate.getTimezoneOffset()*60000;
        clock2.setTime(new Date(newdate));
        clock3.setTime(new Date(newdate+20700000));
        clock4.setTime(new Date(newdate+28800000));
    };
    var clock1=new Clock('hours','minutes','seconds',120);
    var clock2=new Clock('hours2','minutes2','seconds2',120);
    var clock3=new Clock('hours3','minutes3','seconds3',120);
    var clock4=new Clock('hours4','minutes4','seconds4',120);
    RefreshLoop.periodical(500);
}());

在所有部分都保持较小的情况下,myclock是一个真正可重复使用的对象(现在可以工作 4 次)。

该函数setTime必须一起计算所有手,因为每个值包含其他值的一部分,但每个操作只能执行一次。

对于我的时钟, aPath由一个固定的、start point一个固定的length和一个变量定义direction,Path.end 是指定的计算终点direction

并且 aHand是一个给定的SVG line,带有他的原始Path,和一个可选标志,指定在设置时,起点和终点都必须定位在相同的值(零长度线,圆形终止给出一个圆形点)。

备注(错误?):由于每个元素都在 SVG 中定义,并且 Path.length 是根据 Path 两端之间的距离计算的,因此seconds必须首先[x1,y1]在时钟中心绘制路径,! = [x2,y2]!)

希望有些人想纠正/改进/讨论我的objectization...

更新2

我想,这是现在的最终版本,对象很简单,使用 mootools(可能不会太多,欢迎评论),我的最终时钟可以多次使用以显示不同的 timezome。

(function () {
    "use strict";
    var Point = function(x,y) {
         this.x=x;
         this.y=y;
    };
    var Path = function(center,length,both) {
        this.center = center;
        this.length = length;
        this.both   = both;
        this.end    = function(alpha) {
            var retx=1.0*this.center.x+this.length*Math.sin(alpha);
            var rety=1.0*this.center.y-this.length*Math.cos(alpha);
            if (typeof(this.both)!=='undefined')
                 return { x1:retx, x2:retx, y1:rety, y2:rety }
            else return { x2:retx, y2:rety };
        };
    };
    var Hand = function(svgline,both) {
        this.elem   = document.id(svgline);
        var p=this.elem.get(['x1','y1','x2','y2']);
        this.path   = new Path ( new Point(p.x1,p.y1),
                                Math.sqrt(Math.pow(1.0*p.x2-1.0*p.x1,2)+
                                          Math.pow(1.0*p.y2-1.0*p.y1,2)),
                                 both);
        this.setPos = function(angle) {
            this.elem.set(this.path.end(angle));
        };
    };
    var Clock = function(hour,minute,second,refresh) {
        this.hour    = new Hand(hour);
        this.minute  = new Hand(minute);
        this.second  = new Hand(second,true);
        this.setTime = function(timePos) {
            var self= this;
            var tps = 1.0*timePos.getTime() % 60000;
            var tpm = timePos.getMinutes()*1.0 + 1.0* tps/60000;
            var tph = timePos.getHours()*1.0 + 1.0* tpm/60;
            this.second.setPos(tps / 30000 * Math.PI);
            this.minute.setPos(tpm / 30    * Math.PI);
            this.hour  .setPos(tph / 6     * Math.PI);
        };
    };
    var RefreshLoop = function(refresh) {
        var newdate=new Date();
        clock1.setTime(newdate);
        newdate=newdate.getTime()+newdate.getTimezoneOffset()*60000;
        clock2.setTime(new Date(newdate));
        clock3.setTime(new Date(newdate+20700000));
    };
    var clock1=new Clock('hours','minutes','seconds',120);
    var clock2=new Clock('hours2','minutes2','seconds2',120);
    var clock3=new Clock('hours3','minutes3','seconds3',120);
    RefreshLoop.periodical(500);
}());
circle   { stroke: black; }
.startbg { stop-color: #eeeeee; }
.endbg   { stop-color: #777777; }
.box     { fill:url(#grad0); }
.box1    { fill:url(#grad1); }
.box2    { fill:url(#grad2); }
.box3    { fill:url(#grad3); }
.label   { stroke: #424242;fill:#eee;stroke-width:1; }
.minutes { stroke: #2288AA; }
.hours   { stroke: #3388CC; }
.seconds { stroke: #CCCC22; }
line,circle,rect {
    opacity:0.65;
    fill:none;
    stroke-width:8;
    stroke-linecap:round;
    stroke-linejoin:round;
    marker:none;
    stroke-miterlimit:4;
    stroke-dasharray:none;
    stroke-opacity:1;
    visibility:visible;
    display:inline;
    overflow:visible;
    enable-background:accumulate
}
text {
    font-size:15px;
    font-style:normal;
    font-variant:normal;
    font-weight:normal;
    font-stretch:normal;
    text-align:center;
    line-height:100%;
    writing-mode:lr-tb;
    text-anchor:middle;
    fill:#000000;fill-opacity:.7;
    stroke:none;
    font-family:Nimbus Sans L;
}
<script
  src="http://ajax.googleapis.com/ajax/libs/mootools/1.4.5/mootools-nocompat.js"
  ></script>
<svg xmlns="http://www.w3.org/2000/svg" id="svg2" width="100%"
    height="100%" viewBox="-1 -1 900 555" version="1.0"><defs>
    <linearGradient gradientUnits="userSpaceOnUse" id="g0"><stop
        class="startbg" /><stop class="endbg" offset="1" /></linearGradient>
    <linearGradient id="grad0" x1="-1"  y1="-1" x2="256" y2="277" xlink:href="#g0" />
    <linearGradient id="grad1" x1="256" y1="-1" x2="515" y2="277" xlink:href="#g0" />
    <linearGradient id="grad2" x1="512" y1="-1" x2="771" y2="277" xlink:href="#g0" />
    </defs>
    <circle class="box"   id="box1" cy="128" cx="128" r="124" />
    <line class="hours"   id="hours" x1="128" y1="128" x2="128" y2="48" />
    <line class="minutes" id="minutes" x1="128" y1="128" x2="244" y2="128" />
    <line class="seconds" id="seconds" x1="128" y1="128" x2="128" y2="8" />
    <rect class="label"   x="16"  y="256" width="224" height="20" />
    <text x="0" y="0" xml:space="preserve">
        <tspan x="128" y="271">Local time</tspan></text>

    <circle class="box1" id="box2" cy="128" cx="385" r="124" />
    <line class="hours" id="hours2" x1="385" y1="128" x2="385" y2="48" />
    <line class="minutes" id="minutes2" x1="385" y1="128" x2="501" y2="128" />
    <line class="seconds" id="seconds2" x1="385" y1="128" x2="385" y2="8" />
    <rect class="label" x="273" y="256" width="224" height="20" />
    <text x="0" y="0" xml:space="preserve">
        <tspan x="385" y="271">Universal Time Clock</tspan></text>

    <circle class="box2" id="box3" cy="128" cx="642" r="124" />
    <line class="hours" id="hours3" x1="642" y1="128" x2="642" y2="48" />
    <line class="minutes" id="minutes3" x1="642" y1="128" x2="758" y2="128" />
    <line class="seconds" id="seconds3" x1="642" y1="128" x2="642" y2="8" />
    <rect class="label" x="530"  y="256" width="224" height="20" />
    <text x="0" y="0" xml:space="preserve">
        <tspan x="642" y="271">Asia/Katmandu</tspan></text>
</svg>

新尝试完全重写

这将momentjs用于国际信息,但没有其他库。

"use strict";
var gv={ clockcount: 1,
         svg:'http://www.w3.org/2000/svg',
         xlnk:'http://www.w3.org/1999/xlink',
         tzlist:['Local'].concat(moment.tz.names()),
         vbox:document.getElementById('svg').getAttribute("viewBox").split(" ")
       };
function mousepos(event) {
    var minxy=innerWidth;
    if (minxy > innerHeight) minxy=innerHeight;
    return {
        x:((event.clientX-(innerWidth-minxy)/2)/minxy)*(gv.vbox[2]-gv.vbox[0]),
        y:((event.clientY-(innerHeight-minxy)/2)/minxy)*(gv.vbox[3]-gv.vbox[1])
    };
};

function myClock(cx,cy,r,tz) {
    var clock=this, elem;
    this.cx=128;
    if (typeof(cx)!=='undefined') this.cx=cx;
    this.cy=128;
    if (typeof(cy)!=='undefined') this.cy=cy;
    this.r=100;
    if (typeof(r)!=='undefined') this.r=r;
    this.tz=new Date().getTimezoneOffset();
    this.setTz=function(tz) {
        if (typeof(tz)!=='undefined') {
            this.label=tz;
            if (tz!=="Local") {
                var ndte=new Date();
                var tzoff=moment(ndte).tz(tz).format('HH mm ss').split(' ');
                var tznow=Math.floor(ndte/1000)%86400;
                this.tz=(tznow-(tzoff[0]*3600+tzoff[1]*60+1*tzoff[2]))/60;
            } else this.tz=new Date().getTimezoneOffset();
        } else this.label="Local";
    };
    this.setTz(tz);
    this.clkid=gv.clockcount++;
    this.floor=0;
    this.toggleFloor=function(e) { e.preventDefault();
                                   clock.floor=1-clock.floor; };
    this.toggleSecDraw=function(e) { e.preventDefault();
                                     clock.secdraw=1-clock.secdraw; };
    this.wheel=function(e) { e.preventDefault();
                             var sens=1;
                             if (typeof(e.detail)!=='undefined') {
                                 if ( 0 > e.detail ) { sens=-1; }
                             } else if ( 0 > e.wheelDelta ) { sens=-1; };
                             var cidx=gv.tzlist.indexOf(clock.label)*1+1*sens;
                             if (cidx < 0) cidx=gv.tzlist.length-1;
                             if (cidx >= gv.tzlist.length) cidx=0;
                             clock.setTz(gv.tzlist[cidx]);
                             clock.draw=0; };
    this.moused = function (evt) {
        evt.preventDefault(); var m=mousepos(evt);
        if ((clock.r/2 > Math.pow(Math.pow(Math.abs(clock.cx-m.x),2)+
                                  Math.pow(Math.abs(clock.cy-m.y),2),.5))) {
            clock.box.addEventListener("mousemove", clock.mousem, true);
        } else {
            clock.box.addEventListener("mousemove", clock.mouser, true);
        };
        clock.box.addEventListener("mouseup", clock.mouseu, true);
    };
    this.mouseu = function(evt) {
        evt.preventDefault(); clock.draw=0;
        clock.box.removeEventListener("mousemove", clock.mouser, true);
        clock.box.removeEventListener("mousemove", clock.mousem, true);
        clock.box.removeEventListener("mouseup", clock.mouseu, true);
    };
    this.mouser = function(evt) {
        evt.preventDefault(); clock.draw=0;
        var m=mousepos(evt);
        clock.r=1.25*Math.pow(Math.pow(Math.abs(clock.cx-m.x),2)+
                              Math.pow(Math.abs(clock.cy-m.y),2),.5);
    };
    this.mousem = function(evt) { evt.preventDefault(); clock.draw=0;
        var m=mousepos(evt); clock.cx=m.x; clock.cy=m.y; };
    this.drop = function(evt) { evt.preventDefault();clearInterval(clock.loop);
                                clock.box.remove(); };
    elem=document.createElementNS(gv.svg,'g');             
    elem.setAttribute('id','box'+this.clkid);
    document.getElementById('myClock').appendChild(elem);
    this.box=document.getElementById('box'+this.clkid);
    this.box.addEventListener("mousedown",     this.moused ,true);
    this.box.addEventListener("click",         this.toggleSecDraw,true);
    this.box.addEventListener("dblclick",      this.toggleFloor ,true);
    this.box.addEventListener('mousewheel',    this.wheel, true);
    this.box.addEventListener('DOMMouseScroll',this.wheel, true);
    this.box.addEventListener('contextmenu',   this.drop, true);
    
    elem=document.createElementNS(gv.svg,'circle');
    this.fill='fill: url(#g'+this.clkid+');'+
        'stroke: url(#gb'+this.clkid+');';
    elem.setAttribute('style',this.fill);
    elem.setAttribute('id','crc'+this.clkid);
    this.box.appendChild(elem);
    this.crc=document.getElementById('crc'+this.clkid);
    
    this.ticks=[];
    for (var i=0;i<60;i++) {
        elem=document.createElementNS(gv.svg,'line');
        elem.setAttribute('class','ticks');
        elem.setAttribute('id','t'+i+'c'+this.clkid);
        this.box.appendChild(elem);
        this.ticks.push(document.getElementById('t'+i+'c'+this.clkid));
    };
    
    elem=document.createElementNS(gv.svg,'rect');
    elem.setAttribute('class','label');
    elem.setAttribute('id','r'+this.clkid);
    this.box.appendChild(elem);
    this.rct=document.getElementById('r'+this.clkid);
    
    elem=document.createElementNS(gv.svg,'text');
    elem.setAttribute('id','x'+this.clkid);
    this.box.appendChild(elem);
    this.tbx=document.getElementById('x'+this.clkid);
    
    elem=document.createElementNS(gv.svg,'tspan');
    elem.setAttribute('id','t'+this.clkid);
    this.tbx.appendChild(elem);
    this.txt=document.getElementById('t'+this.clkid);

    elem=document.createElementNS(gv.svg,'line');
    elem.setAttribute('id','hr'+this.clkid);
    elem.setAttribute('class','hours');
    this.box.appendChild(elem);
    this.hhr=document.getElementById('hr'+this.clkid);

    elem=document.createElementNS(gv.svg,'line');
    elem.setAttribute('id','mn'+this.clkid);
    elem.setAttribute('class','minutes');
    this.box.appendChild(elem);
    this.hmn=document.getElementById('mn'+this.clkid);

    elem=document.createElementNS(gv.svg,'line'); 
    elem.setAttribute('id','sc'+this.clkid);
    elem.setAttribute('class','seconds');
    this.box.appendChild(elem);
    this.hsc=document.getElementById('sc'+this.clkid);
    
    elem=document.createElementNS(gv.svg,'linearGradient');
    elem.setAttribute('id','g'+this.clkid);
    elem.setAttributeNS(gv.xlnk,'xlink:href','#g0');
    document.getElementById('defs').appendChild(elem);
    this.deg=document.getElementById('g'+this.clkid);
    elem=document.createElementNS(gv.svg,'linearGradient');
    elem.setAttribute('id','gb'+this.clkid);
    elem.setAttributeNS(gv.xlnk,'xlink:href','#g0');
    document.getElementById('defs').appendChild(elem);
    this.dgb=document.getElementById('gb'+this.clkid);

    this.getTZ=function() { return this.tz; };
    this.setTZ=function(tz) { this.tz=tz; };
    this.draw=0;
    this.secdraw=1;
    this.adjust=function() {
        if (clock.draw!==1) {
            clock.crc.setAttribute('style','stroke-width:'+.03*clock.r+";"+
                                  clock.fill);
            clock.hhr.setAttribute('style','stroke-width:'+.11*clock.r);
            clock.hmn.setAttribute('style','stroke-width:'+.075*clock.r);
            clock.hsc.setAttribute('style','stroke-width:'+
                                  (clock.secdraw==1?.03:.09)*clock.r);
            clock.crc.setAttribute('cx',clock.cx);
            clock.crc.setAttribute('cy',clock.cy);
            clock.crc.setAttribute('r',clock.r);
            clock.rct.setAttribute('height',.2*clock.r);
            clock.rct.setAttribute('x',clock.cx-.9*clock.r);
            clock.rct.setAttribute('y',clock.cy*1+1.1*clock.r);
            clock.txt.innerHTML=clock.label;
            clock.txt.setAttribute('x',clock.cx);
            clock.txt.setAttribute('y',clock.cy*1+1.25*clock.r);
            clock.txt.setAttribute('style','font-size: '+(.15*clock.r)+"px;");
            var w=clock.label.length*.1*clock.r+20.0;
            clock.rct.setAttribute('x',clock.cx-w/2);
            clock.rct.setAttribute('width',w);
            for (var i=0;i<60;i++) {
                var x=clock.cx*1+.925*clock.r*Math.sin(i/30*Math.PI);
                var y=clock.cy*1+.925*clock.r*Math.cos(i/30*Math.PI);
                clock.ticks[i].setAttribute('x1',x);
                clock.ticks[i].setAttribute('y1',y);
                clock.ticks[i].setAttribute('x2',x);
                clock.ticks[i].setAttribute('y2',y);
                clock.ticks[i].setAttribute('style','stroke-width:'+
                                            (i%5==0?.04:.02)*clock.r);
            };
            clock.hsc.setAttribute('x1',clock.cx);
            clock.hsc.setAttribute('y1',clock.cy);
            clock.hmn.setAttribute('x1',clock.cx);
            clock.hmn.setAttribute('y1',clock.cy);
            clock.hhr.setAttribute('x1',clock.cx);
            clock.hhr.setAttribute('y1',clock.cy);
            clock.deg.setAttribute('x1',clock.cx-1.1*clock.r);
            clock.deg.setAttribute('y1',clock.cy-1.1*clock.r);
            clock.deg.setAttribute('x2',clock.cx+1.1*clock.r);
            clock.deg.setAttribute('y2',clock.cy+1.1*clock.r);
            clock.dgb.setAttribute('x1',clock.cx+1.1*clock.r);
            clock.dgb.setAttribute('y1',clock.cy+1.1*clock.r);
            clock.dgb.setAttribute('x2',clock.cx-1.1*clock.r);
            clock.dgb.setAttribute('y2',clock.cy-1.1*clock.r);
            clock.draw=1;
        };
        var now=new Date()/1000.0-this.tz*60;
        if (this.floor==1) now=Math.floor(now);
        var x=this.cx+(this.secdraw==1?.975:.925)*
            this.r*Math.sin((now % 60)/30*Math.PI);
        var y=this.cy-(this.secdraw==1?.975:.925)*
            this.r*Math.cos((now % 60)/30*Math.PI);
        this.hsc.setAttribute('x2',x);
        this.hsc.setAttribute('y2',y);
        if (this.secdraw==0) {
            this.hsc.setAttribute('x1',x);
            this.hsc.setAttribute('y1',y);
        }
        if (this.floor==1) now=Math.floor(now/60)         
        else now=now/60;
        x=this.cx+.9*this.r*Math.sin((now %60)/30*Math.PI);
        y=this.cy-.9*this.r*Math.cos((now %60)/30*Math.PI);
        this.hmn.setAttribute('x2',x);
        this.hmn.setAttribute('y2',y);
        if (this.floor==1) now=Math.floor(now/60)         
        else now=now/60;
        x=this.cx+.7*this.r*Math.sin((now % 12)/6*Math.PI);
        y=this.cy-.7*this.r*Math.cos((now % 12)/6*Math.PI);
        this.hhr.setAttribute('x2',x);
        this.hhr.setAttribute('y2',y);
    };
    this.animate = function() {        clock.adjust(); };
    this.loop=setInterval(this.animate,66);
    
};

document.getElementById('svg').addEventListener('dblclick', function(e){ if (e.
 target.id!=='svg')return;var m=mousepos(e);new myClock(m.x,m.y,80,'Local'); });

var clocks=['UTC','Local','Asia/Kolkata'];
for (var i=0;i<3;i++) { new myClock( 90+170*i,90,80,clocks[i]); };
circle   { stroke: black; }
.startbg { stop-color: #CCC; }
.endbg   { stop-color: #222; }
.label   { stroke: #424242;fill:#eee;stroke-width:1; }
.minutes { stroke: #2288AA; }
.hours   { stroke: #3388CC; }
.seconds { stroke: #CCCC22; }
.ticks   { stroke: black; }
line,circle,rect,point {
    opacity:0.65;
    stroke-linecap:round;
    stroke-linejoin:round;
    marker:none;
    stroke-miterlimit:4;
    stroke-dasharray:none;
    stroke-opacity:1;
    visibility:visible;
    display:inline;
    overflow:visible;
    enable-background:accumulate
}
text {
    font-style:normal;
    font-variant:normal;
    font-weight:normal;
    font-stretch:normal;
    text-align:center;
    line-height:100%;
    writing-mode:lr-tb;
    text-anchor:middle;
    fill:#000000;fill-opacity:.7;
    stroke:none;
    font-family:Nimbus Sans L;
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/css" href="myClock2.css" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" id="svg"
    xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" >
   <defs id="defs">
     <linearGradient gradientUnits="userSpaceOnUse" id="g0"><stop
       class="startbg" /><stop class="endbg" offset="1" />
     </linearGradient></defs>
 <script type="text/ecmascript"
         xlink:href="http://momentjs.com/downloads/moment-with-locales.js" />
 <script type="text/ecmascript"
         xlink:href="http://momentjs.com/downloads/moment-timezone-with-data.js" />
 <title id="title">Clock object</title>
 <g id="myClock"></g>
 <script type="text/ecmascript" xlink:href="myClock2.js" />
 <script type="text/ecmascript">
</script>
</svg>

svg 绘图上有 3 个对象时钟,具有一些功能:

鼠标命令:

  • 当鼠标悬停在时钟上时

    • 单击 => 切换秒:路径或点
    • 拖动中心 => 移动时钟
    • 拖动边框 => 调整时钟大小
    • 双击 => 切换地板模式
    • 滚动鼠标滚轮 => 更改时区
    • 右键单击(上下文菜单)=> 删除时钟
  • 当鼠标悬停在背景上时:

    • 双击 => 添加新时钟

这并不完美,因为有一些错误,主要是在鼠标定位中width="100%" height="100%",我认为这是封闭片段的效果,但这并不重要。

您可以在我的网站上找到完整可用的SVG 图片

于 2012-11-04T14:24:12.663 回答
2

我创建了一个 D3 时钟对象

普朗克

在此处输入图像描述


  • d3Clock 可以多次实例化。

  • 构造函数接受 X、Y、Width、TimeZoneOffset 对象、标签

  <script>
    $(document).ready(function() {

      var tokyoClock = new d3Clock({
        clockCenterX: 140,
        clockCenterY: 150,
        clockWidth: 130,
        title: 'Tokyo',
        TZOffset: {
          hours: 13
        }
      });

  • 方法也公开手动设置 TZOffsets

      var iranClock = new d3Clock({
        clockCenterX: 355,
        clockCenterY: 360,
        clockWidth: 180,
        title: 'Iran'    
      });

      iranClock.Hours(8);
      iranClock.Minutes(30);

d3Clock 机箱:

var d3Clock = function(data) {
  var clockGroup, fields, formatHour, formatMinute, formatSecond, pi, render, scaleHours, scaleSecsMins, vis;

  width = data.clockWidth;
  height = data.clockWidth;
  offSetX = data.clockWidth / 2;
  offSetY = offSetX;
  var x = data.clockCenterX;
  var y = data.clockCenterY;

  var hourOffset = 0;
  var minOffset = 0;
  var secOffset = 0;

  title = data.title;

  var clockRadius = data.clockWidth * 0.45;
  formatSecond = d3.time.format("%S");
  formatMinute = d3.time.format("%M");
  formatHour = d3.time.format("%H");

  pi = Math.PI;
  scaleSecsMins = d3.scale.linear().domain([0, 59 + 59 / 60]).range([0, 2 * pi]);
  scaleHours = d3.scale.linear().domain([0, 11 + 59 / 60]).range([0, 2 * pi]);

  // create Parent Div and set x, y
  var iDiv = document.createElement('div');
  iDiv.setAttribute("style", 'background-color: transparent; height: ' + width + ' px; width: ' + width + 'px; position: absolute; top:' + y + 'px; left: ' + x + 'px; text-align: center; v-align:bottom;');
  iDiv.innerHTML = '<span style="font-weight: bold;">' + title + '</span>';
  document.getElementsByTagName('body')[0].appendChild(iDiv);
  vis = d3.select(iDiv).append("svg:svg").attr("width", width).attr("height", height);

  clockGroup = vis.append("svg:g").attr("transform", "translate(" + offSetX + "," + offSetY + ")");
  clockGroup.append("svg:circle").attr("r", clockRadius).attr("fill", "lightgrey").attr("class", "clock outercircle").attr("stroke", "black").attr("stroke-width", 5);
  clockGroup.append("svg:circle").attr("r", 4).attr("fill", "black").attr("class", "clock innercircle");


  // private set TZ Offset methods
  var setTZSeconds = function(sec) {
    if (sec !== undefined)
      secOffset = sec;
  }
  var setTZMins = function(min) {
    if (min !== undefined)
      minOffset = min;
  }
  var setTZHours = function(hr) {
    if (hr !== undefined)
      hourOffset = hr;
  }


  // exposed TimeZoneOffset
    this.Seconds = function(Sec) {
      setTZSeconds(Sec);
    }
    this.Minutes = function(Mins) {
      setTZMins(Mins);
    }
    this.Hours = function(Hours) {
      setTZHours(Hours);
    }


  if (data.TZOffset != undefined) {
    setTZHours(data.TZOffset.hours);
    setTZMins(data.TZOffset.mins);
    setTZSeconds(data.TZOffset.secs);
  }

  // Get time values and apply offsets
  fields = function() {
    var d, data, hour, minute, second;
    d = new Date();
    second = d.getSeconds() + secOffset;
    minute = d.getMinutes() + minOffset;
    hour = d.getHours() + hourOffset + minute / 60;
    return data = [{
      "unit": "seconds",
      "text": formatSecond(d),
      "numeric": second
    }, {
      "unit": "minutes",
      "text": formatMinute(d),
      "numeric": minute
    }, {
      "unit": "hours",
      "text": formatHour(d),
      "numeric": hour
    }];
  };


  render = function(data) {
    var hourArc, minuteArc, secondArc;
    clockGroup.selectAll(".clockhand").remove();
    secondArc = d3.svg.arc().innerRadius(0).outerRadius(clockRadius * .9).startAngle(function(d) {
      return scaleSecsMins(d.numeric);
    }).endAngle(function(d) {
      return scaleSecsMins(d.numeric);
    });
    minuteArc = d3.svg.arc().innerRadius(0).outerRadius(clockRadius * .85).startAngle(function(d) {
      return scaleSecsMins(d.numeric);
    }).endAngle(function(d) {
      return scaleSecsMins(d.numeric);
    });
    hourArc = d3.svg.arc().innerRadius(0).outerRadius(clockRadius * .7).startAngle(function(d) {
      return scaleHours(d.numeric % 12);
    }).endAngle(function(d) {
      return scaleHours(d.numeric % 12);
    });
    clockGroup.selectAll(".clockhand").data(data).enter().append("svg:path").attr("d", function(d) {
      if (d.unit === "seconds") {
        return secondArc(d);
      } else if (d.unit === "minutes") {
        return minuteArc(d);
      } else if (d.unit === "hours") {
        return hourArc(d);
      }
    }).attr("class", "clockhand").attr("stroke", "black").attr("style", function(d) {
      if (d.unit === "seconds") {
        return "stroke-width: 2; stroke: white"
      } else if (d.unit === "minutes") {
        return "stroke-width: 3;"
      } else if (d.unit === "hours") {
        return "stroke-width: 4;"
      }
    }).attr("fill", "none");
  };

  setInterval(function() {
    var data;
    data = fields();
    return render(data);
  }, 1000);
};

可以公开更多方法以允许自定义

所有带前缀的函数this.都公开以用于实例化对象。所以:

this.Seconds = function(Sec) {
  setTZSeconds(Sec);
}
this.Minutes = function(Mins) {
  setTZMins(Mins);
}
this.Hours = function(Hours) {
  setTZHours(Hours);
}

公开访问私有setTZSeconds(), setTZMins(), setTZHours().

对于公共方法调用完成工作的私有方法,这被认为是一种很好的 OO 形式。公共方法可以限制或过滤结果(就像我undefined在私有方法中检查不一样。

公共方法可以暴露给

  • 更改 x, y 以便在实例化后可以在屏幕上移动时钟对象
  • 改变大小
  • 更改时钟指针、标题位置/样式的样式
于 2015-05-19T19:45:23.893 回答
1

更新:

您可以使用 jQuery 或 MooTools,但我看不出这样做的意义。jQuery 和 MooTools 是使 DOM 操作或 AJAX 更简单的库,并且您使用 SVG(在这种情况下)所做的主要目的并没有做太多的 DOM 操作,并且不涉及 AJAX。

也就是说,如果您决定使用其中一个(我将在此答案中使用 jQuery,因为我还不精通 MooTools),我将首先将函数调用包装在一个$(document).ready()函数中的IIFE

$(document).ready(function {
    'use strict';
    ...
});

代替:

(function () {
    'use strict';
    ...
}());

您还可以在内部将元素存储为 jQuery 对象:

this.element = $('#' + hand);

然后用稍微少一点的输入来获取/设置属性:

this.setPosition = function setPosition(now) {
    var x2 = this.element.attr('x2'),
        y2 = this.element.attr('y2');
    this.setInterval(now);
    x2 = this.center.x + (this.length * Math.sin(this.interval / this.frequency * Math.PI));
    y2 = this.center.y - (this.length * Math.cos(this.interval / this.frequency * Math.PI));
    this.element.attr('x2', x2);
    this.element.attr('y2', y2);
    if (this.isSeconds) {
        //special case
        this.element.attr('x1', x2);
        this.element.attr('y1', y2);
    }
};

总体上没有太大区别,在这种情况下加载库的额外开销或额外带宽(当然也不值得两者)都不值得。

如果您有一个更复杂的示例,那么可能值得包含 jQuery 或 MooTools 来提供帮助,但在这种情况下,我认为两者都不会增加足够的价值。

原来的:

我假设通过“对象化此代码”,您的意思是使其更加抽象。就目前而言,您拥有的代码:

  • 做这项工作
  • 相当紧凑
  • 可读性强

因此不太可能变得更小(或必然“更好”)。

也就是说,您可以像这样抽象一个“手”对象:

(function () {
    'use strict';
    var Point = function Point(x, y) {
        this.x = x;
        this.y = y;
    };
    var Hand = function Hand(hand, center, length) {
        this.center = center;
        this.element = document.getElementById(hand);
        this.frequency = 0;
        this.isSeconds = (hand === 'seconds');
        this.hand = hand;
        this.length = length;
        this.interval = 0;
        this.parseMilliseconds = function parseMilliseconds(now) {
            return now.getTime() % 60000;
        };
        this.parseMinutes = function parseMinutes(now) {
            return now.getMinutes() + (this.parseMilliseconds(now) / 60000);
        };
        this.parseHours = function parseHours(now) {
            return now.getHours() + (this.parseMinutes(now) / 60);
        };
        this.setFrequency = function getFrequency() {
            switch (this.hand) {
            case 'hours':
                this.frequency = 6;
                break;
            case 'minutes':
                this.frequency = 30;
                break;
            case 'seconds':
                this.frequency = 30000;
                break;
            }
        };
        this.setInterval = function setInterval(now) {
            switch (this.hand) {
            case 'hours':
                this.interval = this.parseHours(now);
                break;
            case 'minutes':
                this.interval = this.parseMinutes(now);
                break;
            case 'seconds':
                this.interval = this.parseMilliseconds(now);
                break;
            }
        };
        this.setPosition = function setPosition(now) {
            var x2 = this.element.getAttribute('x2'),
                y2 = this.element.getAttribute('y2');
            this.setInterval(now);
            x2 = this.center.x + (this.length * Math.sin(this.interval / this.frequency * Math.PI));
            y2 = this.center.y - (this.length * Math.cos(this.interval / this.frequency * Math.PI));
            this.element.setAttribute('x2', x2);
            this.element.setAttribute('y2', y2);
            if (this.isSeconds) {
                //special case
                this.element.setAttribute('x1', x2);
                this.element.setAttribute('y1', y2);
            }
        };
        this.setFrequency();
    };
    var updateClock = function updateClock(hours, minutes, seconds) {
        var now = new Date();
        hours.setPosition(now);
        minutes.setPosition(now);
        seconds.setPosition(now);
        window.setTimeout(function () {
            updateClock(hours, minutes, seconds);
        }, 80);
    };
    var initClock = function initClock() {
        var center = new Point(128, 128),
            seconds = new Hand('seconds', center, 120),
            minutes = new Hand('minutes', center, 116),
            hours = new Hand('hours', center, 80);
        updateClock(hours, minutes, seconds);
    };
    initClock();
}());

在这里行动:http: //jsfiddle.net/MbktF/19/

于 2012-11-03T18:27:13.170 回答