如何使用d3.js制作药物的形状? [英] how can I make the shape of a medition using d3.js?

查看:44
本文介绍了如何使用d3.js制作药物的形状?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基本上,我试图做类似图像的事情,我以左边的图像为基础,我的目标是在右边的图像中做一些事情.

basically I'm trying to do something like the image, I'm basing myself on the image on the left, my goal is to have something like the image on the right.

这是我所获得的最大成就:

This is the most I have achieved:

我是d3.js的新手,我不知道如何制作温度计形状,我尝试了很多事情,但是也许由于我的经验不足,我变得太复杂了.

I am new to d3.js, I don't know how to make the thermometer shape, I have tried many things but maybe because of my inexperience I get too complicated.

这是我的实时代码:

https://jsfiddle.net/zukdymvf/1/

function generateNumber() {
  let number = parseInt(Math.random() * 100)
  //let number= 100

  d3.select("#indicador").attr("y", yScale(number) - 3); // to center the indicador image
  d3.select("#indicadorText").attr("y", yScale(number) + 5).text(number);
}

let heightRectangle = 10;
d3.select("#visualization").append('svg')
var vis = d3.select("svg").attr("width", 800).attr("height", 614).style("border", "1px solid red");

let g = vis.append("g").style("transform", "translate(0px, 10px)").style("transform", "translate(10px, 10px)");


g.append("image")
  .attr("id", "indicador")
  .attr("href", "https://www.shareicon.net/data/256x256/2015/08/17/86784_left_512x512.png")
  .attr("width", 15)
  .attr("height", 15)
  .attr("y", 403)
  .style("transform", "translate(100px)")

g.append("text")
  .attr("id", "indicadorText")
  .text("0")
  .attr("x", 120)
  .attr("y", 413)
  .attr("alignment-baseline", "middle")

g.append("circle")
  .attr("id", "mycircle")
  .attr("r", 55)
  .attr("cx", 52)
  .attr("cy", 450)
  .attr("width", "100")
  .attr("height", "100")
  .attr("fill", "red")
  .attr("stroke", "black")
//Doing my color bar
var arr = d3.range(101)
let maxRange = 410; // instead of 600
var yScale = d3.scaleLinear().domain([0, 100]).range([maxRange, 0])
let borderRadius = 5;
var colorScale = d3.scaleLinear().domain([0, 50, 100])
  .range(["green", "yellow", "red"])

g.selectAll('.rect').data(arr).enter()
  .append('rect')
  .attr("class", "rect")
  .attr("rx", borderRadius)

  .attr("ry", borderRadius)

  .attr("y", function(d, i) {
    return i * 4
  })
  .attr("x", 20)
  .attr("height", heightRectangle)
  .attr("width", 60)
  .attr("fill", function(d) {
    return colorScale(d)
  })


var y = d3.scaleLinear()
  .domain([0, 500])
  .range([maxRange, 0])


var yAxisBar = d3.axisLeft()
  .scale(y)
  .ticks(15);
//.tickFormat(function(d,i){ return "" });
g.append("g")
  .attr("class", "y axis")
  .attr("transform", "translate(150 , 0)")
  .call(yAxisBar)
  .append("text")
  .attr("transform", "rotate(-90)")
  .attr("y", 0)
  .attr("dy", ".71em")
  .style("text-anchor", "end")
  .text("axis title");

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="visualization"></div>
<button onclick="generateNumber()">
 Generate number
</button>

推荐答案

我编写了一个简单的JavaScript函数,该函数返回温度计的形状.我发现本教程此文档对于理解如何编写SVG路径非常有价值.

I wrote a plain JavaScript function that returns the shape of a thermometer. I find that this tutorial and this documentation are very valuable in understanding how to write SVG paths like that.

要传递的参数为 radius -灯泡的半径, width -轴的宽度和 height -高度轴的

The arguments to pass are radius - the radius of the bulb, width - the width of the shaft, and height - the height of the shaft.

希望您可以使用它在其中渲染比例,并使用新值调整其高度

Hopefully, you can use it to render your scale inside it, and adjust its height with the new value

function getThermometerOutline(shape) {
  const height = shape.height;
  const width = shape.width;
  const radius = shape.radius;

  // Draw it in two parts, first the left, then the right
  // Start at the very top, the total width is 2x the radius
  let result = `M${radius},0 `;

  // Then draw the first rounding
  const offset = radius - (width / 2);
  result += `A ${width / 2} ${width / 2} 0 0 0 ${offset},${offset} `;

  // Go down the shaft to the base of the bulb
  const shaftHeight = height - offset - (2 * radius); // more or less
  result += `V${shaftHeight + offset} `;

  // Draw the bulb in two half circles, first we end at the bottom
  const endPoint = {
    x: radius,
    y: height
  };
  result += `a ${radius} ${radius} 0 1 0 `
  result += `${width},0 `;

  // Now move back up to the very top
  result += `V${offset} `;
  result += `A ${width / 2} ${width / 2} 0 0 0 ${radius},0 `;

  return result + 'Z';
}

function generateNumber() {
  let number = parseInt(Math.random() * 100)
  //let number= 100

  d3.select("#indicador").attr("y", yScale(number) - 3); // to center the indicador image
  d3.select("#indicadorText").attr("y", yScale(number) + 5).text(number);
}

let heightRectangle = 10;
const vis = d3.select("#visualization")
  .append('svg')
  .attr("width", 800)
  .attr("height", 614)
  .style("border", "1px solid red");

let g = vis.append("g")
  .style("transform", "translate(10px, 10px)");

g.append("image")
  .attr("id", "indicador")
  .attr("href", "https://www.shareicon.net/data/256x256/2015/08/17/86784_left_512x512.png")
  .attr("width", 15)
  .attr("height", 15)
  .attr("y", 403)
  .style("transform", "translate(100px)")

g.append("text")
  .attr("id", "indicadorText")
  .text("0")
  .attr("x", 120)
  .attr("y", 413)
  .attr("alignment-baseline", "middle")

const thermometer = vis.append("g")
  .attr("id", "thermometer")
  .attr('transform', 'translate(10, 10)');

thermometer.append("circle")
  .attr("id", "mycircle")
  .attr("r", 55)
  .attr("cx", 52)
  .attr("cy", 450)
  .attr("width", "100")
  .attr("height", "100")
  .attr("fill", "red")
  .attr("stroke", "black")
//Doing my color bar
var arr = d3.range(101)
let maxRange = 410; // instead of 600
var yScale = d3.scaleLinear().domain([0, 100]).range([maxRange, 0])
let borderRadius = 5;
var colorScale = d3.scaleLinear().domain([0, 50, 100])
  .range(["green", "yellow", "red"])

thermometer.selectAll('.rect')
  .data(arr)
  .enter()
  .append('rect')
  .attr("class", "rect")
  .attr("y", function(d, i) {
    return i * 4
  })
  .attr("x", 20)
  .attr("height", heightRectangle)
  .attr("width", 60)
  .attr("fill", function(d) {
    return colorScale(d)
  })

const outline = thermometer.append("path")
  .attr("id", "outline")
  .attr("d", getThermometerOutline({
    width: 62,
    height: 532,
    radius: 56
  }))
  .attr("transform", "translate(-5, -16)")

var y = d3.scaleLinear()
  .domain([0, 500])
  .range([maxRange, 0])


var yAxisBar = d3.axisLeft()
  .scale(y)
  .ticks(15);
//.tickFormat(function(d,i){ return "" });

g.append("g")
  .attr("class", "y axis")
  .attr("transform", "translate(150 , 0)")
  .call(yAxisBar)
  .append("text")
  .attr("transform", "rotate(-90)")
  .attr("y", 0)
  .attr("dy", ".71em")
  .style("text-anchor", "end")
  .text("axis title");

#thermometer #outline {
  fill: none;
  stroke: black;
  stroke-width: 5px;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="visualization"></div>
<button onclick="generateNumber()">
 Generate number
</button>

编辑以完全填满温度计:

function getThermometerOutline(shape) {
  const height = shape.height;
  const width = shape.width;
  const radius = shape.radius;

  // Draw it in two parts, first the left, then the right
  // Start at the very top, the total width is 2x the radius
  let result = `M${radius},0 `;

  // Then draw the first rounding
  const offset = radius - (width / 2);
  result += `A ${width / 2} ${width / 2} 0 0 0 ${offset},${offset} `;

  // Go down the shaft to the base of the bulb
  const shaftHeight = height - offset - (2 * radius); // more or less
  result += `V${shaftHeight + offset} `;

  // Draw the bulb in two half circles, first we end at the bottom
  const endPoint = {
    x: radius,
    y: height
  };
  result += `a ${radius} ${radius} 0 1 0 `
  result += `${width},0 `;

  // Now move back up to the very top
  result += `V${offset} `;
  result += `A ${width / 2} ${width / 2} 0 0 0 ${radius},0 `;

  return result + 'Z';
}

function generateNumber() {
  let number = parseInt(Math.random() * 100)
  //let number= 100

  d3.select("#indicador").attr("y", yScale(number) - 3); // to center the indicador image
  d3.select("#indicadorText").attr("y", yScale(number) + 5).text(number);
}

const vis = d3.select("#visualization")
  .append('svg')
  .attr("width", 800)
  .attr("height", 614)
  .style("border", "1px solid red");

const gradient = vis.append('defs')
  .append('linearGradient')
  .attr('id', 'temperature')
  .attr('x1', '0%')
  .attr('x2', '0%')
  .attr('y1', '100%')
  .attr('y2', '0%');

// Start at red
gradient.append('stop')
  .attr('offset', '0%')
  .style('stop-color', 'red');

// The entire bulb should be red
// a little less than radius / (height + radius)
gradient.append('stop')
  .attr('offset', '8%')
  .style('stop-color', 'red');


gradient.append('stop')
  .attr('offset', '50%')
  .style('stop-color', 'yellow');

gradient.append('stop')
  .attr('offset', '100%')
  .style('stop-color', 'green');

let g = vis.append("g")
  .style("transform", "translate(10px, 10px)");

g.append("image")
  .attr("id", "indicador")
  .attr("href", "https://www.shareicon.net/data/256x256/2015/08/17/86784_left_512x512.png")
  .attr("width", 15)
  .attr("height", 15)
  .attr("y", 403)
  .style("transform", "translate(100px)")

g.append("text")
  .attr("id", "indicadorText")
  .text("0")
  .attr("x", 120)
  .attr("y", 413)
  .attr("alignment-baseline", "middle")

const thermometer = vis.append("g")
  .attr("id", "thermometer")
  .attr('transform', 'translate(10, 10)');

const outline = thermometer.append("path")
  .attr("id", "outline")
  .attr("d", getThermometerOutline({
    width: 62,
    height: 532,
    radius: 56
  }))
  .attr("transform", "translate(-5, -16)")
  .style("fill", "url(#temperature)");

let maxRange = 410; // instead of 600
var y = d3.scaleLinear()
  .domain([0, 500])
  .range([maxRange, 0])


var yAxisBar = d3.axisLeft()
  .scale(y)
  .ticks(15);
//.tickFormat(function(d,i){ return "" });

g.append("g")
  .attr("class", "y axis")
  .attr("transform", "translate(150 , 0)")
  .call(yAxisBar)
  .append("text")
  .attr("transform", "rotate(-90)")
  .attr("y", 0)
  .attr("dy", ".71em")
  .style("text-anchor", "end")
  .text("axis title");

#thermometer #outline {
  fill: none;
  stroke: black;
  stroke-width: 5px;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="visualization"></div>
<button onclick="generateNumber()">
 Generate number
</button>

这篇关于如何使用d3.js制作药物的形状?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆