写点什么

贝塞尔曲线在 iOS 端的绘图实践

  • 2020-09-15
  • 本文字数:9102 字

    阅读完需:约 30 分钟

贝塞尔曲线在iOS端的绘图实践

1 前言

在这个大数据的时代,很多信息只有通过图形才能更好的展示给用户。例如:房屋的历史价格、基金股票的历史增长、数据占比分析图等。如何做图形?需要用到什么知识?本文将从 建模、显示 两方面来展开介绍。


2 建模

建模是一切图形的基础,其他内容的前提,要用代码展示一个图形,首先要有它的几何模型表达。目前在客户端二维图形建模上,Bézier curve(贝塞尔曲线)可以称为 经典 和 主流 并重的数学曲线。


对于贝塞尔曲线来说,最重要的是 起始点、终止点(也称锚点)、控制点。控制点决定了一条路径的弯曲轨迹,根据控制点的个数,贝塞尔曲线被分为:一阶贝塞尔曲线(0 个控制点)、二阶贝塞尔曲线(1 个控制点)、三阶贝塞尔曲线(2 个控制点)、N 阶贝塞尔曲线(n - 1 个控制点)。

2.1 贝塞尔曲线原理

以二阶贝塞尔曲线为例 解释说明:


起始点:P0 ; 控制点:P1 ; 终止点:P2



  1. 连接 P0P1 线 和 P1P2 线。

  2. 在 P0P1 线上找到点 A,在 P1P2 线上找到点 B,使得 P0A/AP1 = P1B/BP2

  3. 连接 AB,在 AB 上找到点 X,X 点满足:AX/XB = P0A/AP1 = P1B/BP2

  4. 找出所有满足公式:AX/XB = P0A/AP1 = P1B/BP2 的 X 点。(从 P0 到 P2 的红色曲线点为所有 X 点的连线)这条由所有 X 点组成的连线 即为 贝塞尔曲线。


二阶贝塞尔曲线 起始点:P0 ; 控制点:P1 ; 终止点:P2



三阶贝塞尔曲线 起始点:P0 ; 控制点:P1、P2; 终止点:P3



四阶贝塞尔曲线 起始点:P0 ; 控制点:P1、P2、P3 ; 终止点:P4


2.2 UIBezierPath 类

系统给我们提供了一个叫做 UIBezierPath 类,用它可以画简单的圆形,椭圆,矩形,圆角矩形,也可以通过添加点去生成任意的图形,还可以简单的创建一条二阶贝塞尔曲线和三阶贝塞尔曲线。我们来了解一下它的常用方法:

2.2.1 初始化方法

// 创建UIBezierPath对象+ (instancetype)bezierPath;// 创建在rect内的矩形+ (instancetype)bezierPathWithRect:(CGRect)rect;// 设定特定的角为圆角的矩形,corners:指定的角为圆角,其他角不变,cornerRadii:圆角的大小+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii;// 创建圆弧+ (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;// 通过已有路径创建路径+ (instancetype)bezierPathWithCGPath:(CGPathRef)CGPath;// 创建三次贝塞尔曲线 endPoint:终点 controlPoint1:控制点1 controlPoint2:控制点2- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2;- // 创建二次贝塞尔曲线 endPoint:终点 controlPoint:控制点- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint;
复制代码

2.2.2 使用方法

// 移动到某一点- (void)moveToPoint:(CGPoint)point;// 绘制一条线- (void)addLineToPoint:(CGPoint)point;// 闭合路径,即在终点和起点连一根线- (void)closePath;// 清空路径- (void)removeAllPoints;// 填充- (void)fill;// 描边,路径创建需要描边才能显示出来- (void)stroke;
复制代码

2.2.3 常用属性

// 将UIBezierPath类转换成CGPath,类似于UIColor的CGColor@property(nonatomic) CGPathRef CGPath;// path线的宽度@property(nonatomic) CGFloat lineWidth;// path端点样式@property(nonatomic) CGLineCap lineCapStyle;// 拐角样式@property(nonatomic) CGLineJoin lineJoinStyle;
复制代码

2.2.4 举个栗子🌰

先看效果👇:



代码如下:


- (void)drawRect:(CGRect)rect {
[[UIColor redColor] set];
// 右边第一个图 UIBezierPath* maskPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 50, 100, 100) byRoundingCorners:UIRectCornerTopLeft cornerRadii:CGSizeMake(30, 30)]; maskPath.lineWidth = 20.f; maskPath.lineJoinStyle = kCGLineJoinBevel; [maskPath stroke]; // 中间第二个图 UIBezierPath* maskFillPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(200, 50, 100, 100) byRoundingCorners:UIRectCornerTopLeft cornerRadii:CGSizeMake(30, 30)]; maskFillPath.lineWidth = 20.f; maskFillPath.lineJoinStyle = kCGLineJoinBevel; [maskFillPath fill]; [maskFillPath stroke]; // 右边第三个图 UIBezierPath *maskLinePath = [UIBezierPath bezierPath]; maskLinePath.lineWidth = 20.f; maskLinePath.lineCapStyle = kCGLineCapRound; [maskLinePath moveToPoint:CGPointMake(250.0, 50)]; [maskLinePath addLineToPoint:CGPointMake(300.0, 100.0)]; [maskLinePath stroke];}
复制代码


上图中:


1)图一和图二 唯一的不同是[maskFillPath fill]方法,fill 方法要在封闭的曲线调用。


2)图一和图二 为设定特定的角为圆角的矩形,corners 为 UIRectCornerTopLeft 左上角,cornerRadii 圆角大小为 30,绿色的箭头 表示的设定的这个角。


corners 为下面五种类型typedef NS_OPTIONS(NSUInteger, UIRectCorner) {    UIRectCornerTopLeft     = 1 << 0,    // 左上角    UIRectCornerTopRight    = 1 << 1,    // 右上角    UIRectCornerBottomLeft  = 1 << 2,    // 左下角    UIRectCornerBottomRight = 1 << 3,    // 右下角    UIRectCornerAllCorners  = ~0UL        // 全部};
复制代码


3)图一和图二 黄色的箭头 设置的属性 拐角样式:lineJoinStyle kCGLineJoinBevel(缺角)


lineJoinStyle 为下面三种类型typedef CF_ENUM(int32_t, CGLineJoin) {    kCGLineJoinMiter,    // 尖角    kCGLineJoinRound,    // 圆角    kCGLineJoinBevel    // 缺角};
复制代码


4)图三 白色的箭头 设置的属性 path 端点样式:lineCapStyle kCGLineCapRound(圆形端点)


lineCapStyle 为下面三种类型typedef CF_ENUM(int32_t, CGLineCap) {    kCGLineCapButt,        // 无端点    kCGLineCapRound,    // 圆形端点    kCGLineCapSquare    // 方形端点};
复制代码


有兴趣的 可以试试别的方法属性~

2.3 波浪曲线实现

如何实现 N 阶 波浪式曲线?如何找到 N-1 个对应的控制点?


有两个方法,下图为同数据,方案一 和 方案二 分别所得曲线图。


方案一 为左边(三阶贝塞尔)图 其中 第二条的红点 为数据的位置


方案二 为右边(CatmullRom)图 其中 第二条的红点 为数据的位置



方案一:根据 创建三次贝塞尔曲线 方法 实现波浪曲线


控制点的选取方案不唯一,以下为我选择控制点的方案:


控制点 P1:CGPointMake((PrePonit.x+NowPoint.x)/2, PrePonit.y)


控制点 P2:CGPointMake((PrePonit.x+NowPoint.x)/2, NowPoint.y)


可以根据前一个点 PrePonit 和 现在的点 NowPoint 进行计算 控制点。


主要代码如下:


UIBezierPath *path = [UIBezierPath bezierPath];[path moveToPoint:[self pointAtIndex:0]];NSInteger count = self.points.count;CGPoint PrePonit;
for (NSInteger i = 0; i < count; i++) {
CGPoint NowPoint = [self pointAtIndex:i]; if(i == 0) { PrePonit = NowPoint; } else { // 利用三次曲线 形成波浪曲线 [path addCurveToPoint:point controlPoint1:CGPointMake((PrePonit.x+NowPoint.x)/2, PrePonit.y) controlPoint2:CGPointMake((PrePonit.x+NowPoint.x)/2, NowPoint.y)]; PrePonit = NowPoint; }}return path;
复制代码


方案二:使用 CatmullRom 插值样条。(有兴趣的可以百度一下~这里只简单介绍)


要点分析:


1)给定一组控制点而得到一条曲线,曲线经过给定所有数据点。


2)Catmull-Rom 公式:P(t) = 0.5 * (2*p1 + (p2 - p0) *t + (2*p0 - 5*p1 + 4*p2 - p3)* t * t + (3*p1 - p0 - 3*p2 + p3) * t * t * t);


注:t 为分割的最小粒尺寸,根据 P0 P1 P2 P3 顺序的四个点 求得 P1P2 曲线公式。


主要代码如下:


void getPointsFromBezier(void *info, const CGPathElement *element) {    NSMutableArray *bezierPoints = (__bridge NSMutableArray *)info;    CGPathElementType type = element->type;    CGPoint *points = element->points;
if (type != kCGPathElementCloseSubpath) { [bezierPoints addObject:VALUE(0)]; if ((type != kCGPathElementAddLineToPoint) && (type != kCGPathElementMoveToPoint)) [bezierPoints addObject:VALUE(1)]; } if (type == kCGPathElementAddCurveToPoint) [bezierPoints addObject:VALUE(2)];}
NSArray *pointsFromBezierPath(UIBezierPath *bpath) { NSMutableArray *points = [NSMutableArray array]; // 获取贝塞尔曲线上所有的点 CGPathApply(bpath.CGPath, (__bridge void *)points, getPointsFromBezier); return points;}
- (UIBezierPath*)smoothedPathWithGranularity:(NSInteger)granularity path:(UIBezierPath *)path { NSMutableArray *points = [pointsFromBezierPath(path) mutableCopy];
if (points.count < 4) return [path copy]; [points insertObject:[points objectAtIndex:0] atIndex:0]; [points addObject:[points lastObject]];
UIBezierPath *smoothedPath = [path copy]; [smoothedPath removeAllPoints]; [smoothedPath moveToPoint:POINT(0)];
for (NSUInteger index = 1; index < points.count - 2; index++) { CGPoint p0 = POINT(index - 1); CGPoint p1 = POINT(index); CGPoint p2 = POINT(index + 1); CGPoint p3 = POINT(index + 2);
for (int i = 1; i < granularity; i++) { // granularity 这里按照 20 粒度划分的 float t = (float) i * (1.0f / (float) granularity); float tt = t * t; float ttt = tt * t;
CGPoint pi; // 根据 CatmullRom 公式 根据 P0 P1 P2 P3 获取点的坐标 pi.x = 0.5 * (2*p1.x+(p2.x-p0.x)*t + (2*p0.x-5*p1.x+4*p2.x-p3.x)*tt + (3*p1.x-p0.x-3*p2.x+p3.x)*ttt); pi.y = 0.5 * (2*p1.y+(p2.y-p0.y)*t + (2*p0.y-5*p1.y+4*p2.y-p3.y)*tt + (3*p1.y-p0.y-3*p2.y+p3.y)*ttt); if (pi.x <= self.width) { [smoothedPath addLineToPoint:pi]; } }
if (p2.x <= self.width) { [smoothedPath addLineToPoint:p2]; } }
return smoothedPath;}
复制代码


对比总结:


方案一 控制点的选取比较难,曲线的弯度 也取决于控制点,操作简单,易理解。


方案二 曲线更顺滑,但实现更复杂,不易理解。


这里推荐两个好用的网站:


a 这个网站提供了丰富的曲线类型可供选择,非常直观。


http://easings.net


b 这个网站提供了可视化的修改两个控制点,来生成一条三阶贝塞尔曲线,并切右边还可以看到这条曲线产生的动画会做怎样的速度改变。


http://www.roblaplaca.com/examples/bezierBuilder/#

3 显示

当 layer 与贝塞尔曲线相遇,会发生什么样的神奇反应?

3.1 CALayer

苹果官网注释:“An object that manages image-based content and allows you to perform animations on that content.” 管理基于图像的内容并允许您对该内容执行动画的对象。


CALayer 主要就两方面作用:


1) 管理展示内容


2)内容可执行动画


CALayer 自身有很多情况下自带隐式动画,但是 UIView 的根 Layer 是没有隐式动画的。

3.1.1 常用属性

// 图层大小 支持隐式动画@property CGRect bounds;// 图层位置 支持隐式动画@property CGPoint position;// 在z轴上的位置 支持隐式动画@property CGFloat zPosition;// 沿z轴位置的锚点 支持隐式动画@property CGFloat anchorPointZ;// 锚点 默认在layer的中心点 取值范围(0~1) 支持隐式动画@property CGPoint anchorPoint;// 图层变换 支持隐式动画@property CATransform3D transform;// 图层大小和位置 不支持隐式动画@property CGRect frame;// 是否隐藏 支持隐式动画@property(getter=isHidden) BOOL hidden;// 图层背景是否显示 支持隐式动画@property(getter=isDoubleSided) BOOL doubleSided;// 父图层 支持隐式动画@property(nullable, readonly) CALayer *superlayer;// 子图层 支持隐式动画@property(nullable, copy) NSArray<__kindof CALayer *> *sublayers;// 子图层变换 支持隐式动画@property CATransform3D sublayerTransform;// 图层蒙版 支持隐式动画@property(nullable, strong) __kindof CALayer *mask;// 子图层是否裁切超出父图层的部分,默认为NO@property BOOL masksToBounds;// 图层显示内容 设置layer的contents可以为layer添加显示内容 支持隐式动画@property(nullable, strong) id contents;// 图层显示内容的大小和位置 支持隐式动画@property CGRect contentsRect;// 用于指定层的内容如何在其范围内定位或缩放@property(copy) CALayerContentsGravity contentsGravity;// 是否包含完全不透明内容的布尔值@property(getter=isOpaque) BOOL opaque;// 背景色 支持隐式动画@property(nullable) CGColorRef backgroundColor;// 圆角半径 支持隐式动画@property CGFloat cornerRadius;// 边框宽度 支持隐式动画@property CGFloat borderWidth;// 边框颜色 支持隐式动画@property(nullable) CGColorRef borderColor;// 透明度 支持隐式动画@property float opacity;// 阴影颜色 支持隐式动画@property(nullable) CGColorRef shadowColor;// 阴影透明度 默认为0 需要显示阴影 必须设置值 支持隐式动画@property float shadowOpacity;// 阴影偏移量 支持隐式动画@property CGSize shadowOffset;// 阴影半径 支持隐式动画@property CGFloat shadowRadius;// 阴影形状 支持隐式动画@property(nullable) CGPathRef shadowPath;
复制代码

3.1.2 子类


CALayer 的子类有很多,下面说几个比较常用的。

3.2 CAShapeLayer

苹果官网注释:“A layer that draws a cubic Bezier spline in its coordinate space.” 专门用于绘制贝塞尔曲线的 layer。

3.2.1 看一下它独特的属性:

// path属性是曲线的路径,也是它和贝塞尔曲线紧密连接一个入口,决定了图层上画的是什么形状。@property(nullable) CGPathRef path;// 填充颜色@property(nullable) CGColorRef fillColor;// 曲线 指定哪块区域为内部,内部会被填充颜色@property(copy) CAShapeLayerFillRule fillRule;// 线的颜色@property(nullable) CGColorRef strokeColor;// strokeStart 和 strokeEnd 两者的取值都是0~1,决定贝塞尔曲线的划线百分比@property CGFloat strokeStart;@property CGFloat strokeEnd;// 虚线开始的位置@property CGFloat lineDashPhase;// 虚线设置,数组中奇数位实线长度,偶数位带遍空白长度@property(nullable, copy) NSArray<NSNumber *> *lineDashPattern;// 线的宽度@property CGFloat lineWidth;// 最大斜接长度 只有lineJoin属性为kCALineJoinMiter时miterLimit才有效@property CGFloat miterLimit;// 线端点样式(样式与 贝塞尔曲线的CGLineCap 属性一致)@property(copy) CAShapeLayerLineCap lineCap;// 拐角样式(样式与 贝塞尔曲线的CGLineJoin 属性一致)@property(copy) CAShapeLayerLineJoin lineJoin;
复制代码

3.2.2 举个栗子🌰

使用上面的一些属性,再结合贝塞尔曲线,我们实现了如下一些效果:



其中图五的效果,代码实现如下:


UIBezierPath *maskPath = [UIBezierPath bezierPath];for (NSInteger i = 1; i < 9; i++) {    UIBezierPath *tempPath = [UIBezierPath bezierPathWithRect:CGRectMake(190 - 20 * i, 550 - 10 * i, 40 * i, 20 * i)];    [maskPath appendPath:tempPath];}[maskPath stroke];
// CAShapeLayerCAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];maskLayer.frame = self.view.bounds;maskLayer.path = maskPath.CGPath;maskLayer.lineWidth = 5;maskLayer.strokeColor = [UIColor purpleColor].CGColor;maskLayer.fillRule = kCAFillRuleEvenOdd;maskLayer.fillColor = [UIColor cyanColor].CGColor;maskLayer.strokeStart = 0.2;maskLayer.strokeEnd = 0.5;maskLayer.lineDashPattern = @[@(10), @(10), @(30), @(30)];maskLayer.lineDashPhase = 0;[self.view.layer addSublayer:maskLayer];
复制代码

3.3 CAGradientLayer

苹果官网注释:“A layer that draws a color gradient over its background color, filling the shape of the layer (including rounded corners)” 专门用于在背景色上绘制颜色渐变的图层,填充图层的形状。

3.3.1 看一下它独特的属性:

// colors属性是CAGradientLayer的特殊属性,完美实现几种颜色的过渡。@property(nullable, copy) NSArray *colors;// 定义每个梯度停止的位置。取值范围为0~1递增@property(nullable, copy) NSArray<NSNumber *> *locations;// 决定了变色范围的起始点@property CGPoint startPoint;// 决定了变色范围的结束点@property CGPoint endPoint;// startPoint 和 endPoint两者的连线决定变色的趋势
复制代码

3.3.2 举个栗子🌰

使用上面的一些属性我们实现了如下一些效果:



其中图五的效果,代码实现如下:


CAGradientLayer *gradientLayer = [CAGradientLayer layer];gradientLayer.frame = CGRectMake(20, 450, 150, 150);gradientLayer.locations = @[@(0.2), @(0.5), @(0.6), @(0.8)];gradientLayer.startPoint = CGPointMake(0, 0);gradientLayer.endPoint = CGPointMake(1, 1);gradientLayer.colors = @[(id)[UIColor purpleColor].CGColor, (id)[UIColor greenColor].CGColor, (id)[UIColor orangeColor].CGColor, (id)[UIColor blackColor].CGColor];[self.view.layer addSublayer:gradientLayer];
复制代码

3.4 再举个栗子🌰🌰

当 CAGradientLayer + CAShapeLayer + 贝塞尔曲线 会有什么效果?上代码~


- (void)setupUI {    // 贝塞尔曲线    UIBezierPath *maskPath = [UIBezierPath bezierPath];    [maskPath moveToPoint:CGPointMake(100, 220)];    [maskPath addLineToPoint:CGPointMake(200, 150)];    [maskPath addLineToPoint:CGPointMake(300, 220)];    [maskPath stroke];
UIBezierPath *maskBottomPath = [UIBezierPath bezierPath]; [maskBottomPath moveToPoint:CGPointMake(280, 250)]; [maskBottomPath addCurveToPoint:CGPointMake(120, 250) controlPoint1:CGPointMake(250, 320) controlPoint2:CGPointMake(150, 320)]; [maskBottomPath stroke];
[maskPath appendPath:maskBottomPath];
// CAShapeLayer CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init]; maskLayer.frame = self.view.bounds; maskLayer.path = maskPath.CGPath; maskLayer.lineWidth = 20; maskLayer.strokeColor = UIColorFromRGB(0xF0F5FF).CGColor; maskLayer.lineCap = kCALineCapRound; maskLayer.lineJoin = kCALineJoinRound; maskLayer.fillColor = [UIColor clearColor].CGColor; maskLayer.strokeStart = 0; maskLayer.strokeEnd = 0; [self.view.layer addSublayer:maskLayer];
// CAGradientLayer NSMutableArray *colorArray = [NSMutableArray new]; for (NSInteger i = 0; i < 6; i++) { [colorArray addObject:[self arc4randomColor]]; }
CAGradientLayer *gradientLayer = [CAGradientLayer layer]; gradientLayer.frame = self.view.bounds; gradientLayer.colors = colorArray; gradientLayer.startPoint = CGPointMake(0, 0.5); gradientLayer.endPoint = CGPointMake(1, 0.5); gradientLayer.mask = maskLayer; [self.view.layer addSublayer:gradientLayer];
// 创建全局并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 创建定时器 dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); // 设置定时器,每N秒触发 int64_t intervalInNanoseconds = (int64_t)(0.3 * NSEC_PER_SEC); dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), (uint64_t)intervalInNanoseconds, 0); // 设置定时器处理事件 dispatch_source_set_event_handler(timer, ^{ dispatch_async(dispatch_get_main_queue(), ^{
if (maskLayer.strokeEnd < 0.6) { maskLayer.strokeEnd += 0.4; } else if (maskLayer.strokeEnd < 0.8){ maskLayer.strokeEnd += 0.2; } else if (maskLayer.strokeEnd < 1){ maskLayer.strokeEnd += 0.1; } else { maskLayer.strokeEnd = 1; if (maskLayer.strokeStart < 0.6) { maskLayer.strokeStart += 0.4; } else if (maskLayer.strokeStart < 0.8){ maskLayer.strokeStart += 0.2; } else if (maskLayer.strokeStart < 1){ maskLayer.strokeStart += 0.1; } else { [colorArray removeObjectAtIndex:0]; [colorArray addObject:[self arc4randomColor]]; gradientLayer.colors = colorArray;
maskLayer.strokeStart = 0; maskLayer.strokeEnd = 0; } } }); });
_timer = timer;
// 开启定时器 dispatch_resume(_timer);}
- (id)arc4randomColor { return (id)[UIColor colorWithRed:arc4random()%255/255.f green:arc4random()%255/255.f blue:arc4random()%255/255.f alpha:1].CGColor;}
复制代码


运行结果👇


<https://v.qq.com/x/page/l3146iykm06.html


其他 layer 怎么使用?贝塞尔曲线 + Layer 还可以组合出更多神奇的反应!感兴趣的可以去试试哦~本文仅为抛砖引玉~~


本文转载自公众号贝壳产品技术(ID:beikeTC)。


原文链接


贝塞尔曲线在iOS端的绘图实践


2020-09-15 10:084127

评论

发布
暂无评论
发现更多内容

面试突击47:死锁产生的原因有哪些?

王磊

Java 面试 java面试

万亿储能的极限拉力赛

钛禾产业观察

投稿开奖丨云服务器ECS征文活动(2&3月)奖励公布

阿里云弹性计算

云服务器 征文投稿开奖 玩转ECS

web技术支持| Web 客户端实现录音、录像

anyRTC开发者

前端 Web 音视频 WebRTC 视频通话

MySQL__数据处理之查询

编程江湖

告诉你使用预约小程序的9个理由

天天预约

小程序 SaaS 企业服务 预约工具

赵海鹏:如何进行OpenHarmony音频特性架构设计和开发工作

OpenHarmony开发者

OpenHarmony 开发者故事 开发者说

极狐GitLab入驻阿里云计算巢,共同提升云上开发体验

阿里云弹性计算

DevOps 计算巢

为了让女朋友运动起来,小伙儿不仅买单车还设计了智能防盗单车锁

华为云开发者联盟

stm32 华为云IoT 智能防盗单车锁 蓝牙

得物技术消息中间件应用的常见问题与方案

得物技术

kafka 分布式 MQ 中间件 消息队列

案例分享|智慧广电的“宽带加速”之路,博睿数据来“私人定制”

博睿数据

数字化转型 博睿数据 智慧广电

记一次存储系统IOPS翻倍的性能优化

Vincent

性能优化 存储系统

趣学设计模式-代理模式

ZuccRoger

5月月更

TiDB 6.0 新特性解读丨 Collation 规则

PingCAP

位运算小妙招-求二进制序列中1的个数

芒果酱

c++ C语言 5月月更

互联网用户画像,精准营销,数仓有妙招

华为云开发者联盟

位图 GaussDB(DWS) 用户画像 精准营销 Roaringbitmap

姐姐驾到 | 零基础小白如何学前端!

锋享前端

如何真正将企业知识管理做出价值?

小炮

企业知识管理

数据湖揭秘—Delta Lake

阿里云大数据AI技术

sql spark 分布式计算 关系型数据库 存储

JAVA异常情况如何处理?

源字节1号

后端开发

5 月 20 日,API 网关 Apache APISIX Summit ASIA 2022 重磅来袭

API7.ai 技术团队

开源 API网关 Apache APISIX APISIX 网关 APISIX Summit

vue 自从使用了组件,工作量减去了一半

CRMEB

明道云入选爱分析2022年两份低代码研究报告

明道云

SAP 订单模型的编排方式概述

汪子熙

订单管理 订单 5月月更 b2b 编排系统

2021年证券类APP更新迭代检测专题分析(上)发布

易观分析

金融 券商App

博云:Kubernetes 近年影响最大版本发布,这几点值得关注

BoCloud博云

Kubetnetes

存储卷指标消失之谜 | K8S Internals 系列第二期

BoCloud博云

Kubernetes kubelet

让客户实现 AI 算力“自由”,博云与趋动科技完成算力调度容器化验证

BoCloud博云

AI

直播预告|争夺存量用户关键战,助力企业构建完美标签体系

袋鼠云数栈

大数据 数据中台

贝塞尔曲线在iOS端的绘图实践_大数据_孙齐_InfoQ精选文章