React-Native画线平滑处理
Posted 苏小败在路上
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React-Native画线平滑处理相关的知识,希望对你有一定的参考价值。
参考:http://blog.csdn.net/pz789as/article/details/52795275
这次开发要手写画线,我们一般画线的时候是直接获取屏幕上的点,然后利用ART绘制出一天路径线:
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, Component from 'react';
import
StyleSheet,
Text,
View,
PanResponder,
TouchableOpacity,
StatusBar,
ART,
from 'react-native';
const
Shape,
Group,
Transform,
Surface,
Path,
Pattern,
LinearGradient,
RadialGradient,
// Text,
ClippingRectangle,
= ART;
import Utils from './Utils';
let cv =
status_norm: 0,
status_auto: 1,
status_pause: 2,
touch_begin: 0,
touch_move: 1,
touch_ended: 2,
;
export default class DrawLayout extends Component
constructor(props)
super(props);
this._panResponder = ;
this.mousePosition = null;
this.lastMousePostion = null;
this.arrOrgPoint = [];
this.arrUsedPoint = [];
this.nowR = 10;
this.blnCanDraw = false;
this.showPoints = null;
this.status = cv.status_norm;
this.wrongCount = 0;
this.state=
blnUpdate: false,
;
setUpdate()
this.setState(
blnUpdate: !this.state.blnUpdate,
);
componentWillMount()
this._panResponder = PanResponder.create(
onStartShouldSetPanResponder: this.onStartShouldSetPanResponder.bind(this),
onMoveShouldSetPanResponder: this.onMoveShouldSetPanResponder.bind(this),
onPanResponderGrant: this.onPanResponderGrant.bind(this),
onPanResponderMove: this.onPanResponderMove.bind(this),
onPanResponderRelease: this.onPanResponderRelease.bind(this),
onPanResponderTerminate: this.onPanResponderTerminate.bind(this),
);
componentDidMount()
this._autoUpdate = setInterval(this.autoUpdate.bind(this), 1/60);
componentWillUnmount()
this._autoUpdate && clearInterval(this._autoUpdate);
onStartShouldSetPanResponder(e, g)
if (this.status == cv.status_auto || this.status == cv.status_pause)
return false;
return true;
onMoveShouldSetPanResponder(e, g)
if (this.status == cv.status_auto || this.status == cv.status_pause)
return false;
return true;
onPanResponderGrant(e, g)
if (g.numberActiveTouches == 1)
this.mousePosition =
x: e.nativeEvent.locationX,
y: e.nativeEvent.locationY
;
this.ResetDrawPoint();
this.AddUsePoint(this.mousePosition, cv.touch_begin);
onPanResponderMove(e, g)
if (g.numberActiveTouches == 1)
this.mousePosition =
x: e.nativeEvent.locationX,
y: e.nativeEvent.locationY
;
var s = Utils.DisP(this.mousePosition, this.lastMousePostion);
if (s >= 1)
this.AddUsePoint(this.mousePosition, cv.touch_move);
onPanResponderRelease(e, g)
this.endPanResponder(e, g);
onPanResponderTerminate(e, g)
this.endPanResponder(e, g);
endPanResponder(e, g)
this.mousePosition =
x: e.nativeEvent.locationX,
y: e.nativeEvent.locationY
;
this.AddUsePoint(this.mousePosition, cv.touch_ended);
ResetDrawPoint()
this.arrOrgPoint = [];
this.arrUsedPoint = [];
this.nowR = 5;
this.blnCanDraw = false;
this.showPoints = null;
AddUsePoint(pos, kind)
if (kind == cv.touch_begin)
this.lastMousePostion = this.mousePosition;
this.arrOrgPoint.push(pos);
this.AddSinglePoint(pos, this.nowR);
this.blnCanDraw = true;
else if (this.blnCanDraw)
this.arrOrgPoint.push(pos);
var blnSet = false;
if (this.arrOrgPoint.length > 2)
var count = Utils.DisP(this.lastMousePostion, pos);
if (count > 1)
for(var i=0;i<count;i++)
var p = Utils.LerpP(this.lastMousePostion, pos, (i+1)/count);
this.AddSinglePoint(p, this.nowR);
blnSet = true;
else
var count = Utils.DisP(this.lastMousePostion, pos);
if (count > 1)
var c = Math.ceil(count);
for(var i=0; i < c; i++)
if (i == c - 1)
this.AddSinglePoint(pos, this.nowR);
else
var p = Utils.LerpP(this.lastMousePostion, pos, (i + 1) / c);
this.AddSinglePoint(p, this.nowR);
blnSet = true;
else
// this.AddSinglePoint(pos, this.nowR);
blnSet = false;
if (kind == cv.touch_ended)
// this.ResetDrawPoint();
if (blnSet)
this.lastMousePostion = this.mousePosition;
this.setUpdate();
AddSinglePoint(pos, r)
this.arrUsedPoint.push(pos);
d = new Path();
for(var i=0;i<this.arrUsedPoint.length;i++)
var p = this.arrUsedPoint[i];
if (i==0)
d.moveTo(p.x, p.y);
else
d.lineTo(p.x, p.y);
this.showPoints = d;
render()
return (
<View style=styles.container ...this._panResponder.panHandlers>
<View style=styles.mouseView>
<Surface ref='lineView' width=ScreenWidth height=ScreenHeight>
<Shape d=this.showPoints stroke='rgb(0,0,255)' strokeWidth=this.nowR />
</Surface>
</View>
</View>
);
这里主要是在AddUsePoint里面对触摸点进行处理,在touchmove之后,每次都要保存好获得到的点,然后取差值,进行计算
上面代码运行后,得到的线条是这样的:
看到结果后,是不是很不理想,我们想要的不是横平竖直啊,怎么使它们变得平滑呢,我开始想的是贝塞尔曲线,于是在网上找,终于找到一个算法,叫B样条曲线算法,其实这个就是贝塞尔的一种,原理大概就是根据其中几个点进行一个公式算法,得到这些点之间的其他点。
于是在上面的代码进行改善,修改AddUsePoint,添加B样条曲线算法,先看看效果:
效果很不错哦~
代码如下:
AddUsePoint(pos, kind)
if (kind == cv.touch_begin)
this.lastMousePostion = this.mousePosition;
this.arrOrgPoint.push(pos);
this.AddSinglePoint(pos, this.nowR);
this.blnCanDraw = true;
else if (this.blnCanDraw)
this.arrOrgPoint.push(pos);
var blnSet = false;
if (this.arrOrgPoint.length > 2)
var listTemp = [];//将最新的三个点加入一个临时数组里面
listTemp.push(this.arrOrgPoint[this.arrOrgPoint.length - 3]);
listTemp.push(this.arrOrgPoint[this.arrOrgPoint.length - 2]);
listTemp.push(this.arrOrgPoint[this.arrOrgPoint.length - 1]);
listTemp = this.BSpline2Smooth1(listTemp, false);//将数组传入算法中进行计算
for(var i=0;i<listTemp.length;i++)
this.AddSinglePoint(listTemp[i], this.nowR);
if (this.arrUsedPoint.length > 500)//控制点的数量,也就是线的长度。
this.blnCanDraw = false;
blnSet = true;
else
var count = Utils.DisP(this.lastMousePostion, pos);
if (count > 1)
var c = Math.ceil(count);
for(var i=0; i < c; i++)
if (i == c - 1)
this.AddSinglePoint(pos, this.nowR);
else
var p = Utils.LerpP(this.lastMousePostion, pos, (i + 1) / c);
this.AddSinglePoint(p, this.nowR);
blnSet = true;
else
// this.AddSinglePoint(pos, this.nowR);
blnSet = false;
if (kind == cv.touch_ended)
// this.CompareBihua();
// this.ResetDrawPoint();
if (blnSet)
this.lastMousePostion = this.mousePosition;
this.drawTouch && this.drawTouch.setPoints(this.showPoints);
BSpline2Smooth1(list, blnSet)//曲线算法处理函数
var aList = [];
aList = aList.concat(list);
if (blnSet)
aList.unshift(list[0]);
aList.push(list[list.length - 1]);
var tList = [];
var loc1 = 1;
var start = , end = ;
while(loc1 < aList.length - 1)
start = aList[loc1 - 1];
end = aList[loc1 + 1];
tList.push(Utils.LerpP(aList[loc1-1], aList[loc1], 0.5));//添加两点的中点
this.BSpline2Smooth2(tList, start, aList[loc1], end);//最主要的是这里
tList.push(Utils.LerpP(aList[loc1], aList[loc1+1], 0.5));
++loc1;
var rl = Utils.ResampleByLen(tList, 2);//得到处理之后的点之后,对点数组进行标准化处理,就算输出总长度,每个2个单位距离去一个插值点,得到新数据
if (rl != null)
return rl
else
return tList;
BSpline2Smooth2(list, arg1, arg2, arg3)
var locx = [];
var locy = [];
locx.push((arg1.x + arg2.x) * 0.5);
locx.push(arg2.x - arg1.x);
locx.push((arg1.x - 2*arg2.x + arg3.x) * 0.5);
locy.push((arg1.y + arg2.y) * 0.5);
locy.push(arg2.y - arg1.y);
locy.push((arg1.y - 2*arg2.y + arg3.y) * 0.5);
var loc6 = parseInt(Utils.CountDistance(arg1, arg3));
var loc7 = 0;
var loc8 = 0;
while(loc7 < loc6)
loc8 = loc7 / loc6;
var loc5 =
x: locx[0] + loc8 * (locx[1] + locx[2] * loc8),
y: locy[0] + loc8 * (locy[1] + locy[2] * loc8)
;
list.push(loc5);
loc7++;
Utils类《-点这里查看,我这里贴出来
以上是关于React-Native画线平滑处理的主要内容,如果未能解决你的问题,请参考以下文章
origin三维图数据过少,曲面不圆滑,如何处理可以使曲面圆滑。拟合、差值等,不能改变原来的走势
基于unity物体定点移动与模拟刹车的细节 GIF 图文详解——线性差值函数以及平滑阻尼的运用和实践(Lerp AND SmoothDamp)