Code Monkey home page Code Monkey logo

d3hub's People

Stargazers

 avatar

Watchers

 avatar

d3hub's Issues

关于透明度fill-opacity

 d3.selectAll(elements).style('fill-opacity', 1);
  1. fill-opacity:该属性指定了填色的不透明度或当前对象的内容物的不透明度

参考资料:fill-opacity

创建一个均匀的量化的线性比例尺 d3.d3.scaleQuantize

var quantizeScale = d3.scaleQuantize()
    .domain([0, 100])    // 数据范围, 会平均分成三部分对应range的三个值
    .range(['red', 'white', 'green']) // 映射范围

console.log(quantizeScale(22))     // red
console.log(quantizeScale(50))    // white
console.log(quantizeScale(88))   // green

console.log(quantizeScale.invertExtent('white'))
// [33.333333336, 66.666667] , 从颜色倒推回数值范围

d3.shuffle - 数组随机排序

const data = [10, 20, 40, 70, 50, 30, 90, 120, 5, 65, 75];
d3.shuffle(data)  // [40, 20, 120, 70, 10, 50, 5, 30, 75, 90, 65]

重新排序

筛选selection.filter

.on('mouseover', function (d, i, elements) {
      d3.select(this).style('transform', 'scaleX(2)');
      d3.selectAll(elements)
        .filter(':not(:hover)')
        .style('fill-opacity', 0.5);
    })
  1. selection.filter - 基于数据过滤元素

画一个X轴

var margin = { top: 10, right: 20, bottom: 60, left: 40 };
var width = 425 - margin.left - margin.right;
var height = 625 - margin.top - margin.bottom;

var svg = d3.select('.chart')
  .append('svg')
    .attr('width', width + margin.left + margin.right)
    .attr('height', height + margin.top + margin.bottom)


var xScale = d3.scaleTime()
  .domain([new Date(2016, 0, 1, 6), new Date(2016, 0, 1, 12)])
  .range([0, width]);
var xAxis = d3.axisBottom(xScale).ticks(5);

image

将属性设置独立成方法

bar.append('rect')
    .style('width', d => d.score)
    .attr('class', 'bar')
    .on('mouseover', function (d, i, elements) {
      d3.select(this).style('transform', 'scaleX(2)');
      d3.selectAll(elements)
        .filter(':not(:hover)')
        .style('fill-opacity', 0.5);
    })
    .on('mouseout', function (d, i, elements) {
      d3.select(this).style('transform', 'scaleX(1)');
      d3.selectAll(elements)
        .style('fill-opacity', 1);
    });

变成

function scaleBar (selection, scale) {
  selection.style('transform', 'scaleX(' + scale + ')');
}

function setFill (selection, color) {
  selection.style('fill', color);
}

function fade (selection, opacity) {
  selection.style('fill-opacity', opacity);
}

bar.append('rect')
    .style('width', d => d.score)
    .attr('class', 'bar')
.on('mouseover', function (d, i, elements) {
      d3.select(this)
        .call(scaleBar, 2)
        .call(setFill, 'orange');

      d3.selectAll(elements)
        .filter(':not(:hover)')
        .call(fade, 0.5);
    })
  1. call方法可将一个函数的对象上下文从初始的上下文改变为由参数指定的新对象

画一个柱状图

var margin = { top: 10, right: 20, bottom: 60, left: 30 };
var width = 400 - margin.left - margin.right;
var height = 565 - margin.top - margin.bottom;

var svg = d3.select('.chart')
  .append('svg')
    .attr('width', width + margin.left + margin.right)
    .attr('height', height + margin.top + margin.bottom)
  .append('g')
    .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');

var data = [
  {score: 63, subject: 'Mathematics'},
  {score: 82, subject: 'Geography'},
  {score: 74, subject: 'Spelling'},
  {score: 97, subject: 'Reading'},
  {score: 52, subject: 'Science'},
  {score: 74, subject: 'Chemistry'},
  {score: 97, subject: 'Physics'},
  {score: 52, subject: 'ASL'}
];

// y轴
var yScale = d3.scaleLinear()
  .domain([0, 100])
  .range([height, 0]);
var yAxis = d3.axisLeft(yScale);
svg.call(yAxis);

// x轴, scaleBand创建序数段比例尺
var xScale = d3.scaleBand()
  .padding(0.2)
  .domain(data.map(d => d.subject))
  .range([0, width]);

var xAxis = d3.axisBottom(xScale)
  .ticks(5)
  .tickSize(10)
  .tickPadding(5);

// 调整刻度文字
svg
  .append('g')
    .attr('transform', `translate(0, ${height})`)
  .call(xAxis)
  .selectAll('text')
  .style('text-anchor', 'end')
  .attr('transform', 'rotate(-45) translate(-10, -10)');

svg.selectAll('rect')
  .data(data)
  .enter()
  .append('rect')
  .attr('x', d => xScale(d.subject))
  .attr('y', d => yScale(d.score))
  .attr('width', d => xScale.bandwidth())  // bandwidth获取每段宽度
  .attr('height', d => height - yScale(d.score));
  1. scaleBand创建序数段比例尺
  2. .attr('transform', 'rotate(-45) translate(-10, -10)'); 多个变幻函数写一起

image

关于svg中的viewBox / preserveAspectRatio

  1. viewBox="x, y, width, height" // x:左上角横坐标,y:左上角纵坐标,width:宽度,height:高度

  2. viewBox的放大效果就相当于从左上角x, y的位置圈定一块width,height的范围然后将之放大到整块svg

  3. preserveAspectRatio 此属性也是应用在svg元素上,且作用的对象都是viewBox,第1个值表示,
    viewBox如何与SVG viewport对齐;第2个值表示,如何维持高宽比(如果有

参考资料:理解SVG viewport,viewBox,preserveAspectRatio缩放

各柱状图的案例特点

  1. 最简单的柱状图,矩形颜色随高度渐变
  2. 基本的柱状图,有XY轴,有Y轴贯穿线
  3. 基本柱状图,有Y轴文本,初始化动画效果
  4. 每过2s重置数据,有动画效果,每个矩形都有对应文字
  5. 鼠标滑过,有tips效果
  6. 同5
  7. 带筛选按钮,可重置数据
  8. 鼠标滑过,有tips效果
  9. 有柱状图折线图,有初始化加载效果,有tips

时间线性比例尺 d3.scaleTime()

var timeScale = d3.scaleTime()
   .domain([new Date(2016,0,1), new Date()])    // 数据范围
   .range([0, 100])                                                // 映射范围

console.log(timeScale(new Date(2016, 0, 15)))   // 6.348066...
console.log(timeScale(new Date(2016, 3, 15)))   // 47.594155...
console.log(timeScale(new Date(new Date())))   // 100.000031...

console.log(timeScale.invert(50))// Wed Apr 20 2016 07:19:59 , 从数字倒推回时间

关于过渡动画.transition

// 2. 添加柱状图容器g
  const chart = svg.append('g')
    .attr('transform', `translate(${margin.left}, -${margin.bottom})`)
    .selectAll('rect').data(chartdata)
    .enter().append('rect')
    .attr('width', xScale.bandwidth())
    .attr('x', (data, i) => xScale(i))
    // Starting position prior to transition
    .attr('height', 0)
    .attr('y', height)
    
 chart.transition()
    .attr('height', yScale)
    .attr('y', data => height - yScale(data))
    .delay((data, i) => i * 20)
    .duration(650)
    .ease(d3.easeSinIn);

画两个Y轴

两个Y轴

var margin = { top: 10, right: 20, bottom: 60, left: 40 };
var width = 425 - margin.left - margin.right;
var height = 625 - margin.top - margin.bottom;

var svg = d3.select('.chart')
  .append('svg')
    .attr('width', width + margin.left + margin.right)
    .attr('height', height + margin.top + margin.bottom)

// 左边轴的容器g
var leftG = svg.append('g')
                .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');

var yScale = d3.scaleLinear()
  .domain([0, 100])
  .range([height, 0]);
var yAxis = d3.axisLeft(yScale).tickValues([0, 8, 19, 43, 77, 100]);
leftG.call(yAxis);

// 右边轴的容器g
var rightG = svg.append('g').attr('transform', `translate(${300}, ${margin.top})`);

var yScale2 = d3.scaleLinear()
  .domain([0, 100])
  .range([height, 0]);
var yAxis2 = d3.axisLeft(yScale2);
rightG.call(yAxis2);
  1. 注意axisLeft和axisRight的意思不是画左边的Y轴和画右边的Y轴,而是指刻度出现在轴的左边还是右边

image

关于方法d3.range()

d3.range(0,7) // [0,1,2,3,4,5,6]
d3.range(-3, 7)  // [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6]

动画相关

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Egghead D3 v4</title>
  <script src="//d3js.org/d3.v4.min.js"></script>
  <style>
    #block {
      background: lightgray;
      border: 1px solid black;
      width: 100px;
      height: 100px;
    }
  </style>
</head>
<body>

  <div id="block"></div>

  <script src="src/app.js"></script>
</body>
</html>
d3.select('#block')
  .transition()
    .duration(600)
    .delay(750)
    .ease(d3.easeBounceOut)
    .style('width', '400px')
  .transition()
    .duration(600)
    .ease(d3.easeBounceOut)
    .style('height', '600px')
  .transition()
    .duration(2000)
    .ease(d3.easeQuadOut)
    .style('background-color', 'purple')

创建有文字的柱子(g / text)

var scores = [
  { name: 'Alice', score: 96 },
  { name: 'Billy', score: 83 },
  { name: 'Cindy', score: 91 },
  { name: 'David', score: 96 },
  { name: 'Emily', score: 88 }
];

var bar = d3.select('.chart')
  .append('svg')
    .attr('width', 225)
    .attr('height', 300)
  .selectAll('g')
  .data(scores)
  .enter()
    .append('g')
    .attr('transform', (d, i) => 'translate(0, ' + i * 33 + ')');

bar.append('rect')
    .style('width', d => d.score)
    .attr('class', 'bar');

bar.append('text')
  .attr('y', 20)
  .text(function (d) {
    return d.name;
  });

注意:

  1. 元素g是用来组合对象的容器。添加到g元素上的变换会应用到其所有的子元素上。添加到g元素的属性会被其所有的子元素继承。此外,g元素也可以用来定义复杂的对象
  2. g元素没有x,y属性,所以如果要移动g属性通过transform
  3. 显示文字需要添加text属性,这个是svg中的一个属性

关于d3.event

 .on('mouseover', data => {
      const { target } = d3.event;
      dynamicColor = d3.color(target.style.fill);
      d3.select(target).style('fill', dynamicColor.brighter(1.5))
    })

选中鼠标mouseover的元素将其颜色改变

.on("mouseover", function(d) {
        div.transition()
          .duration(200)
          .style("opacity", .9);
        div.html(formatTime(d[0]) + "<br/>" + "$" + d[1] + " Billion")
          .style("left", (d3.event.pageX) - 20 + "px")
          .style("top", (d3.event.pageY - 60) + "px");
      })

通过d3.event获取到鼠标的x,y距离

比例尺d3.scaleLinear()

var linearScale = d3.scaleLinear()  // 比例尺
   .domian([0, 100])                          // 数据的边界范围
   .range([0,600])                             // 映射后的数据范围
   .clamp(true)                                  // 启用闭合(如果超出数据的边界范围)

console.log(linearScale(-20))     // 0 , clamp生效
console.log(linearScale(50))      // 300
console.log(linearScale(105))    // 600, clamp生效
console.log(linearScale.invert(300))  // 50, 反转,根据映射倒推出原数据的数值

两种确定y轴domian范围的方法

var data = [
    { value: 99, label: 'Mon' },
    { value: 63, label: 'Tues' },
    { value: 41, label: 'Wed' },
    { value: 100, label: 'Thur' },
    { value: 50, label: 'Fri' },
    { value: 23, label: 'Sat' },
    { value: 8, label: 'Sun' }
  ];

 var yScale = d3.scaleLinear()
     .domain([0, d3.max(data, d => d.value)])          // 第一种方法  
    .domain (d3.extent(data, d => d.value))             // 第二种方法
    .range([0, 400]);

参考资料:d3-array / extent / max

viewBox的缩放,随浏览器尺寸缩放

var margin = { top: 10, right: 20, bottom: 30, left: 30 };
var width = 400 - margin.left - margin.right;
var height = 600 - margin.top - margin.bottom;

var svg = d3.select('.chart')
  .append('svg')
    .attr('width', width + margin.left + margin.right)
    .attr('height', height + margin.top + margin.bottom)
    .call(responsivefy)
  .append('g')
    .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');


var yScale = d3.scaleLinear()
  .domain([0, 100])
  .range([height, 0]);
var yAxis = d3.axisLeft(yScale);
svg.call(yAxis);

var xScale = d3.scaleTime()
  .domain([new Date(2016, 0, 1, 6), new Date(2016, 0, 1, 9)])
  .range([0, width]);

var xAxis = d3.axisBottom(xScale)
  .ticks(5)
  .tickSize(10)
  .tickPadding(5);
svg
  .append('g')
    .attr('transform', `translate(0, ${height})`)
  .call(xAxis);

function responsivefy(svg) {
  // get container + svg aspect ratio
  var container = d3.select(svg.node().parentNode),
      width = parseInt(svg.style("width")),
      height = parseInt(svg.style("height")),
      aspect = width / height;

  // add viewBox and preserveAspectRatio properties,
  // and call resize so that svg resizes on inital page load
  svg.attr("viewBox", "0 0 " + width + " " + height)
      .attr("preserveAspectRatio", "xMinYMid")
      .call(resize);

  // to register multiple listeners for same event type,
  // you need to add namespace, i.e., 'click.foo'
  // necessary if you call invoke this function for multiple svgs
  // api docs: https://github.com/mbostock/d3/wiki/Selections#on
  d3.select(window).on("resize" , resize);

  // get width of container and resize svg to fit it
  function resize() {
      var targetWidth = parseInt(container.style("width"));
      svg.attr("width", targetWidth);
      svg.attr("height", Math.round(targetWidth / aspect));
  }
}

选择器相关 d3.select / d3.selectAll / selection.nodes

<div class="title">
    <a href="#">About</a>
    <a href="#">Products</a>
    <a href="#">Contact</a>
  </div>
var div = d3.select('div');
console.log(div.nodes());    //打印dom节点

var divLinks = div.selectAll('a');
console.log(divLinks.nodes());  // 同上

var secondLink = d3.selectAll('a:nth-child(2)');  //同css
console.log(secondLink.nodes());

var allLinks = d3.selectAll(document.links);
console.log(allLinks.size());

创建简单的柱子

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Egghead D3 v4</title>
  <script src="//d3js.org/d3.v4.min.js"></script>
  <style>
    .chart {
      background: lightgray;
      border: 1px solid black;
      min-width: 200px;
      min-height: 350px;
    }
    .bar {
      height: 30px;
      color: green;
      fill: lightgreen;
      stroke: black;
      stroke-width: 1;
    }
  </style>
</head>
<body>

  <div class="chart"></div>

  <script src="src/app.js"></script>
</body>
</html>
var scores = [
  { name: 'Alice', score: 96 },
  { name: 'Billy', score: 83 },
  { name: 'Cindy', score: 91 },
  { name: 'David', score: 96 },
  { name: 'Emily', score: 88 }
];

d3.select('.chart')
  .append('svg')          // 添加svg, 并设置宽高
    .attr('width', 225)
    .attr('height', 300)
  .selectAll('rect')   // 选择矩形元素
  .data(scores)      // 数据填充
  .enter()                
    .append('rect')
    .attr('y', (d, i) => i * 33)          // 每个矩形距离原点的竖直距离
    .style('width', d => d.score)  
    .text(function (d) {                // 但是文字没有显示出来
      return d.name; 
    })
    .attr('class', 'bar');  

画一个左Y轴

var margin = { top: 10, right: 20, bottom: 60, left: 40 };
var width = 425 - margin.left - margin.right;
var height = 625 - margin.top - margin.bottom;

var svg = d3.select('.chart')
  .append('svg')
    .attr('width', width + margin.left + margin.right)
    .attr('height', height + margin.top + margin.bottom)
  .append('g')
    .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');

svg.append('rect')
  .attr('width', width)
  .attr('height', height)
  .style('fill', 'lightblue')
  .style('stroke', 'green');

var yScale = d3.scaleLinear()
  .domain([0, 100])
  .range([height, 0]);
var yAxis = d3.axisLeft(yScale);
svg.call(yAxis);

dingtalk20170720100913

创建一个序数比例尺 d3.scaleOrdinal

var ordinalScale = d3.scaleOrdinal()
    .domain(['poor', 'good', 'great'])    // 数据范围, 会平均分成三部分对应range的三个值
    .range(['red', 'white', 'green']) // 映射范围

console.log(ordinalScale('good'))     // white
console.log(ordinalScale('great'))    // green
console.log(ordinalScale('poor'))   // red

选择器 selection.data / selection.enter / selection.exit / d3.merge

selection.data - 元素和数据绑定
d3.merge - 将多个数组合并成一个
selection.enter - 获得进入(enter)选择器(数据无元素)
selection.exit - 获得退出(exit)选择器(元素无数据)

  <div class="chart">
    <div>Billy</div>
    <div>Cindy</div>
    <div>Walter</div>
  </div>
var scores = [
  { name: 'Alice', score: 96 },
  { name: 'Billy', score: 83 },
  { name: 'Cindy', score: 91 },
  { name: 'David', score: 96 },
  { name: 'Emily', score: 88 }
];

var update = d3.select('.chart')
  .selectAll('div')
  .data(scores, function (d) {
    return d ? d.name : this.innerText;
  })
  .style('color', 'blue');  // 已存在的三个div文字变蓝色(有一个后面删了)

var enter = update.enter()
  .append('div')
  .text(function (d) {
    return d.name;
  })
  .style('color', 'green');  // 选出enter部分(有数据无div)然后改变文字为绿色

update.exit().remove();  // 将Walter删除了,暂时不知道为什么

update.merge(enter)   // merge后返回新数组(即存在的加上添加的)
  .style('width', d => d.score + 'px')
  .style('height', '50px')
  .style('background', 'lightgreen')
  .style('border', '1px solid black')

属性设置相关 d3.attr / d3.classed / d3.text / d3.html

<div class="title">
    <a href="#">About</a>
    <a href="#">Products</a>
    <a href="#">Contact</a>
  </div>
d3.selectAll('a:nth-child(2)')
  .attr('href', 'http://google.com')
  .classed('red', true)
  .html('Inventory <b>SALE</b>');

selection.attr - 设置或获取特性。
selection.classed - 获取,添加或移除CSS类。
selection.style - 设置或获取样式。
selection.property - 设置或获取行内属性。
selection.text - 设置或获取文本内容。
selection.html - 设置或获取inner HTML。
selection.append - 创建,添加或选择新的元素。
selection.remove - 移除文档中的元素。
selection.sort - 基于数据给文档中的元素排序。
selection.order - 重排列文档中的元素以匹配选择中的顺序。
selection.raise - 重新排列每个元素为父元素的最后一个子节点。
selection.lower - 重新排列每个元素为父元素的第一个子节点。
d3.creator - 通过名称创建元素

参考资料:d3

d3读取json / csv / tsv数据

// 读json数据
d3.json('data/data.json', function (data) {
  console.log(data)
})

// 读csv数据
d3.csv('data/data.json', function (data) {
  console.log(data)
})

// 读tsv数据
d3.json('data/data.tsv', function (data) {
  console.log(data)
})

备注:csv和tsv打印来的data会多columns数组,保存的是数据项

绑定事件dispatch.on

var scores = [
  { name: 'Alice', score: 96 },
  { name: 'Billy', score: 83 },
  { name: 'Cindy', score: 91 },
  { name: 'David', score: 96 },
  { name: 'Emily', score: 88 }
];

var bar = d3.select('.chart')
  .append('svg')
  .attr('width', 225)
  .attr('height', 300)
  .selectAll('g')
  .data(scores)
  .enter()
  .append('g')
  .attr('transform', (d, i) => 'translate(0, ' + i * 33 + ')');

bar.append('rect')
    .style('width', d => d.score)
    .attr('class', 'bar')
    .on('mouseover', function (d, i, elements) {
      d3.select(this).style('transform', 'scaleX(2)');
      d3.selectAll(elements)
        .filter(':not(:hover)')
        .style('fill-opacity', 0.5);
    })
    .on('mouseout', function (d, i, elements) {
      d3.select(this).style('transform', 'scaleX(1)');
      d3.selectAll(elements)
        .style('fill-opacity', 1);
    });

bar.append('text')
  .attr('y', 20)
  .text(function (d) {
    return d.name;
  });
  1. dispatch.on - 注册或者解除注册事件监听器
  2. 注意事件绑定的时候如果会针对每一个元素则不要用箭头函数,使用原生function
  3. 获取每一个元素的方式d3.select(this)
  4. function(d, i, elements) 分别带别data, index,和所有dom元素

d3.set

d3.json('data/data.json', function (data) {
  var extent = d3.extent(data, function (d) {
    return d.age;
  });
  console.log(extent);  // [13.38]

  var scale = d3.scaleLinear()
    .domain(extent)
    .range([0, 600]);
  console.log(scale(37));  // 576

  var ages = d3.set(data, function (d) {
    return d.age;
  });
  console.log(ages.values());  // [23, 38, 13, 37]
})
// data.json
[
  {
    "age": 23,
    "name": "Welch"
  },
  {
    "age": 38,
    "name": "Villarreal"
  },
  {
    "age": 13,
    "name": "Sheryl"
  },
  {
    "age": 37,
    "name": "Marshall"
  },
  {
    "age": 37,
    "name": "Aimee"
  }
]

d3.set类似ES6 Set,但是键时字符类型的,并且有点其他区别
set.values - 获取值数组
参考资料:d3.set

距离大小设置,画布的大小,g的大小等

var margin = { top: 10, right: 20, bottom: 25, left: 25 };

var svgWidth = 425;
var svgHeight = 625;
var width = 425 - margin.left - margin.right;
var height = 625 - margin.top - margin.bottom;

var svg = d3.select('.chart')
  .append('svg')
    .attr('width', svgWidth)
    .attr('height', svgHeight)
  .append('g')
    .attr('transform', `translate(${margin.left}, ${margin.top})`);

svg.append('rect')
  .attr('width', width / 2)
  .attr('height', height)
  .style('fill', 'lightblue')
  .style('stroke', 'green');

svg.append('rect')
  .attr('x', width / 2)
  .attr('width', width / 2)
  .attr('height', height)
  .style('fill', 'lightblue')
  .style('stroke', 'green');

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.