У меня следующая проблема: я хочу создать простую диаграмму, используя библиотеку d3 и визуализацию холста.

var width = 800;
var height = 600;

var data = [10, 15, 20, 25, 30];

var chart = d3.select("#chart")
            .append("canvas")
            .attr("width", width)
            .attr("height", height);

var scale = d3.scaleLinear()
              .domain([d3.min(data), d3.max(data)])
              .range([0, width - 100]);

var x_axis = d3.axisBottom()
               .scale(scale);

chart.append("group")
   .call(x_axis);

Я ничего не вижу в своем браузере, но, если я проверяю элемент, Axis «компилируется» в коде, и я могу навести курсор на каждую отметку в коде, пока позиция в DOM отмечена. Но не на что смотреть.

Уже существует диаграмма, написанная в d3 / canvas, но доступ к Axis осуществляется напрямую на холст, например

const canvas = document.getElementById(this.id)
const context = canvas.getContext('2d')
// ..a lot of code here..
context.beginPath()
moveTo(0, height + tickSize)
lineTo(0, height - 0.5)
// ...

Цель состоит в том, чтобы использовать для этого d3.

Это возможно только с svg?

Заранее спасибо!

1
wolfbiker1 7 Сен 2020 в 11:44

1 ответ

Лучший ответ

Вам нужно будет нарисовать ось вручную на элементе <canvas>. Вот пример с помощью D3 и Canvas в 3 шага и D3 + Canvas demo:

// Grab a reference to the canvas element
let canvas = document.querySelector('canvas');
// And to its context
let ctx = canvas.getContext('2d');

// Define our margins and plot dimensions
let margins = {
  top: 20,
  bottom: 40,
  left: 30,
  right: 20
};
let width = canvas.width - margins.left - margins.right;
let height = canvas.height - margins.top - margins.bottom;

// Center the chart
ctx.translate(margins.left, margins.top);

// Your data
let data = [10, 15, 20, 25, 30];

// Create the x-scale
let x = d3.scaleBand()
  .domain(data)
  .rangeRound([0, width])
  .padding(0.1);

// Create the y-scale
let y = d3.scaleLinear()
  .domain([0, d3.max(data)])
  .rangeRound([height, 0]);

// Define y-ticks
var yTickCount = 10;
var yTicks = y.ticks(yTickCount);

// Draw the x-axis
ctx.beginPath();
x.domain().forEach(d => {
  ctx.moveTo(x(d) + x.bandwidth() / 2, height);
  ctx.lineTo(x(d) + x.bandwidth() / 2, height + 6);
});
ctx.strokeStyle = '#000';
ctx.stroke();

// And apply the x-axis labels
ctx.textAlign = "center";
ctx.textBaseline = "top";
x.domain().forEach((d, i) => {
  ctx.fillText(i, x(d) + x.bandwidth() / 2, height + 6);
});
ctx.textAlign = "center";
ctx.textBaseline = "bottom";
x.domain().forEach((d, i) => {
  ctx.fillText(d, x(d) + x.bandwidth() / 2, y(d));
});
ctx.strokeStyle = "#000";
ctx.stroke();

// Now draw the y-axis
yTicks.forEach(d => {
  ctx.moveTo(0, y(d) + 0.5);
  ctx.lineTo(-6, y(d) + 0.5);
});
ctx.strokeStyle = "#000";
ctx.stroke();

// And add the y-axis ticks and labels
ctx.textAlign = "right";
ctx.textBaseline = "middle";
yTicks.forEach(d => {
  ctx.fillText(d, -9, y(d));
});
ctx.beginPath();
ctx.lineTo(0.5, 0.5);
ctx.lineTo(0.5, height + 0.5);
ctx.strokeStyle = "#000";
ctx.stroke();

ctx.save();
ctx.rotate(-Math.PI / 2);
ctx.textAlign = "right";
ctx.textBasline = "top";
ctx.restore();

// Finally, draw the bars using your data
ctx.fillStyle = 'blue';
data.forEach((d, i) => {
  ctx.fillRect(x(d), y(d), x.bandwidth(), height - y(d));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<canvas id="canvas" height=300 width=600></canvas>

Если вам не нужно использовать D3, вы можете изучить другую библиотеку диаграмм, разработанную специально для элемента canvas, например CanvasJS.

1
JoshG 7 Сен 2020 в 10:25