如何制作一个简单的腾讯logo ——css、canvas、svg制作方法

668 阅读12分钟

笔者是个小萌新,最近刚刚学习了css、canvas、svg这几种常用的画图方法,所以打算使用这3钟方法制作一个小logo,以加深自己对这方面知识的掌握。废话不多说,先放上本次要制作的logo~

由上面的腾讯logo图中,我们可以看到logo的组成大致为周围环绕的绿、黄、红三色条形图案,以及中间的小企鹅。这个logo的元素并不复杂,所以一开始我选择从较简单的3色条形图案入手。

通过观察logo外围的图形,可以大概得到一个思路

①、3个不同颜色的图案的形状是完全一样的,我们可以通过画出其中一个,定好旋转 的中心后,得到另外的两个

②、图形具有一定的弧度,所以我首先想到的是通过贝塞尔函数的方法去绘制,但是 因为取得参数需要花费较多的时间,所以打算采用绘制圆弧的方法去绘制。

③、该图案至少由3个不同半径的圆组成闭合的图形,所以首先我们需要得到构成图形 的几个圆的圆心的相对位置及半径。

④、通过上网查找和计算绘制这些圆弧所使用的一些参数,通过下面的视频链接可以 得到一些绘制的数据www.bilibili.com/video/av381…。(链接内容仅供参考,本文参数仅供参考,可以通过自己的方法取得参数)

有了上面大概的思路之后笔者就开始了图形的绘制(下面例子统一以右上方的绿色图形为样本开始绘制)

1、Canvas绘制图形

首先,准备我们的画板,创建一个canvas元素。

<body>
    <canvas id="canvas" width ="600" height ="600">你的浏览器不支持canvas</canvas>
    <script type="text/javascript" >
        var canvas = document.getElementById("canvas");
        var ctx = canvas.getContext("2d");
    </script>
</body>

通过beginPath()方法创建一个新的绘制路径,并且设置canvas的坐标原点,绘制线条的宽度和颜色。

ctx.beginPath();
ctx.rotate(Math.PI*240/180);
ctx.strokeStyle = "green" ;
ctx.lineWidth = 3;

使用arc()方法绘制圆弧,arc()方法的几个参数按顺序分别为圆心的x、y坐标,半径r,起始的角度、结束的角度,而最后的参数true为逆时针绘制,false为顺时针绘制,默认为顺时针(false);

ctx.arc(29,-116,30,Math.PI*1.1/2,Math.PI*3.08/2);
ctx.arc(1,1,150,Math.PI*3.13/2,Math.PI/9);
ctx.arc(42,50,100,0,Math.PI*3.54/2,true);
ctx.arc(-13,59,150,-Math.PI/5.99,Math.PI*3.14/2,true);

在绘制的时候有几个需要注意的地方。这几个圆弧是在同一条路径里面的,这样在最后形成闭合路径的时候,才能通过fill()方法对绘制出的图形上色。arc()方法绘制的圆形起始位置需要注意,这里就不用图片标示了。还有里面的角度设置,无论是顺时针画还是逆时针画,角度的大小都是从起始位置按顺时针计算的,也可以这么理解,我们平时看的x,y轴的正轴是往→和↑的,而这里的坐标轴的正轴是往→和↓的,因此造成了角度的区别。

最后通过闭合路径,绘制并上色之后得到了我们需要的图形

ctx.closePath();
ctx.stroke()

ctx.fillStyle = "green";
ctx.fill();

接着,我们新创建一条路径,旋转一定的角度之后,开始和之前一致的绘制方法就可以得到另外两个图形了。

ctx.beginPath();
ctx.rotate(Math.PI*240/180);

!!注意:这里画布的旋转一定要添加到绘制图形之前,rotate()方法不对绘制之前的图形生效。第三个绘制的图形要在上一次画布旋转的基础上进行旋转,而不是按照120°、240°就可得到最终图形。

由于企鹅的绘制需要使用贝塞尔函数实现,所以在这里我通过canvas导入一张企鹅的图片完成logo。这里需要注意的是,由于图片的加载是需要一定的时间的,所以需要通过onload事件来判断进行图片的绘制。不然,会出现使用了drawImage()方法却没看到图片的情况。

ctx.beginPath();
var img = new Image();
img.src = "images/qie.png";
img.onload = function(){
    ctx.rotate(Math.PI*240/180);
    ctx.drawImage(img,-60,-60,120,120);
}

附上绘制结果图

2、svg绘制图形

由于这次制作的图形是不规则的,所以我想到的是通过使用svg的path标签构建一个路径。并设置好线条和颜色。

<body> 
    <svg width="600" height="600" id="logo">
        <path class="shape" stroke = "green" stroke-width ="2" fill="green"></path>
    </svg>
</body>

首先照例取得path,并且设置绘制路径的坐标圆点。

<script type="text/javascript">

        var path = document.getElementsByClassName("shape"); 
        
        //以坐标(300,300)为圆心
        path[0].setAttribute('transform','translate(300,300)');
    </script>

定义一些基本的参数。

//每段圆弧对应的圆的半径
        var r1 = 30;
        var r2 = 150;
        var r3 = 100; 
        var r4 = 150;

        //起始位置
        var cx = 90*Math.cos(Math.PI*75/180);
        var cy = -90*Math.sin(Math.PI*75/180);

        //每一段圆弧的结束位置
        var x1 = 150*Math.cos(Math.PI*75/180);
        var y1 = -150*Math.sin(Math.PI*75/180);
        var x2 = 150*Math.cos(Math.PI*20/180);
        var y2 = 150*Math.sin(Math.PI*20/180);
        var x3 = 125;
        var y3 = 0;

这里来说明一下path的d属性的设置。这里由于我们需要绘制圆弧,可以知道,我们需要使用的是起始位置M和绘制圆弧路径A这两个参数。其中d=M 0 0表示画笔的初始位置,后接A rx ry Xrotation flag1 flag2 x y , 这几个参数分别为

横轴(rx)和纵轴(ry)的大小(绘制圆的话两者一致),

X为相对于坐标的旋转角度,

flag1是 绘制大弧或小弧

flag2 是 (1)顺时针绘制,(0)逆时针绘制

x、y为绘制的终点坐标

由上面可以发现,同样是通过闭合路径的绘制,svg和canvas是有一定的差别的。canvas绘制圆弧是通过 圆心的坐标x、y,半径r,起始和结束位置的角度来确定圆弧的路径的,而svg是通过起始和结束位置的坐标,根据半径r来得到圆弧,并且由于两点之间是确定不了具体的圆弧的,所以还需要加上flag1、flag2来得到唯一的圆弧。所以,我使用svg绘制圆弧的时候,不必知道圆心的位置和旋转的角度,但是要计算出每段圆弧的始末位置,这也是上面定义的内容。

 var dOne = ['M',cx,cy,'A',r1,r1,0,1,1,x1,y1];
        var dTwo = ['A',r2,r2,0,0,1,x2,y2];
        var dThree = ['A',r3,r3,0,0,0,x3,y3];
        var dFour = ['A',r4,r4,0,0,0,cx,cy];

        var d = dOne.concat(dTwo,dThree,dFour);
        
        path[0].setAttribute('d',d.join(" "));

通过把每一段圆弧的各项参数放入到一个数组中,并且最终连接起来就是一条完整的路径了。这里有一点需要注意,M参数定义的起始位置在一条闭合路径中只需要有一个就行,在之后的圆弧中添加M的相当与建立新的路径,这样在为整个图形上色的时候就会出现错误。

最后,完成一个图形后,添加另外两个图形的path标签,并且在path中transform属性中添加不同的旋转角度,就可以得到另外两个图形了。(企鹅通过css添加图片如何添加的代码在css绘制中会说明)

<svg width="600" height="600" id="logo">
        <path class="shape" stroke = "green" stroke-width ="2" fill="green"></path>
        <path class="shape" stroke = "yellow" stroke-width ="2" fill="yellow"></path>
        <path class="shape" stroke = "red" stroke-width ="2" fill="red"></path>
    </svg>
        path[0].setAttribute('transform','translate(300,300)');
        path[1].setAttribute('transform','translate(300,300)rotate(240)');
        path[2].setAttribute('transform','translate(300,300)rotate(120)');

在旋转方面,canvas和svg也是不太一样的。canvas旋转的是整块画布,所以后面绘制的路径统一受到影响,而svg是单独对路径进行旋转,路径互相之间不会影响。

        path[0].setAttribute('d',d.join(" "));
        path[1].setAttribute('d',d.join(" "));
        path[2].setAttribute('d',d.join(" "));

最后的结果图

3、css绘制图形

在css制作中,我的想法是把图形拆分成两个图形,一个半圆作为头部,一个是尾巴作为身体部分,两段拼接就是要制作的图形。 下面是这两部分的制作方法。

.lHead{
            width:30px;
            height:60px;
            background: green;
            border-radius:30px 0 0 30px ;
            position:absolute;
        }

由上面的样式可以得到一个半圆,主要是通过border-radius把设置左上角和左下角的角为圆角,另外两个角不变,就可以完成。

.lBody{
            width:150px;
            height:90px;
            position:absolute;
            border-top:60px solid green;
            border-radius:0 150px 0 0 ;
            left:29px;
        }

尾巴的图形是通过制作1/4圆,并且只留下上边距而得到的,这样看如果不清楚,为其添加背景颜色就清楚为什么会形成尾巴的样子了。

制作完头部和尾巴两个图形,只需要通过定位连接起来,就完成其中的一个图形了。

body{
            margin:50px;
            margin-left:300px;
            position:relative;
        }

创建3个div来转载头部和尾巴组合的图形。(结构如下图)

<body>
    <div class="logo rotateG">
        <div class="lHead green"></div>
        <div class="lBody greenB"></div>
    </div>
    <div class="logo rotateY">
            <div class="lHead yellow"></div>
            <div class="lBody yellowB"></div>
    </div>
    <div class="logo rotateR">
            <div class="lHead red"></div>
            <div class="lBody redB"></div>
    </div>
    <div id="qie"></div>
</body>

为3个图形设定一样的旋转中心。

.logo{
            position:absolute;
            transform-origin:30px 150px; 
        }

每个图形旋转不同的角度。

.rotateR{
    
            transform: rotate(140deg);

        }

.rotateY{
  
    transform: rotate(260deg);

}

建立不同的背景颜色样式,和边框颜色样式(因为尾巴部分需要的是边框颜色的样式)

.green{
            background: green;
        }
        
.greenB{
    border-color:green;
}

.red{
    background: red;
}

.redB{
    border-color:red;
}

.yellow{
    background: yellow;
}

.yellowB{
    border-color:yellow;
}

导入企鹅的图片。

#qie{
            
            background: url("images/qie.png")no-repeat;
            background-size: cover;
            width:120px;
            height:120px;
            position: absolute;
            top:90px;
            left:-30px;
           
        }

最终得到的结果。

Css制作题外话:一开始用css绘制的时候,我是想通过不同的圆形遮挡的方式绘制出图形,图中为蓝色、绿色两个大圆,红色、黄色两个小圆,以及灰色的遮挡块,把相应的图形设置为白色后。

可是当旋转的时候发现,那些用来遮挡的部分,同样遮挡住了两外两个绘制的条状图形,导致无法同时显现完整的图案,因此最后才使用了上面的拼接图形的方法。

关于css、canvas、svg制作的一些心得体会。

1、从最直观的成品来说,三个最终图形的效果是差不多的,但是如果放大之后,canvas会出现模糊的现象,svg、css的图案依旧清晰。这是因为canvas的图形是位图,是由像素点组成的,而svg、css的图案是矢量图,主要是线条和颜色块构成,因此放大图片之后,canvas的图像会出现模糊。

2、从代码的数量来看,如果只是绘制出一个图形则canvas代码量最少(由于本次绘制中svg中包含了起始结束点的计算,代码量较大),而绘制完整的图形时,三者差不多。

3、从绘制图形难度来说,css是3者中最简单的,只需要知道图形长宽的大小,并且应用相应的样式即可。而canvas、svg之间各有优势。在上面svg绘制的过程中,我有说明过两者的绘制条件上的一些区别。就圆弧来说,如果初始、结束位置比较容易得到,svg无疑会简单很多,但是像上面我已经知道需要多少角度的圆弧,还要通过半径r计算起始结束位置就会很麻烦,而这时候canvas较好用。(ps:得到合适的圆弧参数真的花了不少时间。)

4、从图像的路径连续程度的方面来说,css拼接图形的时候难免会有1、2像素的误差,有可能出现拼接口不连续,或者图形之间不够紧密的情况。而canvas和svg都是路径构成的,不会出现不连续的情况。但是我在使用canvas绘制圆弧的时候,两段圆弧之间也不是完美接合上的,只是因为同一路径的原因首尾连接上了而已。而svg则不同,每一段的结尾是下一段的开始,不会有不连续的问题存在,这也是起始、结束位置的优点。

5、从圆弧的修正容易程度来说,canvas是较容易的,通过修改圆心,半径,角度,都可以做到微调整。而css比较困难做到对图形的细微调整,只能通过边框和长宽改变图形的总体外形,或者拼接更多的图形来达到复杂的图像。

6、由于篇幅关系,笔者就没有在文章中写下自己构思可以添加的一些交互动画效果了,可是关于这3种方法在交互操作时的一些区别还是需要说一下。在实现交互方面,canvas相对于另外两者就不占什么优势了。canvas不能直接通过内部图形绑定事件,需要通过获取鼠标的位置绑定。而css、svg绘制的图像都有元素标签进行绑定事件,所以可以在交互较多的情况下使用。

以上就是笔者本次一个小小制作的思路,制作过程,以及自己的一些感想。