Write in front:

  1. This article is a simple personal learning summary and class notes arrangement. Most of the knowledge points come from the online live courses of “Kaikaiba” and official materials.
  2. As it is still in the front-end learning and entry stage, it is inevitable that there will be deviations in the mastery and understanding of knowledge. Therefore, this article is only a personal record, and please do not use it as a basis for information.

D3 Basics 03 – Scale and axes

We can use the scale, axes, and plotting capabilities provided by D3 to achieve a simple bar chart. Adding mouse events, transition animations, and slow animations to optimize the bar chart user experience. Let’s take a step-by-step look at how to implement the bar chart.

scale

The scale function of D3 allows us to set up a coordinate system freely, set the component size of each coordinate axis, and make the scale of the coordinate axis correspond to the pixels of the canvas coordinate axis.

The scale of the coordinate axis can be divided into two kinds:

  • Category type axes: Axes are composed of discrete elements, such as[Zhang SAN, Li Si, Wang Wu]
  • Numerical axis: The coordinate axis consists of consecutive numbers, such as[0]This is an array, not a mathematical interval, and it needs to be distinguished. All subsequent pairs of values in brackets are arrays.

Therefore, there are two corresponding scale rules:

  • scaleBandCategory axial type scale rules
  • scaleLinearNumerical axial scale rules

Use the scale to establish the X axis

  • The X-axis is the category coordinate axis
  • The first step is to get the length of the X-axis data and store an index of each data
  • Then set the pixel positions for the start and end of the X-axis
  • Scale is then used to correspond the data to the scale of the coordinate axes
  • The x – axis coordinate generator is established based on x – axis scale
  • Call the generator to draw the X-axis and populate it with data.

Without further ado, let’s talk in code:

/*===========1- Required data ===========*/
/* Categories data */
const categories = ['html'.'css'.'js'];

/*===========2- Create the container object ===========*/
/* Get the main container */
const main = d3.select('#main')

/* Declare drawing box size width, 600 height, 600 */
const width = 600
const height = 600

/* Create SVG object * SVG canvas size 100% fill container object * Drawing frame size set to 600 * */
const svg = main.append('svg')
    .attr('version'.1.2)
    .attr('xmlns'.'http://www.w3.org/2000/svg')
    .attr('width'.'100%')
    .attr('height'.'100%')
    .attr('viewBox'.` 0 0${width} ${height}`)

/*===========3- Create the base data ===========*/
/* Count the number of categories len*/
const len = categories.length

/* use range() to get the X-axis xChartData in the charting coordinate system based on the number of categories, such as [0,1,2]*/
const xChartData = d3.range(len)
console.log('xChartData', xChartData);

/* The starting and ending points of the X-axis in the pixel coordinates are xPixelRange, offset by 50*/
const xPixelRange = [50, width - 50]

/*===========4- Create x scale xScale===========*/
/* * scaleBand() : xScale * Domain () : xChartData * rangeRound() : rangeRound() : That is, the start and end bits of the pixel xPixelRange * */
const xScale = d3.scaleBand()
    .domain(xChartData)
    .rangeRound(xPixelRange)
console.log('xScale', xScale)
/*===========5- Create an X-axis object ===========*/
/* Create a scale-down axis generator xAxisGenerator*/ using the axisBottom() method based on the scale xScale
const xAxisGenerator = d3.axisBottom(xScale)

/* Draw the axis with the axis generator * add the G object to the SVG append * Set the y position of the x axis with the transform attribute translate * call the xAxisGenerator axis generator with the call() method, Generate axes * selectAll text text with selectAll() * set chart data to category data with text() * set font size with attr() * */
svg.append('g')
    .attr('transform'.`translate(0,${height-50}) `)
    .call(xAxisGenerator)
    .selectAll('text')
    .text(d= > categories[d])
    .style('font-size'.'12px')
Copy the code

Use the scale to establish the Y-axis

Although the Y-axis is numerical, the overall idea is the same as that of the X-axis. The only point that needs to be noted is that the Y-axis direction of the pixel coordinate axis is opposite to the direction of the Y-axis we drew. Therefore, attention should be paid to the corresponding relationship when establishing the scale.

/*===========1- Required data ===========*/
/* Data source: two series of data */
const source = [
    //html css js
    [30.20.40].// The number of students
    [40.30.50] // Employment number
]

/*===========1- Create the container object ===========*/
/* Get the main container */
const main = d3.select('#main')

/* Declare drawing box size width, 600 height, 600 */
const width = 600
const height = 600

/* Create SVG object * SVG canvas size 100% fill container object * Drawing frame size set to 600 * */
const svg = main.append('svg')
    .attr('version'.1.2)
    .attr('xmlns'.'http://www.w3.org/2000/svg')
    .attr('width'.'100%')
    .attr('height'.'100%')
    .attr('viewBox'.` 0 0${width} ${height}`)

/*===========3- Create the base data ===========*/
/* Calculate the extreme value of all data in the data source maxY * expand the data source with JS native method flat(), and then use Max () method to get the extreme value * */
const maxY = Math.max(... source.flat())console.log('maxY', maxY);

/* Declare the starting and ending points of the Y-axis in the charting coordinate system yChartRange*/
const yChartRange = [0, maxY]

/* Declare the starting and ending points of the Y-axis data in the pixel coordinate system yPixelRange*/
const yPixelRange = [height - 50.50]

/*===========4- Create y-scale yScale===========*/
YScale scaleLinear(); yChartRange (); yChartRange (); That is, the start and end bits of the pixel, yPixelRange * */
const yScale = d3.scaleLinear()
    .domain(yChartRange)
    .range(yPixelRange)

/*===========5- Create the Y-axis object ===========*/
/* Create a left-graduated axis generator yAxisGenerator*/ using the axisLeft() method based on the scale yScale
const yAxisGenerator = d3.axisLeft(yScale)

/* Generate axis with axis generator * add g object to SVG append * set y axis x position with transform property translate * call xAxisGenerator axis generator with call() method, Generate the axes * set the font size with the style() method * */
svg.append('g')
    .attr('transform'.'translate(50 0)')
    .call(yAxisGenerator)
    .style('font-size'.'12px')
Copy the code

Draw diagrams

Now that we have successfully established the coordinate system, there is only one step to success: drawing.

  • Initialize drawing data
    • Get the pixel width of each class on the X-axis (HTML, CSS, JS)
    • Get the length of the series (employed, studying)
    • Divide the two to get the X-axis pixel width occupied by each series under each class.
  • Building a drawing areagJust frame the drawing area, no graphics have been drawn at this point
    • Create a collection of drawing areas and bind category data to each collection
    • Settings will be filled in togThe starting pixel position of the X-axis coordinates of each cylinder in
    • Set the fill color
  • Building a collection of rectanglesrect— Creates the cylinder collection and object, but does not set the properties
    • Create the cylinder collection and bind the series of data to each collection
    • At the end of eachgBatch wear within elementsrectThe element
  • Sets the properties of each cylinder
/*===========6- Create basic data related to the drawing area ===========*/
/*----- Basic data related to the plot area -----*/
/* Get a class pixel width xBandW*/ from xScale's bandwidth()
const xBandW = xScale.bandwidth()
console.log('xBandW', xBandW);
/* Get the number of series n*/
const n = source.length

/* Divide the category width by the number of series to get the width of each series element in a category. ColW */
const colW = xBandW / n
console.log('colW', colW);

/* Count the number of colors in the palette colorLen*/
const colorLen = color.length

/*===========7- Architecture drawing area ===========*/
/* create seriesObjs in SVG, create seriesObjs in SVG * add g object to append in SVG * selectAll() selectAll g elements. Instead, create a selection set object * bind the data source with the series of information to the series with the data() method * use join() to batch create g elements based on the data sources, one G represents a series, Each G element is then filled with three columns of a different class. * Set the series x pixel position using the Transform attribute Translate -- the column width multiplied by the series index * Based on the series index, take the color from the palette and use it as the fill color for all shapes in the series * */
const seriesObjs = svg.append('g')
    .selectAll('g')
    .data(source)
    .join('g')
    .attr('transform'.(seriesData, seriesInd) = > {
        const seriesX = colW * seriesInd
        return `translate(${seriesX}`, 0)
    })
    .attr('fill'.(seriesData, seriesInd) = > color[seriesInd % colorLen])

/* selectAll rect elements with seriesObjs selectAll(), Use to create selection set objects * bind data previously bound in each collection to the cylinder collection using the data() method * batch create rect elements based on each collection of data using join() * add item attributes to them using classed() method * */
const rects = seriesObjs.selectAll('rect')
    .data(seriesData= > seriesData)
    .join('rect')
    .classed('item'.true)

console.log('rects', rects);
/*=8- Use attr() to set the x, y positions and width, height dimensions of each cylinder =*/
/* * Set the column's x pixel level * From the callback parameter to get the column's index in the current series rectInd, seriesInd * Based on the column's index in the current series rectInd, * Set column width to column width colW * Set column y pixel * Deconstruct column data from callback parameters * rectData based on column data rectData, RectData * rectData is deconstructed from the callback parameter. RectData * rectData is the height of the column * */ by subtracting the number of pixels calibrated to the actual data on the column from the 0 scale on the y axis
rects.attr('x'.(rectData, rectInd) = > xScale(rectInd))
    .attr('width', colW)
    .attr('y'.rectData= > yScale(rectData))
    .attr('height'.rectData= > yScale(0) - yScale(rectData))
Copy the code

At this point, you’ve created an intuitive bar chart. You can also add transition animations, slow animations, and mouse events to make this bar chart a better and cooler user experience (save that for when you get back from your business trip).