图例来源网络我们熟知的图形、图表以及地图等都属于数据可视化的范畴。今天我们主要讨论数据可视化中的图表,像柱状图、折线图、面积图、饼图、热力图都是使用频率非常高的图表。
图例来源网络如果要在移动端绘制一个类似于下图,使用真实数据渲染的简单面积图表,我们应该如何实现它呢?相信大家脑子里应该都有各种方案了,那么接下来我们就来一步步实现它。



我们由元素间的继承关系可以得出的结论是:svg元素和dom元素基本相似,因此对于svg元素,完全可以从dom元素的角度去理解和应用,上手成本几乎就可以忽略不计了。并且svg和css,javascript等其他网络标准无缝衔接。本质上,svg相对于图像,就好比html相对于文本;
图例来源于网络了解了svg的坐标系之后,我们来绘制曲线面积图中的坐标系,坐标系其实就是由两条线相交而成,svg中的line元素就是用来绘制直线的,所以使用line元素就可以绘制出X轴和Y轴。需要注意的是svg的坐标系原点在左上角,而我们需要实现的图表中坐标系原点在左下角,所以在实现的时候要对y轴的实际坐标进行处理。createCoordinate() {
this.svg.createLine(
[
{
x1: '0',
y1: '0',
x2: '0',
// ui设计稿上y轴高度为205,由于顶部游标的存在(游标高度57,宽度122),所以y轴变为205+57;
// 由于整个坐标轴往下平移了57,所以最下面的坐标会出现不显示的情况,故再增加50的buffer
y2: `${this.$toRealPx(262 + 50)}px`,
stroke: '#F0F0F0',
'stroke-width': '1',
},
{
x1: '0',
y1: `${this.$toRealPx(262 + 50)}px`,
x2: `${this.$toRealPx(595)}px`,
y2: `${this.$toRealPx(262 + 50)}px`,
stroke: '#F0F0F0',
'stroke-width': '1',
},
],
this.svgObj
)
}
const circlePoints = this.graphAxisData.map((v, idx) => {
return {
cx: v.xAxis,
cy: v.yAxis || 0,
r: this.$toRealPx(5),
stroke: '#7792D8',
'stroke-width': this.$toRealPx(3),
fill: 'white',
title: `class${idx + 1}`,
imageIndex: `imageClass${idx + 1}`,
}
})
const circleImage = this.graphAxisData.map((v, idx) => {
return {
x: (v.xAxis - this.$toRealPx(122) / 2),
y: (v.yAxis - this.$toRealPx(52) - this.$toRealPx(8)) || 0,
height: this.$toRealPx(52),
width: this.$toRealPx(122),
id: `imageClass${idx + 1}`,
href: 'https://pic3.zhuanstatic.com/zhuanzh/b13744dd-c240-4961-8054-9f923586ea5a.png',
}
})
const circleText = this.graphAxisData.map((v, idx) => {
return {
x: v.xAxis,
y: (v.yAxis - this.$toRealPx(52 / 2)) || 0,
fill: '#111111',
'font-size': this.$toRealPx(24),
'text-anchor': 'middle',
title: `¥${v.oriYAxis}`,
id: `class${idx + 1}`,
}
})
其中,t代表斜率,取值为0-1;p0代表起始点坐标(x0,y0);p1代表第一个控制点坐标(x1,y1);p2代表第二个控制点坐标(x2,y2);p3代表终点坐标(x3,y3);pt代表这条曲线上的任意一个点坐标(xt,yt)。当t由0-1逐渐变化的时候,可以得到一系列的(xt,yt),这一系列(xt,yt)就组成了一条三次贝塞尔曲线,这就是三次贝塞尔曲线的定义。通过以上介绍可知,绘制三次贝塞尔曲线必须得知道起始点、两个控制点以及终点。后端会返回给我们相应的几个数据点,也就是说这几个数据点的坐标是已知的,现在的问题就成了给定一组已知数据点,如何拟合成一条曲线?其实思路很简单,假如说有已知的5个点,那么我们将第一个点作为起始点,第二个点作为终点,计算出他们之间的控制点,绘制一条曲线,同样的,又以第二个点作为起点,第三个点作为终点,再重复以上过程,最终即绘制出一条横穿五个点的平滑曲线。此处附上算法源码createBezierLine() {
const polygonPath = this.getCubicBezierCurvePath(
this.graphAxisData.map((v) => {
return {
x: v.xAxis,
y: v.yAxis,
}
})
)
this.svg.createPath(
{
d: polygonPath,
fill: 'none',
stroke: '#7792D8',
'stroke-width': 2
},
this.svgObject
)
}
getCubicBezierCurvePath(knots) {
const firstControlPoints = []
const secondControlPoints = []
const path = []
this.getCubicBezierCurvePoints(knots, firstControlPoints, secondControlPoints)
for (let i = 0, len = knots.length; i < len; i++) {
if (i === 0) {
path.push(['M', knots[i].x, knots[i].y].join(' '))
} else {
const firstControlPoint = firstControlPoints[i - 1]
const secondControlPoint = secondControlPoints[i - 1]
path.push(
[
'C',
firstControlPoint.x,
firstControlPoint.y, // 第一个控制点
secondControlPoint.x,
secondControlPoint.y, // 第二个控制点
knots[i].x,
knots[i].y, // 实点
].join(' ')
)
}
}
return path.join(' ')
}
getCubicBezierCurvePoints(knots, firstControlPoints, secondControlPoints) {
const rhs = []
const n = knots.length - 1
let x = 0
let y = 0
let i = 0
if (n < 1) {
return
}
// Set right hand side X values0
for (i = 0; i < n - 1; ++i) {
rhs[i] = 4 * knots[i].x + 2 * knots[i + 1].x
}
rhs[0] = knots[0].x + 2 * knots[1].x
rhs[n - 1] = 3 * knots[n - 1].x
// Get first control points X-values
x = this.getFirstControlPoints(rhs)
// Set right hand side Y values
for (i = 1; i < n - 1; ++i) {
rhs[i] = 4 * knots[i].y + 2 * knots[i + 1].y
}
rhs[0] = knots[0].y + 2 * knots[1].y
rhs[n - 1] = 3 * knots[n - 1].y
// Get first control points Y-values
y = this.getFirstControlPoints(rhs)
for (i = 0; i < n; ++i) {
// First control point
firstControlPoints[i] = {
x: x[i],
y: y[i],
}
// Second control point
if (i < n - 1) {
secondControlPoints[i] = {
x: 2 * knots[i + 1].x - x[i + 1],
y: 2 * knots[i + 1].y - y[i + 1],
}
} else {
secondControlPoints[i] = {
x: (knots[n].x + x[n - 1]) / 2,
y: (knots[n].y + y[n - 1]) / 2,
}
}
}
}
getFirstControlPoints(rhs) {
const n = rhs.length
const x = [] // Solution vector.
const tmp = [] // Temp workspace.
let b = 2.0
let i = 0
x[0] = rhs[0] / b
for (i = 1; i < n; i++) {
// Decomposition and forward substitution.
tmp[i] = 1 / b
b = (i < n - 1 ? 4.0 : 2.0) - tmp[i]
x[i] = (rhs[i] - x[i - 1]) / b
}
for (i = 1; i < n; i++) {
x[n - i - 1] -= tmp[n - i] * x[n - i] // Backsubstitution.
}
return x
}
我安装了ruby、yeoman,当我运行我的项目时,出现了这个错误:Warning:Running"compass:dist"(compass)taskWarning:YouneedtohaveRubyandCompassinstalledthistasktowork.Moreinfo:https://github.com/gruUse--forcetocontinue.Use--forcetocontinue.我有进入可变session目标的路径,但它不起作用。谁能帮帮我? 最佳答案 我必须运行这个:geminstallcom
文章目录一、项目场景二、基本模块原理与调试方法分析——信源部分:三、信号处理部分和显示部分:四、基本的通信链路搭建:四、特殊模块:interpretedMATLABfunction:五、总结和坑点提醒一、项目场景 最近一个任务是使用simulink搭建一个MIMO串扰消除的链路,并用实际收到的数据进行测试,在搭建的过程中也遇到了不少的问题(当然这比vivado里面的debug好不知道多少倍)。准备趁着这个机会,先以一个很基本的通信链路对simulink基础和相关的debug方法进行总结。 在本篇中,主要记录simulink的基本原理和基本的SISO通信传输链路(QPSK方式),计划在下篇记
我不是Ruby专家,但想弄清楚发生了什么,因为我试图让指南针在节点应用程序中工作,但我的Ruby似乎坏了。打字:ruby--version让我:ruby2.1.1p76(2014-02-24revision45161)[x86_64-darwin13.0]我安装了Homebrew,之前遇到过Ruby版本的问题,但它似乎已安装并且可以正常工作。但是,当我使用gem输入请求时,出现此错误:$gem-hErrorloadingRubyGemsplugin"/Users/user_dir/.rvm/gems/ruby-2.1.1@global/gems/executable-hooks-1.3
Unity数据可视化图表插件XCharts3.0发布历时8个多月,业余时间,断断续续,XCharts3.0总算发布了。如果要打个满意度,我给3.0版本来个80分。对于代码框架结构设计的调整改动,基本符合预期,甚是满意。相比之前的1.0和2.0版本,我认为3.0才是一个拿得出手给广大开发者使用的版本。1.0发布的时候,很兴奋,从0.1到1.0,也磨了一年,真的等不及想给大家试用了,还特地写过一篇文章以示庆祝。那个时候,1.0虽然还还不够完善,功能也不够丰富,但它是XCharts的开始,没有1.0,也就没有后面的2.0和3.0。后面的2.0发布,做了很多改进和优化,随着版本迭代,慢慢的发现有不少硬
我正在尝试安装bootstrap-sass并收到以下错误。我试过旧版本的sass,但bundler一直在安装3.3.0。WARN:UnresolvedspecsduringGem::Specification.reset:sass(~>3.2)WARN:Clearingoutunresolvedspecs.Pleasereportabugifthiscausesproblems./Library/Ruby/Gems/2.0.0/gems/compass-0.12.2/lib/compass/sass_extensions/monkey_patches/browser_support.r
目录配置模拟模拟类型与实例期望录制-回放-验证指定调用计数验证指定自定义结果验证调用参数联级模拟部分模拟模拟未实现的类其他伪装伪装方法及类伪装未实现类本文主要内容如何在SpringBoot中配置使用JMockit如何mock/faking依赖的对象如何对行为mock如何VerificationJMockit之所以强大,是因其使用了javaagent对类的字节码做了修改,在JVM的所有mock工具中,它是功能最强大的。同时注解又是最少的。配置在SpringBoot项目中使用JMockit隔离代码做单元测试,需要做以下配置引入JMockit依赖。dependencies>dependency>gr
几年前,我从一些Rails初学者指南开始学习Ruby/Rails。那时我已经学习了Rails的基础知识,例如模型和路由的一些约定优于配置,以及如何使用helpers等。但是,我并没有坚持多久,因为此后不久我发现了Sinatra,并决定我个人更喜欢它。不过,我最终真的爱上了Ruby,从那以后我写了很多Ruby,几乎没有一个是针对任何Rails项目的。然而,事实证明大部分可用的Ruby工作都是针对Rails应用程序的。所以我现在想再尝试一下Rails。现在,该引用资料很棒并且有很多有用的信息,但我只查看了我需要的特定内容的引用资料,而没有记住。但我不太可能在引用资料中看到像script/c
刚刚意识到instance_eval产生self作为关联block的参数(除了1.9.2版本中的错误:http://www.ruby-forum.com/topic/189422)1.9.3p194:003>classC;end1.9.3p194:004>C.new.instance_eval{|*a|a}=>[#]1.9.3p194:005>这是否在某处记录/规范?看着ruby-doc:BasicObject,看不到提到的任何block参数。除了一些纯粹的历史原因之外,是否还有其他原因明确地传递它,而它自己总是被定义?我被这个击中的方式是:l=lambda{}myobj.instan
我正在研究rubyonrails指南,即http://guides.rubyonrails.org/layouts_and_rendering.html上的“布局和渲染”主题我对将实例变量传递给redirect_to方法感到困惑。这怎么可能?我认为redirect_to与重定向到另一个网页或url相关。在指南中给出的示例中,它说了以下内容:2.2.2RenderinganAction’sViewIfyouwanttorendertheviewthatcorrespondstoadifferentactionwithinthesametemplate,youcanuserenderw
当我运行rakedb:migrate时出现这个错误rakeaborted!Savingdiagramfailed!VerifythatGraphvizisinstalledandinyourpath,orusefiletype=dot.完整日志:rakedb:migrateLoadingapplicationenvironment...LoadingcodeinsearchofActiveRecordmodels...GeneratingEntity-RelationshipDiagramfor20models...rakeaborted!Savingdiagramfailed!Ver