08-D3.js散點圖

散點圖.png

隨機數(shù)+坐標軸+散點圖

//Width and height
var w = 1000;
var h = 300;
var padding = 30;

//Dynamic, random dataset
var dataset = [];                   //Initialize empty array
var numDataPoints = 50;             //Number of dummy data points to create
var xRange = Math.random() * 1000;  //Max range of new x values
var yRange = Math.random() * 1000;  //Max range of new y values
for (var i = 0; i < numDataPoints; i++) {                   //Loop numDataPoints times
    var newNumber1 = Math.floor(Math.random() * xRange);    //New random integer
    var newNumber2 = Math.floor(Math.random() * yRange);    //New random integer
    dataset.push([newNumber1, newNumber2]);                 //Add new number to array
}

//Create scale functions
var xScale = d3.scaleLinear()
    .domain([0, d3.max(dataset, function (d) { return d[0]; })])
    .range([padding, w - padding * 2]);

var yScale = d3.scaleLinear()
    .domain([0, d3.max(dataset, function (d) { return d[1]; })])
    .range([h - padding, padding]);

var aScale = d3.scaleSqrt()
    .domain([0, d3.max(dataset, function (d) { return d[1]; })])
    .range([0, 10]);

//Define X axis
var xAxis = d3.axisBottom()
    .scale(xScale)
    .ticks(5);

//Define Y axis
var yAxis = d3.axisLeft()
    .scale(yScale)
    .ticks(5);

//Create SVG element
var svg = d3.select("body")
    .append("svg")
    .attr("width", w)
    .attr("height", h);

//Create circles
svg.selectAll("circle")
    .data(dataset)
    .enter()
    .append("circle")
    .attr("cx", function (d) {
        return xScale(d[0]);
    })
    .attr("cy", function (d) {
        return yScale(d[1]);
    })
    .attr("r", function (d) {
        return aScale(d[1]);
    });

//Create X axis
svg.append("g")
    .attr("class", "axis")
    .attr("transform", "translate(0," + (h - padding) + ")")
    .call(xAxis);

//Create Y axis
svg.append("g")
    .attr("class", "axis")
    .attr("transform", "translate(" + padding + ",0)")
    .call(yAxis);
    
  • 更新散點圖翎冲,支持數(shù)據(jù)更新和動態(tài)比
更新散點圖.gif

單擊上方的文本可以生成新數(shù)據(jù)并更新圖表

更新數(shù)據(jù)后,使用了動畫過渡

更新x和y軸的比例尺

<p>單擊此文本以使用新數(shù)據(jù)值更新圖表</p>
//Width and height
var w = 500;
var h = 300;
var padding = 30;

//Dynamic, random dataset
var dataset = [];                                           //Initialize empty array
var numDataPoints = 50;                                     //Number of dummy data points to create
var maxRange = Math.random() * 1000;                        //Max range of new values
for (var i = 0; i < numDataPoints; i++) {                   //Loop numDataPoints times
    var newNumber1 = Math.floor(Math.random() * maxRange);  //New random integer
    var newNumber2 = Math.floor(Math.random() * maxRange);  //New random integer
    dataset.push([newNumber1, newNumber2]);                 //Add new number to array
}

//Create scale functions
var xScale = d3.scaleLinear()
    .domain([0, d3.max(dataset, function (d) { return d[0]; })])
    .range([padding, w - padding * 2]);

var yScale = d3.scaleLinear()
    .domain([0, d3.max(dataset, function (d) { return d[1]; })])
    .range([h - padding, padding]);

//Define X axis
var xAxis = d3.axisBottom()
    .scale(xScale)
    .ticks(5);

//Define Y axis
var yAxis = d3.axisLeft()
    .scale(yScale)
    .ticks(5);

//Create SVG element
var svg = d3.select("body")
    .append("svg")
    .attr("width", w)
    .attr("height", h);

//Create circles
svg.selectAll("circle")
    .data(dataset)
    .enter()
    .append("circle")
    .attr("cx", function (d) {
        return xScale(d[0]);
    })
    .attr("cy", function (d) {
        return yScale(d[1]);
    })
    .attr("r", 2);

//Create X axis
svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + (h - padding) + ")")
    .call(xAxis);

//Create Y axis
svg.append("g")
    .attr("class", "y axis")
    .attr("transform", "translate(" + padding + ",0)")
    .call(yAxis);

d3.select("p")
    .on("click", function () {

        //New values for dataset
        var numValues = dataset.length;
        var maxRange = Math.random() * 1000;
        dataset = [];
        for (var i = 0; i < numValues; i++) {
            var newNumber1 = Math.floor(Math.random() * maxRange);
            var newNumber2 = Math.floor(Math.random() * maxRange);
            dataset.push([newNumber1, newNumber2]);
        }

        //Update scale domains
        xScale.domain([0, d3.max(dataset, function (d) { return d[0]; })]);
        yScale.domain([0, d3.max(dataset, function (d) { return d[1]; })]);

        //Update all circles
        svg.selectAll("circle")
            .data(dataset)
            .transition()
            .duration(1000)
            .attr("cx", function (d) {
                return xScale(d[0]);
            })
            .attr("cy", function (d) {
                return yScale(d[1]);
            });

        //Update X axis
        svg.select(".x.axis")
            .transition()
            .duration(1000)
            .call(xAxis);

        //Update Y axis
        svg.select(".y.axis")
            .transition()
            .duration(1000)
            .call(yAxis);
    });
  • 加載動畫在過渡開始和結束時執(zhí)行操作

//Update all circles
svg.selectAll("circle")
    .data(dataset)
    .transition()
    .duration(1000)
    // 在過渡開始時執(zhí)行
    .on("start", function () {
        d3.select(this) // 選擇 'this',即當前元素
      // .duration(150) //不能在這里添加新的過渡動畫尊蚁,
            .attr("fill", "magenta")
            .attr("r", 3)
    })
    .attr("cx", function (d) {
        return xScale(d[0]);
    })
    .attr("cy", function (d) {
        return yScale(d[1]);
    })
    // 在過渡結束時執(zhí)行
    .on("end", function () {
        d3.select(this)
            .attr("fill", "black")
            .attr("r", 2)
    })

在默認情況下亡笑,任何元素在任意時刻都只能有一個過渡效果。新過渡效果會打斷并覆蓋原來的過渡效果;

與jQuery不同横朋,默認情況下仑乌,jQuery 會把所有過渡效果排成隊列,然后一個接一個地執(zhí)行它們琴锭。換句話說晰甚,執(zhí)行新過渡不會自動中斷原有過渡。這種設計有時候會導致令人討厭的界面行為决帖,比如鼠標放到菜單上再離開后厕九,菜單并不會馬上就淡出,而是必須完全淡入之后再淡出地回。

由于過渡中存在的這個問題扁远,一定要記住只能在 ("start", ...) 里面執(zhí)行立即變換俊鱼,而不能再添加任何過渡效果。

  • 優(yōu)雅收場

在執(zhí)行("end", ...) 的時候畅买,主過渡已經(jīng)結束了并闲,因此再執(zhí)行新過渡不會產(chǎn)生任何副作用。

.on("end", function () {
    d3.select(this)
        .transition() //新增
        .duration(1000) //新增
        .attr("fill", "black")
        .attr("r", 2);
});

單擊 p 元素的文本谷羞,會發(fā)現(xiàn):

圓形立即變成粉紅并增大帝火;

圓形過渡到新位置;

圓形過渡到原來的顏色和大小湃缎。

  • 或者順序地使用連綴的方式
svg.selectAll("circle")
    .data(dataset)
    .transition() //過渡1
    .duration(1000)
    .on("start", function() {
        d3.select(this)
            .attr("fill", "magenta")
            .attr("r", 7);
    })
    .attr("cx", function(d) {
        return xScale(d[0]);
    })
    .attr("cy", function(d) {
        return yScale(d[1]);
    })
    .transition() //過渡2
    .duration(1000)
    .attr("fill", "black")
    .attr("r", 2);
  • 在剪切路徑中包含可見元素

好在 SVG 支持剪切路徑犀填,也就是 Photoshop 或 Illustrator 中的蒙 版。剪切路徑就是一個 SVG 元素雁歌,可以包含可見的元素宏浩,并與這個可見元素一起構成可以應用到其他元素的剪切路徑或蒙版。在把蒙版應用到某個元素時靠瞎,只有落在該蒙版圖形內(nèi)部的像素才會顯示比庄。

與 g 元素相似,clipPath 本身也不可見乏盐,但它可以包含可見的元素(這些元素用作蒙版)

<clipPath id="chart-area">
  <rect x="30" y="30" width="410" height="240"></rect>
</clipPath>

注意外面的 clipPath 元素有一個 ID佳窑,值為 chart-area。后面會通過這個 ID 來引用它父能。這個剪切路徑內(nèi)部有一個矩形神凑,將被用作蒙版。

  • 使用剪切路徑的步驟如下:
  1. 定義clipPath并給它一個ID

  2. 在這個clipPath中放一個可見的元素(通常是一個 rect何吝,但也可以包含

    circle 和其他可見元素)溉委;

//定義剪切路徑
svg.append("clipPath")//創(chuàng)建新的clipPath元素
    .attr("id", "chart-area")//為它指定ID,后面綁定時使用
    .append("rect")//在clipPath中爱榕,創(chuàng)建并添加新的rect
    .attr("x", padding) //設置rect的位置和大小
    .attr("y", padding)
    .attr("width", w - padding * 3)
    .attr("height", h - padding * 2);

我們希望把這個蒙版應用給所有圓形瓣喊,可以分別為每個圓形都添加一個對該clipPath 的引用。但把所有圓形都放到一個分組 g 中黔酥,然后給這個分組添加引用藻三, 會讓代碼更清晰也更簡單:

  1. 在需要使用蒙版的元素上添加一個對 clipPath 的引用。
//創(chuàng)建圓形
svg.append("g") //創(chuàng)建新的g元素跪者,包裹所有的circle
    .attr("id", "circles")  //指定它的ID為circles
    .attr("clip-path", "url(#chart-area)") //添加對 clipPath 的引用
    .selectAll("circle") 
    .data(dataset)
    ……

這個 g 元素的 clip?path 屬性指向了新創(chuàng)建的剪切路徑棵帽,語法有點不太常見:url(#chart-area)。但這都是 SVG 標準規(guī)定的渣玲。

clipPath.png

最終結果就是逗概,當圓形跑到圖表區(qū)域的邊界時,超出邊界的部分會被剪切掉忘衍。注意最上方和最右邊的那些圓形仗谆。

image.png
<p>Click on this text to update the chart with new data values as many times as you like!</p>
//Width and height
var w = 500;
var h = 300;
var padding = 30;

//Dynamic, random dataset
var dataset = [];                                           //Initialize empty array
var numDataPoints = 50;                                     //Number of dummy data points to create
var maxRange = Math.random() * 1000;                        //Max range of new values
for (var i = 0; i < numDataPoints; i++) {                   //Loop numDataPoints times
    var newNumber1 = Math.floor(Math.random() * maxRange);  //New random integer
    var newNumber2 = Math.floor(Math.random() * maxRange);  //New random integer
    dataset.push([newNumber1, newNumber2]);                 //Add new number to array
}

//Create scale functions
var xScale = d3.scaleLinear()
    .domain([0, d3.max(dataset, function (d) { return d[0]; })])
    .range([padding, w - padding * 2]);

var yScale = d3.scaleLinear()
    .domain([0, d3.max(dataset, function (d) { return d[1]; })])
    .range([h - padding, padding]);

//Define X axis
var xAxis = d3.axisBottom()
    .scale(xScale)
    .ticks(5);

//Define Y axis
var yAxis = d3.axisLeft()
    .scale(yScale)
    .ticks(5);

//Create SVG element
var svg = d3.select("body")
    .append("svg")
    .attr("width", w)
    .attr("height", h);

//Define clipping path
svg.append("clipPath")
    .attr("id", "chart-area")
    .append("rect")
    .attr("x", padding)
    .attr("y", padding)
    .attr("width", w - padding * 3)
    .attr("height", h - padding * 2);

//Create circles
svg.append("g")
    .attr("id", "circles")
    .attr("clip-path", "url(#chart-area)")
    .selectAll("circle")
    .data(dataset)
    .enter()
    .append("circle")
    .attr("cx", function (d) {
        return xScale(d[0]);
    })
    .attr("cy", function (d) {
        return yScale(d[1]);
    })
    .attr("r", 2);

//Create X axis
svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + (h - padding) + ")")
    .call(xAxis);

//Create Y axis
svg.append("g")
    .attr("class", "y axis")
    .attr("transform", "translate(" + padding + ",0)")
    .call(yAxis);



//On click, update with new data            
d3.select("p")
    .on("click", function () {

        //New values for dataset
        var numValues = dataset.length;                             
        var maxRange = Math.random() * 1000;                    
        dataset = [];                                               
        for (var i = 0; i < numValues; i++) {                   
            var newNumber1 = Math.floor(Math.random() * maxRange);
            var newNumber2 = Math.floor(Math.random() * maxRange);  
            dataset.push([newNumber1, newNumber2]);                 
        }

        //Update scale domains
        xScale.domain([0, d3.max(dataset, function (d) { return d[0]; })]);
        yScale.domain([0, d3.max(dataset, function (d) { return d[1]; })]);

        //Update all circles
        svg.selectAll("circle")
            .data(dataset)
            .transition()
            .duration(1000)
            .on("start", function () {
                d3.select(this)
                    .attr("fill", "magenta")
                    .attr("r", 7);
            })
            .attr("cx", function (d) {
                return xScale(d[0]);
            })
            .attr("cy", function (d) {
                return yScale(d[1]);
            })
            .on("end", function () {
                d3.select(this)
                    .transition()
                    .duration(1000)
                    .attr("fill", "black")
                    .attr("r", 2);
            });

        //Update X axis
        svg.select(".x.axis")
            .transition()
            .duration(1000)
            .call(xAxis);

        //Update Y axis
        svg.select(".y.axis")
            .transition()
            .duration(1000)
            .call(yAxis);
    });
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末指巡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子隶垮,更是在濱河造成了極大的恐慌藻雪,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狸吞,死亡現(xiàn)場離奇詭異勉耀,居然都是意外死亡,警方通過查閱死者的電腦和手機蹋偏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門便斥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人威始,你說我怎么就攤上這事枢纠。” “怎么了黎棠?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵晋渺,是天一觀的道長。 經(jīng)常有香客問我脓斩,道長木西,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任随静,我火速辦了婚禮八千,結果婚禮上,老公的妹妹穿的比我還像新娘燎猛。我一直安慰自己恋捆,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布重绷。 她就那樣靜靜地躺著沸停,像睡著了一般。 火紅的嫁衣襯著肌膚如雪论寨。 梳的紋絲不亂的頭發(fā)上星立,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天爽茴,我揣著相機與錄音葬凳,去河邊找鬼。 笑死室奏,一個胖子當著我的面吹牛火焰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播胧沫,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼昌简,長吁一口氣:“原來是場噩夢啊……” “哼占业!你這毒婦竟也來了?” 一聲冷哼從身側響起纯赎,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤谦疾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后犬金,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體念恍,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年晚顷,在試婚紗的時候發(fā)現(xiàn)自己被綠了峰伙。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡该默,死狀恐怖瞳氓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情栓袖,我是刑警寧澤匣摘,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站叽赊,受9級特大地震影響恋沃,放射性物質發(fā)生泄漏。R本人自食惡果不足惜必指,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一囊咏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧塔橡,春花似錦梅割、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至癞谒,卻和暖如春底燎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背弹砚。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工双仍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人桌吃。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓朱沃,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子逗物,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容