怎麼實現微信聊天時的氣泡圖(一)

首先,微信聊天的時候氣泡圖是什麼樣呢?上圖,
微信聊天氣泡圖
要實現這種氣泡圖,要怎麼作?
主要的就是實現那個小三角嗎?首先想到的確定是使用僞元素+定位,對!!!css

那咱們來試一下,上代碼點這裏,這樣很輕鬆的實現了想要的背景加小三角的效果css3

-----------------------可是--------------------------------------------git

像截圖中的圖片那樣,怎麼才能讓小三角里也充滿背景圖?

能夠由兩種實現的方式github

  1. canvas,繪製路徑,而後再clip圖片,本文暫不描述web

  2. 另外一種就是利用css3的新屬性clip-path屬性,繪製出要切割的路徑,而後再給clip-path屬性賦值,火狐和IE未實現此屬性canvas

這裏先講第二種,咱們觀察到大概有11個關鍵點,大體如圖
關鍵點
咱們能夠經過構造ploygon多邊形函數的參數來達到咱們的目的,其中四個圓角是對稱的,咱們能夠之計算一個圓角的圓弧的座標就好了,能夠經過對稱的關係再得出其餘三段圓弧的座標。數組

怎麼獲得一段圓弧的座標呢?這樣,根據高中數學知識可得,,,咱們用無數相鄰近的點的連線來模擬圓弧,微信

/**
@param r {number} 圓角半徑
@param x {number} 左上圓角圓心x座標
@param y {number} 左上圓角圓心y座標
x,y座標指的是相對於原始圖像的位置
*/

function makeTopLeftPos(r,x,y){
  var angle,rx,ry,a,b;var arr=[];item={};
  var len=2000;
  //這裏是用2000個點來模擬,可使用更多的點,但2000效果已經很不錯了
  for(var i=0;i<len+1;i++){
      angle=i/len*Math.PI/2;
      rx=x-r*Math.sin(angle);
      ry=y-r*Math.cos(angle);
      item.x=rx;
      item.y=ry;
      arr.push({x:rx,y:ry});
  }
  return arr;
}

而後根據對稱分別算出其餘三個圓角的位置函數

function makeTopRightPos(){
    var arr=makeTopLeftPos(r,a.x+r,a.y+r);
    var newArr=[];
    var rx,ry;
    for(var i=0,len=arr.length;i<len;i++){
        rx=d.x+a.x-arr[i].x;
        ry=arr[i].y;
        newArr.push({x:rx,y:ry});
    }
    newArr.reverse();
    return newArr;
}
function makeBottomLeftPos(){
    var arr=makeTopLeftPos(r,a.x+r,a.y+r);
    var newArr=[];
    var rx,ry;
    for(var i=0,len=arr.length;i<len;i++){
        ry=c.y+a.y-arr[i].y;
        rx=arr[i].x;
        newArr.push({x:rx,y:ry});
    }
    newArr.reverse();
    return newArr;
}
function makeBottomRightPos(){
    var arr=makeTopRightPos();
    var newArr=[];
    var rx,ry;
    for(var i=0,len=arr.length;i<len;i++){
        ry=c.y+d.y-arr[i].y;
        rx=arr[i].x;
        newArr.push({x:rx,y:ry});
    }
    newArr.reverse();
    return newArr;
}

注意,由於ploygan函數接受的路徑是逆時針的,因此咱們在獲得其餘三段圓弧的時候要注意點的順序,在這裏要翻轉一下數組,才能獲得正常的順序。
下面是獲得小三角的三個關鍵點,在這裏我默認小三角是等邊三角形了,給出三角形頂點座標進行了,其餘兩點的座標都在邊界上,截圖裏的5,7兩點。
num是在哪條邊界上,固然嫌麻煩的話能夠經過小三角形的座標範圍來斷定小三角是嵌在哪一個邊界上,我偷懶了。。spa

function makeTrigonPos(num){
    var x=p.x;
    var y=p.y;
    var trigonPos=[];
    switch(num){
        case 1: trigonPos=[{x:a.x,y:y-0.577*(a.x-x)},{x:x,y:y},{x:a.x,y:y+0.577*(a.x-x)}];break;
        case 2: trigonPos=[{x:x-0.577*(y-b.y),y:b.y},{x:x,y:y},{x:x+0.577*(y-b.y),y:b.y}];break;
        case 3: trigonPos=[{x:c.x,y:y-0.577*(x-c.x)},{x:x,y:y},{x:c.x,y:y+0.577*(x-c.x)}];break;
        default:
        trigonPos=[{x:c.x,y:y-0.577*(x-c.x)},{x:x,y:y},{x:c.x,y:y+0.577*(x-c.x)}];break;
    }
    var arr=trigonPos.map(function(item){
        return item.x+'px'+' '+item.y+'px';
    });
    return arr;
}

下面就拼接憑藉polygon函數的參數了

function makeAllParams(){
    var arr1=makeTopLeftPos(r,a.x+r,a.y+r).map(function(item){
        return item.x+'px'+' '+item.y+'px';
    });
    var arr2=makeBottomLeftPos().map(function(item){
        return item.x+'px'+' '+item.y+'px';
    });
    var arr3=makeBottomRightPos().map(function(item){
        return item.x+'px'+' '+item.y+'px';
    });
    var arr4=makeTopRightPos().map(function(item){
        return item.x+'px'+' '+item.y+'px';
    });
    var arr=[arr1,arr2,arr3,arr4];
    arr.splice(num,0,makeTrigonPos(num));
    var params=arr.join(',');
    img.style.webkitClipPath='polygon('+params+')';
}

完整代碼:看這裏
參考:css-tricks

相關文章
相關標籤/搜索