? ? ? ? ? sparkline這個單詞,我第一次看的時候,也不知道這什么意思啊,以前根本沒聽過啊,但是這真真實實的出現在了redis的代碼中了,剛剛開始以為這也是屬于普通的隊列嘛,就把他分在了struct包里了。好來分析完了,與原本我所想的差太大了。sparkline英文中的意思“微線圖”,這么說吧,類似于折線圖,由一個一個信息點構成。所以看到這個意思,你或許就明白了sparkline.c是干什么用的了吧,就是畫圖用的。我們看看這個畫圖的內部結構是什么,畫圖需要的元素是哪些:
~~~
/* sparkline.h -- ASCII Sparklines header file
*
* ---------------------------------------------------------------------------
*
* Copyright(C) 2011-2014 Salvatore Sanfilippo <antirez@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __SPARKLINE_H
#define __SPARKLINE_H
/* sparkline是一類信息體積小和數據密度高的圖表。目前它被用作一些測量,
*相關的變化的信息呈現的方式,如平均溫度,股市交投活躍。sparkline常常以一組多條的形式出現在柱狀圖,折線圖當中。
*可以理解為一個圖線信息 */
/* A sequence is represented of many "samples" */
/* 可以理解為圖像上的一個信息點,有文字,有值的大小 */
struct sample {
double value;
char *label;
};
/* 圖線信息結構體,包括n個元素點,可以據此描述出圖,繪圖的可不是直接按點和值直接繪制的 */
struct sequence {
//當前元素點個數
int length;
//總共的文字個數,有些點沒有label描述,為NULL
int labels;
//元素點列表
struct sample *samples;
//元素中的最大值,最小值
double min, max;
};
/* 定義了一些渲染圖時候一些屬性操作設置 */
#define SPARKLINE_NO_FLAGS 0
#define SPARKLINE_FILL 1 /* Fill the area under the curve. */
#define SPARKLINE_LOG_SCALE 2 /* Use logarithmic scale. */
struct sequence *createSparklineSequence(void); //創建圖線序列結構體
void sparklineSequenceAddSample(struct sequence *seq, double value, char *label); //在圖線序列中添加一個信息點
void freeSparklineSequence(struct sequence *seq); //釋放圖線序列
sds sparklineRenderRange(sds output, struct sequence *seq, int rows, int offset, int len, int flags); //渲染圖線序列為一個圖,其實就是得到一個字符串組成的圖
sds sparklineRender(sds output, struct sequence *seq, int columns, int rows, int flags); //方法同上,只是少可一個偏移量
#endif /* __SPARKLINE_H */
~~~
我們看到上面的sample結構體其實“信息點”元素的意思了,里面很簡單,一個文字label,一個value值,簡潔明了,然后sequence就自然是圖線了,里面就定義了元素點列表了,里面還有線的長度,和最大值,最小值,信息還挺全面的線。后序的畫圖操作都是根據這個圖線序列結構體操作的。結構體一點都不復雜。但是畫圖的實現一點都不簡單,如何根據給定的一些點信息畫出一個類似折線的圖線呢,可別忘了,這是要在命令行窗口的圖線哦,所以不會像高級語言中的GUI的操作那樣很方便,我們看看redis代碼中是怎么寫的。
~~~
/* sparkline.c -- ASCII Sparklines
* This code is modified from http://github.com/antirez/aspark and adapted
* in order to return SDS strings instead of outputting directly to
* the terminal.
*
* ---------------------------------------------------------------------------
~~~
在sparkline.c中的注釋聲明,此代碼修改自?http://github.com/antirez/aspark,原來是開源的代碼實現,但是一開始真的不知道還有這么個叫aspark的東西,都跟BigData里的spark搞混了,然后我點擊此地址,官方解釋來了:
~~~
aspark is a C program to display ASCII Sparklines.
It is completely useless in 2011.
~~~
不錯,意思就是說aspark就是用來在C程序上顯示圖線效果的。后來,我看了下,的確代碼差不多,redis的代碼在上面加了自己的東西,稍稍修改,aspark的圖線展現有幾種形式,第一種,最簡單的展示:
~~~
$ ./aspark 1,2,3,4,10,7,6,5
`-_
__-` `
~~~
第二張把行數擴展為更多行,展示更多的數據,上面的這個為2行展示,數據多的時候,調節行數,默認輸出2行展示
~~~
$ ./aspark 1,2,3,4,5,6,7,8,9,10,10,8,5,3,1 --rows 4
_-``_
_`
-` `
_-` `_
~~~
當然可以更加可視化,在空白處填充字符,看起來更舒服:
~~~
$ ./aspark 1,2,3,4,5,6,7,8,9,10,10,8,5,3,1 --rows 4 --fill
_o##_
_#|||||
o#|||||||#
_o#||||||||||#_
~~~
用了"|"符號,很有想象力的哦,最最關鍵的我們看如何實現這樣的效果呢,核心代碼如下:
~~~
/* Render part of a sequence, so that render_sequence() call call this function
* with differnent parts in order to create the full output without overflowing
* the current terminal columns. */
/* 渲染出這個圖線信息 */
sds sparklineRenderRange(sds output, struct sequence *seq, int rows, int offset, int len, int flags) {
int j;
double relmax = seq->max - seq->min;
int steps = charset_len*rows;
int row = 0;
char *chars = zmalloc(len);
int loop = 1;
int opt_fill = flags & SPARKLINE_FILL;
int opt_log = flags & SPARKLINE_LOG_SCALE;
if (opt_log) {
relmax = log(relmax+1);
} else if (relmax == 0) {
relmax = 1;
}
while(loop) {
loop = 0;
memset(chars,' ',len);
for (j = 0; j < len; j++) {
struct sample *s = &seq->samples[j+offset];
//value派上用處了
double relval = s->value - seq->min;
int step;
if (opt_log) relval = log(relval+1);
//最后會算出相關的step
step = (int) (relval*steps)/relmax;
if (step < 0) step = 0;
if (step >= steps) step = steps-1;
if (row < rows) {
/* Print the character needed to create the sparkline */
/* step控制輸出的字符是哪一個 */
int charidx = step-((rows-row-1)*charset_len);
loop = 1;
if (charidx >= 0 && charidx < charset_len) {
chars[j] = opt_fill ? charset_fill[charidx] :
charset[charidx];
} else if(opt_fill && charidx >= charset_len) {
//用"|"填充內容,更加可視化
chars[j] = '|';
}
} else {
/* Labels spacing */
if (seq->labels && row-rows < label_margin_top) {
loop = 1;
break;
}
/* Print the label if needed. */
if (s->label) {
int label_len = strlen(s->label);
int label_char = row - rows - label_margin_top;
if (label_len > label_char) {
loop = 1;
chars[j] = s->label[label_char];
}
}
}
}
if (loop) {
row++;
output = sdscatlen(output,chars,len);
output = sdscatlen(output,"\n",1);
}
}
zfree(chars);
return output;
}
~~~
由于本人能力有限,有點不太懂里面的具體細節,大概看了下,把變量用到的地方稍稍看了下,上面的代碼都是非常優秀的代碼,值得我們學習,今天至少讓我知道了什么叫sparkline叫什么 了,哈哈。
- 前言
- (一)--Redis結構解析
- (二)--結構體分析(1)
- (三)---dict哈希結構
- (四)-- sds字符串
- (五)--- sparkline微線圖
- (六)--- ziplist壓縮列表
- (七)--- zipmap壓縮圖
- (八)--- t_hash哈希轉換
- (九)--- t_list,t_string的分析
- (十)--- testhelp.h小型測試框架和redis-check-aof.c日志檢測
- (十一)--- memtest內存檢測
- (十二)--- redis-check-dump本地數據庫檢測
- (十三)--- redis-benchmark性能測試
- (十四)--- rdb.c本地數據庫操作
- (十五)--- aof-append only file解析
- (十六)--- config配置文件
- (十七)--- multi事務操作
- (十八)--- db.c內存數據庫操作
- (十九)--- replication主從數據復制的實現
- (二十)--- ae事件驅動
- (二十一)--- anet網絡通信的封裝
- (二十二)--- networking網絡協議傳輸
- (二十三)--- CRC循環冗余算法和RAND隨機數算法
- (二十四)--- tool工具類(2)
- (二十五)--- zmalloc內存分配實現
- (二十六)--- slowLog和hyperloglog
- (二十七)--- rio系統I/O的封裝
- (二十八)--- object創建和釋放redisObject對象
- (二十九)--- bio后臺I/O服務的實現
- (三十)--- pubsub發布訂閱模式
- (三十一)--- latency延遲分析處理
- (三十二)--- redis-cli.c客戶端命令行接口的實現(1)
- (三十三)--- redis-cli.c客戶端命令行接口的實現(2)
- (三十四)--- redis.h服務端的實現分析(1)
- (三十五)--- redis.c服務端的實現分析(2)
- (三十六)--- Redis中的11大優秀設計