предисловие
Наконец-то снова выходные, 3D-статья с прошлой неделиПерейдите к three.js - от 0 до 1, чтобы получить трехмерную визуальную картуЯ очень счастлив 😺 Я получил так много лайков от моих друзей, что является подтверждением моих знаний. Еще раз всем спасибо! Я снова здесь на этой неделе, и на этот раз я поделюсь с вами простой диаграммой для визуализации диаграмм📈 Но в то же время, что мы должны узнать, это————линейный график. Что вы узнаете после прочтения этой статьи
- js реализует уравнение прямой линии
- Выражение линейной диаграммы
- Гибкое использование некоторых API холста
Линейный график
Давайте посмотрим на очень известный официальный сайт Echarts, как выглядит его линейный график? Как показано на рисунке:
Следующие 2d графические элементы могут быть получены из рисунка:
- Прямая линия (две конечные точки - круги)
- Прямая линия (две конечные точки прямые)
- Слово
Вроде и нечего тщательно анализировать, по сути, это рисовать прямые линии и добавлять текст. Хорошо, спросите себя, как рисовать прямые линии на холсте? Есть ли метод ctx.LineTo, но он рисует прямую линию без концов? Мы инкапсулируем на этой основе, и графика концов прямой линии является управляемой, и при этом текст находится в положении прямой линии.Можем ли мы нарисовать такую графику? Далее переходим к практической части.
Создание полотна
Первым шагом, безусловно, является создание холста, здесь особо не о чем говорить. Здесь я создаю новый холст в html, я создаю новый класс с именемlineChartПерейдите непосредственно к коду:
class lineChart {
constructor(data, type) {
this.get2d()
}
get2d() {
const canvas = document.getElementById('canvas')
this.ctx = canvas.getContext('2d')
}
}
Приведенный выше код ни о чем не говорит, а затем я устанавливаю цвет фона для холста. код показывает, как показано ниже:
<style>
* {
padding: 0;
margin: 0;
}
canvas {
background: aquamarine;
}
</style>
Обзор операции рисования холста
На самом деле линейная диаграмма представляет собой прямую линию, но в исходную возможность рисования прямых линий были внесены некоторые улучшения. Я использую пример рисования треугольника: Позвольте вам ознакомиться с операцией рисования линии.
Первый взгляд на API:
Рисует линию от текущей позиции до указанных позиций x и y.
Линия обычно состоит из двух точек.Этот метод имеет два параметра: x и y, которые представляют собой точку в системе координат, где линия заканчивается. Начальная точка связана с предыдущим нарисованным путем, конечная точка предыдущего пути является следующей начальной точкой и так далее. . . Начальную точку также можно пройти черезmoveTo()
меняется функция.
moveTo — это то, что перемещает штрих на холсте, первую точку, которую вы начинаете рисовать, или вы можете представить себе работу на бумаге, когда кончик пера или карандаша перемещается из одной точки в другую.
moveTo(*x*, *y*)
Переместите штрих к указанным координатам x и y.
После введения, давайте начнем настоящий бой:
drawtriangle() {
this.ctx.moveTo(25, 25)
this.ctx.lineTo(105, 25)
this.ctx.lineTo(25, 105)
}
Сначала мы перемещаем точку, затем рисуем линию, а затем рисуем линию. Если вы пишете, пока не думаете, что все кончено, вы ошибаетесь
Вы все еще в очень важном шаге от обводки или заливки холста, я забуду об этом, когда впервые узнаю об этом..
Здесь я разберу для вас весь процесс рисования холста.
- Во-первых, вам нужно создать начальную точку пути.
- тогда вы используетекоманды рисованиянарисовать путь.
- После этого вы закрываете путь.
- После того, как путь сгенерирован, вы можете визуализировать форму, обводя или заполняя область пути.
То есть все, что мы только что сделали, это подготовили путь, поэтому нам нужноИнсультилизаполнениеЧтобы отобразить графику, давайте посмотрим на эти два API.
// 通过线条来绘制图形轮廓。
ctx.stroke()
// 通过填充路径的内容区域生成实心的图形。
ctx.fill()
Добавим отступ: посмотрите на эффект:
Давайте посмотрим на эффект обводки:
Вы найдете, почему он не закрыт? , код такой:
this.moveTo(25, 25)
this.lineTo(105, 25)
this.lineTo(25, 105)
this.stroke()
Что это говорит о важном вопросе?
Обводка не закрыта по умолчанию, нам нужно закрыть ее вручную Заливка поможет нам закрыть график по умолчанию, и заполнить
Теперь, когда мы нашли проблему, нам нужно ее решить, так как же холст закрывает путь? ?
closePath:
После закрытия пути команды рисования графики перенаправляются в контекст.
код показывает, как показано ниже:
this.moveTo(25, 25)
this.lineTo(105, 25)
this.lineTo(25, 105)
this.closePath()
this.stroke()
На данный момент вышли рендеры:
Есть ли близкий путь? Разве нет начального пути? Ответ конечно:
// 新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。
this.beginPath()
Что это здесь делает?
Первый Первый шаг в создании пути называется beginPath(). По сути, путь состоит из множества подпутей, каждый из которых находится в списке, и все подпути (линии, дуги и т. д.) составляют граф. И каждый раз, когда вызывается этот метод, список очищается и сбрасывается, после чего мы можем перерисовывать новый график.
Примечание. Когда текущий путь пуст, то есть после вызова beginPath() или когда холст только что построен, первая команда построения пути обычно обрабатывается как moveTo(), независимо от того, что это на самом деле. По этой причине вы почти всегда хотите конкретно указать свое начальное местоположение после установки пути.
closePath на самом деле не нужен.Если графика уже закрыта, то вызывать ее не нужно.Вот обзор основных операций рисования холста.Позже есть несколько практических API:поясню на примере, иначе это будет выглядеть очень несуразно.
Прямолинейный метод рисования пакетов
Ранее я снова использовал точку point2d для представления положения каждой точки на холсте и написал несколько методов. Я подробно рассказывал об этом в предыдущих статьях. Я не буду подробно описывать это здесь:Длинный текстовый холст на 3000 слов для реализации движения произвольных правильных многоугольников (точек, линий, поверхностей)эта статья. Здесь я помещаю код напрямую:
export class Point2d {
constructor(x, y) {
this.x = x || 0
this.y = y || 0
this.id = ++current
}
clone() {
return new Point2d(this.x, this.y)
}
equal(v) {
return this.x === v.x && this.y === v.y
}
add2Map() {
pointMap.push(this)
return this
}
add(v) {
this.x += v.x
this.y += v.y
return this
}
abs() {
return [Math.abs(this.x), Math.abs(this.y)]
}
sub(v) {
this.x -= v.x
this.y -= v.y
return this
}
equal(v) {
return this.x === v.x && this.y === v.y
}
rotate(center, angle) {
const c = Math.cos(angle),
s = Math.sin(angle)
const x = this.x - center.x
const y = this.y - center.y
this.x = x * c - y * s + center.x
this.y = x * s + y * c + center.y
return this
}
distance(p) {
const [x, y] = this.clone().sub(p).abs()
return x * x + y * y
}
distanceSq(p) {
const [x, y] = this.clone().sub(p).abs()
return Math.sqrt(x * x + y * y)
}
static random(width, height) {
return new Point2d(Math.random() * width, Math.random() * height)
}
cross(v) {
return this.x * v.y - this.y * v.x
}
}
Соответствует некоторым статическим методам, перекрестному произведению, расстоянию между двумя точками и так далее.
Сначала мы рисуем базовую линию на холсте. Сначала мы используем random, чтобы регенерировать две точки на холсте, а затем рисуем случайную линию. Код выглядит следующим образом:
new lineChart().drawLine(
Point2d.random(500, 500),
Point2d.random(500, 500)
)
// 画直线
drawLine(start, end) {
const { x: startX, y: startY } = start
const { x: endX, y: endY } = end
this.beginPath()
this.moveTo(startX, startY)
this.lineTo(endX, endY)
this.stroke()
}
js реализует уравнение прямой линии
这里没有好展示的,我们还是分析下echarts 官方的折线图直线,直线两旁是两个圆的,想一想?其实这边涉及到一个数学知识,各位小伙伴,Fly再一次化身数学老师给大家讲解,主要是帮有些小伙伴复习复习。 这里我们已经知道直线的开始点和结束点,在数学中我们可以确定一条直线方程,那么我们就可以求出直线上任意一点的(x,y)坐标。那么直线的两个端点的圆心我们就可以确定? 半径也可以确定了就是圆心分别到开始点和结束点的距离。
Шаг 1: Реализуйте уравнение линии
Давайте сначала рассмотрим несколько выражений уравнения прямой линии:
-
Общая формула:Ax+By+C=0(A и B не равны 0 одновременно) [применимо ко всем прямым линиям]
-
Наклон точки:у-у0=к(х-х0) [для линий, не перпендикулярных оси x】Представляет собой прямую линию с наклоном k, проходящую через (x0, y0)
-
Формула перехвата:x/a+y/b=1[Применимо к линиям, которые не находятся в начале координат или не перпендикулярны оси x и оси y]
-
Двухточечный тип: представляет собой прямую линию, проходящую через (x1, y1) и (x2, y2) [применяется к прямым линиям, которые не перпендикулярны оси x и оси y](х1≠х2, у1≠у2)
Вот очевидно, что мы подходят для четвертого: начальная точка и конечная точка прямой линии можно найти в линейном уравнении. Я даю следующий код:
export function computeLine(p0, p1, t) {
let x1 = p0.x
let y1 = p0.y
let x2 = p1.x
let y2 = p1.y
// 说明直线平行 y轴
if (x1 === x2) {
return new Point2d(x1, t)
}
// 平行X轴的情况
if (y1 === y2) {
return new Point2d(t, y1)
}
const y = ((t - x1) / (x2 - x1)) * (y2 - y1) + y1
return new Point2d(t, y)
}
p0, p1, соответствующие две точки прямой линии t являются параметрами, соответствующими x прямой линии, мы находим y и просто возвращаем новую точку. По умолчанию мы вычитаем или добавляем фиксированное значение из положения x начальной и конечной точек соответственно, чтобы найти центр круга. Просто посмотрите на картинку ниже:
Эта картина уже очень очевидна. Расстояние между 1 и 2 - это радиус, поэтому нам нужно только задать точки 1 и 4. Вроде бы все в порядке. Как нарисовать круг в холсте? Есть дуга api:
arc(x, y, radius, startAngle, endAngle, anticlockwise)
Нарисуйте дугу (окружность) с (x, y) в качестве центра и радиусом в качестве радиуса, начиная с startAngle и заканчивая endAngle, и сгенерируйте в соответствии с направлением, заданным против часовой стрелки (по умолчанию — по часовой стрелке).
Уведомление:
arc()
Единица измерения угла в функции — радианы, а не градусы. js выражения для углов и радианов:радианы = (Math.PI/180)*градусы.
Окружность должна быть от 0 до 360 градусов, код выглядит следующим образом:
drawCircle(center, radius = 4) {
const { x, y } = center
this.ctx.beginPath()
this.ctx.arc(x, y, radius, 0, Math.PI * 2, true) // 绘制
this.ctx.fill()
}
Все приготовления сделаны, приступаем к реализации прямой с окружностью. Шаги рисования
- сначала нарисуйте круг
- рисовать прямые линии
- нарисовать конечный круг
Рисование начального круга и рисование конечного круга на самом деле можно инкапсулировать в один метод: основное различие между ними заключается в разнице в начальной точке Код выглядит следующим образом:
drawLineCircle(start, end, type) {
const flag = type === 'left'
const { x: startX, y: startY } = start
const { x: endX, y: endY } = end
const center = this.getOnePointOnLine(
start.clone(),
end.clone(),
flag ? startX - this.distance : endX + this.distance
)
// 两点之间的距离 不熟悉的小伙伴可以看下上面的文章
const radius = (flag ? start : end).clone().distanceSq(center)
this.drawCircle(center, radius)
}
Таким образом, мы можем рисовать круги. Сначала посмотрите на диаграмму эффектов:
Здесь мы закончили первую часть линейного графика, а затем вошли во вторую часть:
Нарисовать ось XY
Оси координат представляют собой две прямые линии, поэтому первым шагом является определение начала координат, а затем проведение двух вертикальных и горизонтальных линий от начала координат. Мы устанавливаем начало координат из левого и нижнего отступов холста, чтобы мы могли получить y начала координат, вычитая нижний отступ из высоты холста, а затем получить x, вычитая левый отступ из ширины. холста нет большой проблемы в рисовании координатной оси с началом координат. код показывает, как показано ниже:
//定义坐标轴相对于画布的内边距
this.paddingLeft = 30 // 至少大于绘制文字的宽度
this.paddingBottom = 30 // 至少大于绘制文字的高度
this.origin = new Point2d(
this.paddingLeft,
this.height - this.paddingBottom
)
this.drawCircle(this.origin, 1, 'red')
this.addxAxis()
this.addyAxis()
// 画 x 轴
addxAxis() {
const end = this.origin
.clone()
.add(new Point2d(this.width - this.paddingLeft * 2, 0))
this.drawLine(this.origin, end)
}
// 画y轴
addyAxis() {
const end = this.origin
.clone()
.sub(new Point2d(0, this.height - this.paddingBottom * 2))
this.drawLine(this.origin, end)
}
Особое напоминание здесь заключается в том, что, прежде всего, ось координат всего холста находится в левом верхнем углу всего экрана, но начало координат, которые мы отображаем, находится в левом нижнем углу, а затем, когда ось Y рисуется, оно вычитается из начала координат, что является вычитанием векторных точек.
Схема эффекта выглядит следующим образом:
Но это не то же самое, что диаграммы, его ось X имеет сегменты линий и текст, а затем мы начинаем трансформировать ось X. Он состоит в том, чтобы разделить ось X на несколько сегментов.
然后生成一个点的集合,这些点的y都是相同的, 然后 x是不相同的。 код показывает, как показано ниже:
drawLineWithDiscrete(start, end, n = 5) {
// 由于 x 轴上的 y 都是相同的
const points = []
const startX = start.x
const endX = end.x
points.push(start)
const segmentValue = (endX - startX) / n
for (let i = 1; i <= n - 1; i++) {
points.push(new Point2d(startX + i * segmentValue, start.y))
}
points.push(end)
// 生成线段
points.forEach((point) => {
this.drawLine(point, point.clone().add(new Point2d(0, 5)))
})
}
Здесь следует обратить внимание на количество петель, потому что есть начальные и конечные точки. Взгляните на рендеры:
В это время еще есть текст, canvas api для рисования текста
在指定的(x,y)位置填充指定的文本,绘制的最大宽度是可选的.
ctx.fillText(text,x,y,[,maxwidth])
Грубо говоря, это все еще вычисление координат текстовых точек.Во-первых, определить данные оси X и оси Y в инициализации проекта. код показывает, как показано ниже:
this.axisData = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
this.yxisData = ['0', '50', '100', '150', '200', '250', '300']
Мы помещаем текст в середину отрезка, на самом деле нам нужно только вычислить длину номера каждого отрезка, а затем получить его в конечной точке + половина длины номера отрезка. код показывает, как показано ниже:
// 生成X轴文字的点
const segmentValue = (endX - startX) / n
for (let i = 0; i <= n - 1; i++) {
const textpoint = new Point2d(
startX + i * segmentValue + segmentValue / 2,
start.y + 20
)
// 这里每个点的文字与X轴数据是互相呼应的
textPoints.push({
point: textpoint,
text: this.axisData[i],
})
}
// 生成文字
this.clearFillColor()
textPoints.forEach((info) => {
const { text, point } = info
this.ctx.fillText(text, point.x, point.y)
})
Схема эффекта выглядит следующим образом:
Но глядя на картинку, кажется, что текст не по центру.Толстый Тигр задумался над этим некоторое время.На самом деле, поскольку текст тоже имеет длину, то координаты каждого текста надо вычесть на половину длины текста . На данный момент очень важен третий параметр this.ctx.fillText, для ограничения длины текста, чтобы мы могли с ним разобраться, код повторно модифицируется:
// 限制文字的长度
this.ctx.fillText(text, point.x, point.y, 20)
// 文字的每个点要减去长度的一半
const textpoint = new Point2d(
startX + i * segmentValue + segmentValue / 2 - 10,
start.y + 20
)
Смотрите прямо на рендеры:
Теперь это выглядит идеально.
Ось X была обработана, и мы будем иметь дело с осью Y. Ось Y на самом деле относительно проста, она представляет собой прямую линию, соответствующую всем данным.
Для оси Y также необходимо вычислить значение длины каждого отрезка линии, а затем провести прямую линию.Особое внимание следует уделить размещению текста и тонкой настройке в каждой конечной точке. Выравнивает текст и строки по центру. код показывает, как показано ниже:
addyAxis() {
const end = this.origin
.clone()
.sub(new Point2d(0, this.height - this.paddingBottom * 2))
const points = []
const length = this.origin.y - end.y
const segmentValue = length / this.yxisData.length
for (let i = 0; i < this.yxisData.length; i++) {
const point = new Point2d(end.x, this.origin.y - i * segmentValue)
points.push({
point,
text: this.yxisData[i],
})
}
points.forEach((info) => {
const { text, point } = info
const end = point
.clone()
.add(new Point2d(this.width - this.paddingLeft * 2, 0))
this.setStrokeColor('#E0E6F1')
this.drawLine(point, end)
this.clearStrokeColor()
this.ctx.fillText(text, point.clone().x - 30, point.y + 4, 20)
})
}
Поскольку процесс очень похож на ось X, напомню, что после установки обводки необходимо восстановить ее значение по умолчанию, иначе она будет ссылаться на предыдущий цвет.
Как показано на рисунке:
Весь холст — это почти последний шаг, создание линейной диаграммы, которую мы инкапсулировали выше, прямая линия с кругом, поэтому просто найдите все точки, чтобы нарисовать линейную диаграмму. Во-первых, нет проблем с координатой X каждой точки, которая соответствует каждомуСредняя точка, в основномКоординаты по оси Y: Вспомните, как мы привыкли вычислять координаты по оси Y, длину / деленную на количество сегментов для расчета.Это приводит к проблеме, результат может быть десятичным, потому что наши фактические данные могут быть 223, что приводит к слишком большой ошибке в нарисованных точках графика, поэтому, чтобы уменьшить ошибку, я меняю режим расчета, который должен разделить поровну, чтобы точки в интервале могли быть выражены, а ошибка могла быть немного меньше.На самом деле, в реальном проекте проблема толерантности - это проблема, которая должна существовать в расчете, и у самого js есть такие проблемы, как 0,1+0,2, т. е. или в допуске В диапазоне мы можем считать эти две точки эквивалентнымикод показывает, как показано ниже:
const length = this.origin.y - end.y
const division = length / 300
const point = new Point2d(end.x, this.origin.y - i * division * 50)
Затем я ввожу реальные данные в это время:
this.realData = [150, 230, 224, 218, 135, 147, 260]
this.xPoints = []
this.yPoints = []
В соответствии с реальными данными код координат средней точки текста xPoints выглядит следующим образом:
// 生成文字
this.clearFillColor()
textPoints.forEach((info) => {
const { text, point } = info
this.xPoints.push(point.x)
this.ctx.fillText(text, point.x, point.y, 20)
})
yPoints на самом деле относительно прост, реальные данные * расстояние каждой копии просто отлично.
const division = length / 300
for (let i = 0; i < this.yxisData.length; i++) {
const point = new Point2d(end.x, this.origin.y - i * division * 50)
// 在这里, 还是得注意坐标轴的位置
const realData = this.realData[i]
this.yPoints.push(this.origin.y - realData * division)
points.push({
point,
text: this.yxisData[i],
})
}
Когда данные готовы, начинаем вызывать метод для построения линейного графика:
let start = new Point2d(this.xPoints[0], this.yPoints[0])
// 生成折线图
this.setStrokeColor('#5370C6')
this.xPoints.slice(1).forEach((x, index) => {
const end = new Point2d(x, this.yPoints[index + 1])
this.drawLineWithCircle(start, end)
start = end
})
На что этот код должен обратить внимание, так это найти начальную точку по умолчанию, затем постоянно менять начальную точку, а затем обращать внимание на позицию нижнего индекса.
Как показано на рисунке:
существующие на данный момент проблемы:
- Существующие точки повторяются
- Радиус точек непостоянен, значит, мы рассчитали расстояние от центра круга до прямой линии, неправильно задавать радиус как радиус, потому что наклон каждой линии разный. Вот и получается, что есть проблема.
Здесь каждый может подумать так, зачем окружность и прямая должны быть связаны вместе, если ты не рисуешь ее одну, то такой проблемы нет. Просто сделай это,
let start = new Point2d(this.xPoints[0], this.yPoints[0])
this.drawCircle(start)
// 生成折线图
this.setStrokeColor('#5370C6')
this.xPoints.slice(1).forEach((x, index) => {
const end = new Point2d(x, this.yPoints[index + 1])
// 画圆
this.drawCircle(end)
// 画直线
this.drawLine(start, end)
start = end
})
Обратите внимание, что стартовой окружности будет на одну меньше, мы просто добавим ее непосредственно в начало, радиус окружности я задал равномерным.
Как показано на рисунке:
На данный момент эта линейная диаграмма полностью завершена, чтобы сделать ее более совершенной, я еще добавляю намеки и пунктирные линии.
показать всплывающую подсказку
Здесь я вижу, что на большинстве графиков будет отображаться пунктирная линия и подсказка при перемещении мыши, иначе как я могу очистить данные, верно? Мы по-прежнему инициализируем div и устанавливаем для него скрытый стиль.
#tooltip {
position: absolute;
z-index: 2;
background: white;
padding: 10px;
border-radius: 2px;
visibility: hidden;
}
<div id="tooltip"></div>
Добавьте события прослушивателя на холст:
canvas.addEventListener('mousemove', this.onMouseMove.bind(this))
// 这里取相对于画布原点的位置 offset
onMouseMove(e) {
const x = e.offsetX
const y = e.offsetY
}
На самом деле, то, что нам нужно сделать, очень просто. Прежде всего, мы должны сравнить точку мыши и реальную точку. Я буду отображать ее в определенном диапазоне. Как и в случае с адсорбцией, невозможно перейти туда полностью из точка зрения пользователя.
код показывает, как показано ниже:
onMouseMove(e) {
const x = e.offsetX
const find = this.xPoints.findIndex(
(item) => Math.abs(x - item) <= this.tolerance
)
if (find > -1) {
this.tooltip.textContent = `数据:${this.axisData[find]}_ ${this.yxisData[find]}`
this.tooltip.style.visibility = 'visible'
this.tooltip.style.left = e.clientX + 2 + 'px'
this.tooltip.style.top = e.clientY + 2 + 'px'
} else {
this.tooltip.style.visibility = 'hidden'
}
}
Фактически, до тех пор, пока сравнивается положение x, допуск можно настроить.
рисуем вертикальные пунктирные линии
Я видел много диаграмм, и все они имеют вертикальные пунктирные линии, вот вопрос о том, как холст рисует пунктирные линии, я вИспользуйте холст для реализации движения прямоугольников (точек, линий, поверхностей) (1)В этой статье есть введение, я возьму его прямо, но объясню больше Заинтересованные друзья могут прочитать эту статью. код показывает, как показано ниже:
drawDashLine(start, end) {
if (!start || !end) {
return
}
this.ctx.setLineDash([5, 10])
this.beginPath()
this.moveTo(start.x, start.y)
this.lineTo(end.x, end.y)
ctx.stroke()
}
Мы снова переделываем onMouseMove:
onMouseMove(e) {
const x = e.offsetX
const find = this.xPoints.findIndex(
(item) => Math.abs(x - item) <= this.tolerance
)
if (find > -1) {
this.tooltip.textContent = `数据:${this.axisData[find]}_ ${this.yxisData[find]}`
this.tooltip.style.visibility = 'visible'
this.tooltip.style.left = e.clientX + 2 + 'px'
this.tooltip.style.top = e.clientY + 2 + 'px'
// 画虚线
const start = new Point2d(this.xPoints[find], this.origin.y)
const end = new Point2d(this.xPoints[find], 0)
this.drawDashLine(start, end)
} else {
this.tooltip.style.visibility = 'hidden'
}
}
Добавлен следующий код, но с этим есть проблема, то есть наша мышь продолжает двигаться, поэтому пунктирная линия, нарисованная в прошлый раз, не будет отменена. Произойдет следующее:
Итак, я сделал очистку данных при очистке холста и перерисовке:
clearData() {
this.ctx.clearRect(0, 0, 600, 600)
this.xPoints = []
this.yPoints = []
}
Общий код выглядит следующим образом:
const start = new Point2d(this.xPoints[find], this.origin.y)
const end = new Point2d(this.xPoints[find], 0)
// 清除数据
this.clearData()
this.drawDashLine(start, end)
// 虚线样式也要每次清除 不然会影响下面的画的样式
this.ctx.setLineDash([])
this.addxAxis()
this.addyAxis()
this.setStrokeColor('#5370C6')
this.generateLineChart()
Магия восстановления и сохранения
Позвольте мне дать вам небольшую хитрость **, на самом деле, если рисунок на холсте работает только в определенном рисунке: есть методы сохранения и восстановления
использоватьsave()
метод для сохранения текущего состояния, используйтеrestore()
восстановить к началу
Таким образом, мы можем переписать метод рисования пунктирной линии, svae в начале, а затем закончить восстановлением, что немного похоже на стек, сначала войти, затем закончить рисование и всплыть. Каждый элемент имеет свое собственное уникальное состояние рисования, которое не влияет на другие элементы.
drawDashLine(start, end) {
if (!start || !end) {
return
}
this.ctx.save()
this.ctx.setLineDash([5, 10])
this.beginPath()
this.moveTo(start.x, start.y)
this.lineTo(end.x, end.y)
this.stroke()
this.ctx.restore()
}
На этом вся линейная диаграмма, которую я хочу вам объяснить, закончилась, давайте посмотрим на эффект:
наконец
Эта статья является первой для холста, в которой реализованы визуальные диаграммы. Позже я продолжу делиться различными визуальными диаграммами, круговыми диаграммами, древовидными диаграммами, диаграммами K-line и т. Д.
Пока пишу статью, постоянно думаю, как лучше выразить. Если вас интересует визуализация, ставьте лайк и подписывайтесь на 👍! , ты можешь следовать за мной
лицоСтолбец визуализации данных, делиться статьей в неделю либо в 2d, либо в three.js. Каждую статью я буду создавать с душой, а не по гидрологии.
Последнее слово: все, присоединяйтесь ко мне, чтобы стать создателем API, а не абонентом!
Загрузка исходного кода
Весь код для примеров в этой статье находится в моемgithubДобро пожаловать, звезда☆😯!