精华内容
下载资源
问答
  • Ameba Canvas 是一个用于快速重绘的画布元素优化器。 安装 请通过以下命令构建项目(需要 Grunt)。 编译后的 JS 文件位于/js/ameba-canvas.js $ npm install $ grunt build 用法 Ameba Canvas 使用策略模式来管理...
  • 重绘、回流和图层 在前面的学习中,我们知道浏览器在渲染一个页面的过程是这样的: 解析HTML构建DOM树 渲染引擎使用HTML解析器(调用XML解析器)解析HTML(XML)文档,将各个HTML(XML)元素逐个转化成DOM节点,...

    重绘、回流和图层

    在前面的学习中,我们知道浏览器在渲染一个页面的过程是这样的:

    1. 解析HTML构建DOM树

      渲染引擎使用HTML解析器(调用XML解析器)解析HTML(XML)文档,将各个HTML(XML)元素逐个转化成DOM节点,从而生成DOM树。

      接着渲染引擎使用CSS解析器解析外部CSS文件及style标签中的样式信息,构建出CSSOM 树。

    2. 构建渲染树

      渲染引擎使用上一步CSS解析器解析得到的样式规则,将其附着到DOM树上,从而构成渲染树,其实就是讲DOM树和CSSOM树合并成渲染树。

    3. 布局渲染树

      渲染树构建完毕之后,进入布局阶段,也就是为每个节点分配一个应出现在屏幕上的确切坐标。

    4. 绘制render树

      渲染引擎将遍历渲染树,并调用显示后端将每个节点绘制出来。

    在这里插入图片描述

    在整个页面被渲染的过程中,最后两个步骤是: layout(布局) 和 paint (绘制)。

    重绘

    其实就是触发浏览器的 paint 的过程。

    只触发重绘的样式:

    样式属性名 样式属性名 样式属性名
    color background outline-color
    border-style background-image outline
    border-radius background-position outline-style
    visibility background-repeat outline-width
    text-decoration background-size box-shadow

    回流

    其实不仅仅是触发了 paint 的过程还触发 layout 的过程,所以回流必定触发重绘

    能触发回流的样式:

    样式属性名 样式属性名 样式属性名
    width top text-align
    height bottom overflow-y
    padding left font-weight
    margin right overflow
    display position font-family
    border-width float line-height
    border clear vertival-align
    min-height font-size white-space

    能触发回流的JS操作

    JS属性或者方法 JS属性或者方法 JS属性或者方法 JS属性或者方法 JS属性或者方法
    offsetTop scrollTop clientTop width getComputedStyle()
    offsetLeft scrollLeft clientLeft height IE的:currentStyle
    offsetWidth scrollWidth clientWidth getBoundingClientRect()
    offsetHeight scrollHeight clientHeight

    另外,只要是获取元素位置相关的操作,都会触发回流。

    可以避免重绘和回流的方式是启用CSS的硬件加速,硬件加速其实就是GPU加速,可以触发硬件加速的css属性有:

    样式属性名 样式属性名 样式属性名 样式属性名
    transform opacity filters Will-change

    图层(Layer)

    浏览器的渲染策略是分层的,当遇到会增加图层的标签的时候,浏览器会生成一个新的图层(比如:div、canvas等),之后该元素内的重绘和回流的过程只存在于该图层中。之后再进行图层的合并,这样重绘和回流的效率就会提高,但是会增加一个图层的合并过程。

    优化思路

    明白了重绘和回流等知识,我们的优化思路其实就有了,其实就是:减少重绘和回流,因此我们以下几个地方入手:

    1. 在布局上可以使用:translate替代top/left…、opacity替代visibility
    2. 操作DOM的时候
      • 不要一条一条地修改 DOM 的样式,预先定义好 class,然后修改 DOM 的 className,可以减少重绘和回流的次数
      • 不要把 DOM 结点的属性值放在一个循环里当成循环里的变量,这将会导致页面一直处于回流的过程
      • 不要使用 table 布局,因为你改动一点点都将影响整个 table 的布局
      • 对于动画,放到新建的图层中进行,这样重绘和回流就都只在该图层中进行
      • 尽量少用JS去操作布局
    展开全文
  • Android使用Canvas绘图

    万次阅读 2015-11-01 22:43:45
    自定义圆形进度条前言Android自定义控件经常会用到Canvas绘制2D图形,在优化自己自定义控件技能之前,必须熟练掌握Canvas绘图机制。本文从以下三个方面对Canvas绘图机制进行讲解: 画布Canvas 画笔Paint 示例圆形...

    目录


    前言

    Android自定义控件经常会用到Canvas绘制2D图形,在优化自己自定义控件技能之前,必须熟练掌握Canvas绘图机制。本文从以下三个方面对Canvas绘图机制进行讲解:

    • 画布Canvas
    • 画笔Paint
    • 示例圆形进度条

    画布Canvas

    首先,来看一下Android官网对Canvas类的定义:

    The Canvas class holds the “draw” calls。To draw something, you need 4 basic components: A Bitmap to hold the pixels, a Canvas to host the draw calls(writing into the bitmap), a drawing primitive(eg, Rect, Path, text, Bitmap), and a paint(to describe the colors and styles for the drawing).

    简单来说,Android进行2D绘图必须要有Canvas类的支持,它位于“android.graphics.Canvas”包下。我们可以把Canvas理解成系统分配给我们的一块用于绘图的内存(ps:真正的内存是其包含的Bitmap)。

    Canvas提供了两个构造函数:

    1. Canvas() : 创建一个空的Canvas对象。
    2. Canvas(Bitmap bitmap) : 创建一个以bitmap位图为背景的Canvas。

    通常,我们会采用第二种包含Bitmap参数的构造函数方式或者直接使用onDraw方法中系统提供的Canvas。

    既然Canvas主要用于绘图,那么它提供了很多相应的draw方法,方便我们在Canvas对象上绘图,介绍几个常用的draw方法:

    • void drawRect(RectF rect, Paint paint) : 绘制区域,参数为RectF的区域。
    • void drawOval(RectF oval, Paint paint) : 绘制矩形的内切椭圆。
    • void drawCircle(float cx, float cy, float radius, Paint paint) : 绘制圆形。cx和cy是圆心坐标,radius是半径长度。
    • void drawArc(RectF oval, float startAngle, float sweepAngle. boolean useCenter, Paint paint) : 绘制圆弧形,也是以矩形的内切椭圆为标准。其中,startAngle为起始角度,sweepAngle为弧度大小,useCenter为true,则是绘制一个扇行,为false,则只是一段圆弧。(ps:startAngle为0时,是圆形钟表3点钟方向)。
    • void drawPath(Path path, Paint paint) : 根据给定的path,绘制连线。
    • void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) : 贴图,参数bitmap是要进行绘制的bitmap对象,参数src是指bitmap的源区域(一般为null),dst是bitmap的目标区域,paint是画笔,可为null。
    • void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) : 根据给定的起点和结束点之间绘制连线。
    • void drawPoint(float x, float y, Paint paint) : 根据给定的坐标,绘制点。
    • void drawText(String text, float x, float y, Paint paint) : 根据给定的坐标,绘制文字。其中,x是文本起始的x轴坐标,y是文本纵向结束的y轴坐标。

    画笔Paint

    从上面列举的几个Canvas.drawXXX()方法可以看到,其中都有一个类型为Paint的参数,可以把它理解成为”画笔”,通过这个画笔,在Canvas这张画布上作画。它位于“android.graphics.Paint”包下,主要用于设置绘图风格,包括画笔颜色。

    Paint中提供了大量设置绘画风格的方法,这里仅列出一些常用的功能:

    • setARGB(int a, int r, int g, int b) : 设置ARGB颜色。
    • setColor(int color) : 设置颜色。
    • setAlpha(int a) : 设置透明度。
    • setAntiAlias(boolean aa) : 设置是否抗锯齿。
    • setShader(Shader shader) : 设置Paint的填充效果。
    • setStrokeWidth(float width) : 设置Paint的笔触宽度。
    • setStyle(Paint.Style style) : 设置Paint的填充风格。
    • setTextSize(float textSize) : 设置绘制文本时的文字大小。

    自定义圆形进度条

    这里以一个自定义的圆形进度条为例,我们首先看一下效果图:
    round_progressbar

    通过效果图,我们首先抽象出自定义属性,如下:

    • 圆环内部填充色。
    • 圆环进度条的背景色。
    • 圆环进度条的颜色。
    • 圆环半径。
    • 圆环进度条的宽度。
    • 进度条起始的角度。
    • 中间文字的颜色。
    • 中间文字的大小。
    • 中间文字是否需要显示的标志位。

    在Android中,可以在项目的res/values/目录下,建立一个resources源文件,通过declare-styleable来声明一个特定的属性集合。

    示例属性集合如下所示(res/values/attrs_round_progress_bar.xml):

    <resources>
        <declare-styleable name="RoundProgressBar">
            <attr name="startAngle" format="integer"></attr>
            <attr name="radius" format="dimension"></attr>
            <attr name="ringWidth" format="dimension"></attr>
            <attr name="centerColor" format="color"></attr>
            <attr name="ringColor" format="color"></attr>
            <attr name="progressColor" format="color"></attr>
            <attr name="textSize" format="dimension"></attr>
            <attr name="textColor" format="color"></attr>
            <attr name="isTextDisplay" format="boolean"></attr>
        </declare-styleable>
    </resources>

    自定义的属性可以在自定义View的构造函数中,通过TypedArray数组获取,我们来自定义一个圆形的View来实现上图的效果(RoundProgressBar.java):

    package love.com.progressbar.view;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.RectF;
    import android.graphics.Typeface;
    import android.util.AttributeSet;
    import android.util.TypedValue;
    import android.view.View;
    
    import love.com.progressbar.R;
    
    
    public class RoundProgressBar extends View {
        private static final int START_ANGLE = -90;
        private static final String CENTER_COLOR = "#eeff06";
        private static final String RING_COLOR = "#FF7281E1";
        private static final String PROGRESS_COLOR = "#FFDA0F0F";
        private static final String TEXT_COLOR = "#FF000000";
        private static final int TEXT_SIZE = 30;
        private static final int CIRCLE_RADIUS = 20;
        private static final int RING_WIDTH = 5;
    
        /**
         * 圆弧的起始角度,参考canvas.drawArc方法
         */
        private int startAngle;
    
        /**
         * 圆形内半径
         */
        private int radius;
    
        /**
         * 进度条的宽度
         */
        private int ringWidth;
    
        /**
         * 默认进度
         */
        private int mProgress = 0;
    
        /**
         * 圆形内部填充色
         */
        private int centerColor;
    
        /**
         * 进度条背景色
         */
        private int ringColor;
    
        /**
         * 进度条的颜色
         */
        private int progressColor;
    
        /**
         * 文字大小
         */
        private int textSize;
    
        /**
         * 文字颜色
         */
        private int textColor;
    
        /**
         * 文字是否需要显示
         */
        private boolean isTextDisplay;
    
        private String textContent;
    
        private Paint mPaint;
    
        public RoundProgressBar(Context context) {
            this(context, null);
        }
    
        public RoundProgressBar(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public RoundProgressBar(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
    
            // 获取自定义属性
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundProgressBar);
            for (int i = 0; i < a.length(); i ++) {
                int attr = a.getIndex(i);
                switch (attr) {
                    case R.styleable.RoundProgressBar_startAngle:
                        startAngle = a.getInteger(attr, START_ANGLE);
                        break;
                    case R.styleable.RoundProgressBar_centerColor:
                        centerColor = a.getColor(attr, Color.parseColor(CENTER_COLOR));
                        break;
                    case R.styleable.RoundProgressBar_progressColor:
                        progressColor = a.getColor(attr, Color.parseColor(PROGRESS_COLOR));
                        break;
                    case R.styleable.RoundProgressBar_ringColor:
                        ringColor = a.getColor(attr, Color.parseColor(RING_COLOR));
                        break;
                    case R.styleable.RoundProgressBar_textColor:
                        textColor = a.getColor(attr, Color.parseColor(TEXT_COLOR));
                        break;
                    case R.styleable.RoundProgressBar_textSize:
                        textSize = (int) a.getDimension(attr, TypedValue.applyDimension(
                                TypedValue.COMPLEX_UNIT_SP, TEXT_SIZE,
                                getResources().getDisplayMetrics()));
                        break;
                    case R.styleable.RoundProgressBar_isTextDisplay:
                        isTextDisplay = a.getBoolean(attr, true);
                        break;
                    case R.styleable.RoundProgressBar_radius:
                        radius = (int) a.getDimension(attr, TypedValue.applyDimension(
                                TypedValue.COMPLEX_UNIT_DIP, CIRCLE_RADIUS,
                                getResources().getDisplayMetrics()
                        ));
                        break;
                    case R.styleable.RoundProgressBar_ringWidth:
                         ringWidth = (int) a.getDimension(attr, TypedValue.applyDimension(
                                TypedValue.COMPLEX_UNIT_DIP, RING_WIDTH,
                                getResources().getDisplayMetrics()
                        ));
                        break;
                    default:
                        break;
                }
            }
            a.recycle();
    
            // 初始化画笔设置
            setPaint();
        }
    
        private void setPaint() {
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            // 获取圆心坐标
            int cx = getWidth() / 2;
            int cy = cx;
    
            /**
             * 画圆心颜色
             */
            if (centerColor != 0) {
                drawCenterCircle(canvas, cx, cy);
            }
    
            /**
             * 画外层大圆
             */
            drawOuterCircle(canvas, cx, cy);
    
            /**
             * 画进度圆弧
             */
            drawProgress(canvas, cx, cy);
    
            /**
             * 画出进度百分比
             */
            drawProgressText(canvas, cx, cy);
        }
    
        private void drawProgressText(Canvas canvas, int cx, int cy) {
            if (!isTextDisplay) {
                return;
            }
            mPaint.setColor(textColor);
            mPaint.setTextSize(textSize);
            mPaint.setTypeface(Typeface.DEFAULT_BOLD);
            mPaint.setStrokeWidth(0);
            textContent = getProgress() + "%";
            float textWidth = mPaint.measureText(textContent);
            canvas.drawText(textContent, cx - textWidth / 2, cy + textSize / 2, mPaint);
        }
    
        private void drawProgress(Canvas canvas, int cx, int cy) {
            mPaint.setColor(progressColor);
            mPaint.setStrokeWidth(ringWidth);
            mPaint.setStyle(Paint.Style.STROKE);
            RectF mRectF = new RectF(cx - radius, cy - radius, cx + radius, cy + radius);
            float sweepAngle = (float) (mProgress * 360.0 / 100);
            canvas.drawArc(mRectF, startAngle, sweepAngle, false, mPaint);
        }
    
        private void drawOuterCircle(Canvas canvas, int cx, int cy) {
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setColor(ringColor);
            mPaint.setStrokeWidth(ringWidth);
            canvas.drawCircle(cx, cy, radius, mPaint);
        }
    
        private void drawCenterCircle(Canvas canvas, int cx, int cy) {
            mPaint.setColor(centerColor);
            mPaint.setStyle(Paint.Style.FILL);
            canvas.drawCircle(cx, cy, radius, mPaint);
        }
    
    
        public synchronized int getProgress() {
            return mProgress;
        }
    
        public synchronized void setProgress(int progress) {
            if (progress < 0) {
                progress = 0;
            } else if (progress > 100) {
                progress = 100;
            }
            mProgress = progress;
            // 进度改变时,需要通过invalidate方法进行重绘
            postInvalidate();
        }
    }

    在MainActivity.java的布局文件中,可以这样调用圆形进度条:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:round="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <love.com.progressbar.view.RoundProgressBar
            android:id="@+id/id_round_progressbar"
            android:layout_width="400dp"
            android:layout_height="400dp"
            round:radius="100dp"
            round:ringWidth="20dp"
            round:startAngle="-90"
            round:centerColor="#eeff06"
            round:ringColor="#e16556e6"
            round:progressColor="#d20c0c"
            round:textColor="#000000"
            round:textSize="20sp"
            round:isTextDisplay="true"/>
    </RelativeLayout>

    其中,xmlns:round=”http://schemas.android.com/apk/res-auto是Android Studio中增加的导入自定义View属性的命名空间写法。

    展开全文
  • 题记:web开发经常会听到回流和重绘这两个词,最近看了一些文档,简单记录下自己对这两个概念的理解以及怎么尽可能避免回流和重绘,提高页面渲染速度。 概念 回流: 浏览器的渲染过程中,计算DOM节点在视口内的...

    题记:web开发经常会听到回流和重绘这两个词,最近看了一些文档,简单记录下自己对这两个概念的理解以及怎么尽可能避免回流和重绘,提高页面渲染速度。

    概念

    • 回流
      浏览器的渲染过程中,计算DOM节点在视口内的显示/隐藏,确切位置和大小,这个计算的阶段就是回流。

    • 重绘
      是一个元素外观的改变(自身的宽高,布局,及显示或隐藏没有改变)所触发的浏览器行为,例如改变vidibility、background-color等属性。浏览器会根据元素的新属性重新绘制,这个阶段就是重绘。

    • 根据两个的概念我们可以得出:

    回流必定触发重绘,而重绘不一定触发回流

    优化回流和重绘

    • 减少回流和重绘的次数
    <style type="text/css">
         .change { width: 10px; height: 10px; }
    </style>
    <script type="text/javascript">
         $(document).ready(function () {
             var el = $('#id');
             //1
             el.css('width', '10px');
             el.css('height', '10px');
             //2
             el.addClass('change');
             //3
             el.style.cssText += 'width: 10px; height: 10px;';
         });
    </script>
    

    以上3种做法,我这里弱弱的推荐第2,3种,避免第1种。

    • 限制回流和重绘的范围
      先说说图层吧

    css 中有一个重要的概念的就是 “划分图层”。

    在页面加载完dom之后,浏览器会根据自身制定的一些特殊css 属性对页面进行划分为一个个图层。例如:一些有着 position: absolute 属性的元素他们会被浏览器归纳到一个图层中,而另外一些 position: fixed 的元素也会被浏览器归纳到另外一个图层中,还有一些例如:transform: translateZ(0)… 这些属性都是视浏览器厂商制定的

    图层的优点就是:当一个元素在自己图层内发生变化的时候它的回流和重绘只会在图层内部发生,从而减少了浏览器对于重绘与回流的运算量。

    那图层内部究竟干了什么呢?

    首先,图层对图层里面的节点做回流和重布局运算,计算出他们的样式

    然后,对它们生成图形和位置

    紧跟着,将每个节点绘制填充到图层位图中

    再然后,图层作为纹理发送到GPU 上

    最后,将所有图层合并,显示在浏览器的页面上

    图层虽好,但是如果滥用图层的话就会让页面因为进行了太多合并运算导致页面卡顿。

    所以说,图层的用途应该让给那些经常要进行位置结构,布局变换的元素去使用。例如轮播图

    那我们如创建一个图层呢?

    就拿chrome 来说,创建一个图层要有以下其中一个条件:

    1:一个dom 元素拥有 3d 或 透视变换的css 属性(persepective, transform)

    2:video 标签

    3:拥有3d 上下文或加速 2d 上下文的 canvas 节点

    4:混合插件 flash

    5:自己做的opacity 动画 或 使用一个动画 webkit 变换的元素

    6:拥有 translate3d 或 translateZ 这两会使 GPU 加速的属性

    7:一个包含复合层子节点的元素。(有点绕,可以这样想:其实本身整个网页页面就是一个图层,html 标签下包含着若干的标签 head, body,… 这样便满足了这个条件了)

    8:元素有一个其 z-index 比它低的兄弟节点。由于 z-index 控制的是元素上下层的关系,所以当上下层关系变换的时候就需要一个图层去渲染,因此满足这个条件的元素也会被创建一个图层

    但是在我的实验中发现第7 和 8是没有被变成图层的,不知道为嘛…

    那如果我们使用属性又有那些可替换的属性可以优化回流与重绘呢
    一共有以下9点:

    1. 用transform 代替 top,left ,margin-top, margin-left… 这些位移属性

    2. 用opacity 代替 visibility,但是要同时有translate3d 或 translateZ
      这些可以创建的图层的属性存在才可以阻止回流 但是第二点经过我的实验,发现如果不加 transform: translateZ(0)
      配合opacity的话还是会产生回流的,而只用visibility 就只会产生重绘不会回流,而 opacity 加上
      transform: translateZ/3d 这个属性之后便不会发生回流和重绘了

    3. 不要使用 js 代码对dom
      元素设置多条样式,选择用一个 className 代替之。

    4. 如果确实需要用 js 对 dom 设置多条样式那么可以将这个dom
      先隐藏,然后再对其设置

    5. 不要在循环内获取dom 的样式例如:offsetWidth, offsetHeight,
      clientWidth, clientHeight…这些。浏览器有一个回流的缓冲机制,即多个回流会保存在一个栈里面,当这个栈满了浏览器便会一次性触发所有样式的更改且刷新这个栈。但是如果你多次获取这些元素的实际样式,浏览器为了给你一个准确的答案便会不停刷新这个缓冲栈,导致页面回流增加。所以为了避免这个问题,应该用一个变量保存在循环体外。

    6. 不要使用table 布局,因为table 的每一个行甚至每一个单元格的样式更新都会导致整个table 重新布局

    7. 动画的速度按照业务按需决定

    8. 对于频繁变化的元素应该为其加一个 transform 属性,对于视频使用video 标签

    9. 必要时可以开启 GPU 加速,但是不能滥用

    展开全文
  • 位图:支持更多像素但放大会模糊 canvas 矢量图: 放大依旧很清晰 svg canvas默认大小300*150 标签上设置height和width来设置大小 1.获取canvas标签,并设置绘制环境 let c1=document.getElementById(‘c1’) let ...
    • 首次使用canvas绘图
    • 删除画布区域 重绘
    • 绘制边框 填充图形 修改样式(作用域)
    • 插入图片, 2d变换
    • 绘制圆 弧形
    • 像素及操作
    • 引入图片和视频
    • 覆盖模式
    • canvas动画 ,示例动画 (做canvas前先看看示例动画
    • 微信场景
    	// 建议这样绘制
          ctx.beginPath();
          ctx.save()
    	      ctx.setFontSize(28 * common);
    	      ctx.fillStyle = "#E9CA97"; // linear-gradient(#FFFFFF, #FDCA99)
    	      ctx.fillText('再住2间夜可升级为', 240 * common, 156 * common);
          ctx.restore()
    

    位图:支持更多像素但放大会模糊 canvas
    矢量图: 放大依旧很清晰 svg

    canvas默认大小300*150
    标签上设置height和width来设置大小

    1.获取canvas标签,并设置绘制环境
    let c1=document.getElementById(‘c1’)
    let ctx =c1.getContext(‘2d’) //有两种环境2d 3d是webgl
    2开始绘制
    绘制方块 x y w h默认黑色
    ctx.fillRect(100,100,100,100)
    绘制边框 默认黑色 大小1px(会从边框向两边平分像素)
    ctx.strokeRect(100.5,100.5,100,100)
    先写样式再写边框图形等
    ctx.lineWidth = 10
    ctx.strokeStyle =‘red’
    ctx.fillStyle = ‘black’ // 或者’rgba(255,0,0,255)’
    ctx.fillRect(100,100,100,100)
    ctx.strokeRect(100,100,100,100)

    绘制路径 绘制填充
    ctx.save()//开启作用域,不会对外部的起作用 restore结束作用域
    ctx.strokeStyle = ‘blue’
    ctx.beginPath()//(begainPath表示开始绘制一个新路径)baginPath和closePath用来包裹点,使每个路径不受填充的影响
    ctx.moveTo(100,100) //第一个点
    ctx.lineTo(200,200) //后续的点。。。
    ctx.lineTo(300,300)
    ctx.closePath()//closePath默认连接起点和终点
    ctx.stroke() //进行绘制 stroke() 方法会实际地绘制出通过 moveTo() 和 lineTo() 方法定义的路径
    //ctx.fill() //填充
    ctx.restore()

    删除一个矩形区域 删除画布
    删除矩形区域 x y w h
    ctx.clearRect(100,100,50,50)
    删除画布
    ctx.clearRect(0,0,c1.width,c1.height)//意思就是 (0,0)坐标点删除画布一样大小区域

    插入图片
    //创建img对象,加载成功后添加到canvas中
    let img = new Image()
    img.src=’./logo.png’
    img.οnlοad=function(){
    //三个参数时
    ctx.drewImg(img,100,100)
    //五个参数时
    // ctx.drewImg(img,100,100,50,50)//图片对象,图片偏移的xy坐标,图片在canvas中的大小
    // 九个参数
    ctx.drawImg(img,在图片的x坐标,在图片的y坐标,在图片的宽,在图片的高,100,100,50,50)
    }
    2d变换
    ctx.translate(100,100)
    ctx.rotate(45*Math.PI/180)//单位为弧度
    ctx.scale(2,0.5)//xy轴缩放比例
    绘制圆形 圆弧
    ctx.arc(圆心x坐标,圆心y坐标,圆半径,开始圆弧的弧度,结束圆弧的弧度,圆弧方向默认顺时针false可不写)
    //角度和弧度换算公式 1角度= Math.PI / 180
    //开始和结束圆弧的弧度相等时,绘制的是一条直线
    //0弧度的位置在整个圆的最右侧
    ctx.arc(200,200,100,0,90 * Math.PI/180,true)

    像素及操作
    获取像素点
    ctx.getImageData(x坐标,y坐标,获取像素区域的宽,获取像素区域的高)
    ctx.fillRct(50,50,100,100)
    let imgs = cxt.getImageData(50,50,100,100)
    // imgs.width imgs.height imgs.data//存储的是每个像素的rgba颜色值(所以是像素个数的4倍)
    设置新的像素
    ctx.putImageData(获取图片的像素,x,y)
    imgs.data[0] = 255
    imgs.data[1] = 0
    imgs.data[2] = 255
    imgs.data[3] = 125
    ctx.putImageData(imgs,50,50)
    生成像素矩阵
    ctx.createImageData(像素区域的宽,像素区域的高)
    let imgs = ctx.createImageData(100,100)
    console.log(imgs) // 默认全部都是黑色透明的像素点
    for(let i=0;i<imgs.data.length;i+=4){
    imgs.data[i] = ‘255’
    imgs.data[i+1] = ‘255’
    imgs.data[i+1] = ‘0’
    imgs.data[i+2] = ‘255’
    }
    ctx.putImageData(imgs,0,0)

    封装: 获取和设置指定位置的像素点
    // 在数组中的位置 = y*w+x
    function getXY(imgs,x,y){
       let w = imgs.data.width
       let d = imgs.data
       let color = []
       color[0] = d[ 4 * ( y * w +x ) ]
       color[1] = d[ 4 * ( y * w +x ) + 1]
       color[2] = d[ 4 * ( y * w +x ) + 2]
       color[3] = d[ 4 * ( y * w +x ) + 3]
      return color
    }
    
    function setXY(imgs,x,y,color){
      let w = imgs.data.width
       let d = imgs.data
       let color = []
       d[ 4 * ( y * w +x ) ] = color[0] 
       d[ 4 * ( y * w +x ) + 1] = color[1] 
       d[ 4 * ( y * w +x ) + 2] = color[2] 
       d[ 4 * ( y * w +x ) + 3] = color[3] 
    }
    
    

    canvas倒影(图片倒着渲染) canvas色彩公式(图片反色[256分别减去r g b ] 图片灰色[给r g b同时给 (r+b+c)/3]等效果) canvas视频操作
    canvas操作图片必须在服务器下(有跨域限制)
    c1.height = 800 c1.width=800
    // 要先改变画布大小再操作画布
    引入视频
    页面使用video标签拿到视频

    let c1 = document.getElementById('canvas')
        let video = document.getElementById('video')
        let ctx = c1.getContext('2d')
    
        video.addEventListener('canplaythrough', function () {
        c1.height = this.videoHeight
        c1.width = this.videoWidth
          let imgs = ctx.getImageData(0, 0, this.videoWidth, this.videoHeight)
          let newImgs = ctx.createImageData(this.videoWidth, this.videoHeight)
          ctx.drawImage(this, 0, 0)
          setInterval(() => {
            for (let i = 0; i < imgs.height; i++) {
              for (let j = 0; j < imgs.width; j++) {
                let color = getXY(imgs, j, i)
                color[3] = color[3] * (i / (imgs.height - 1))
                setXY(newImgs, j, imgs.height - 1 - i, color)
              }
            }
            ctx.putImageData(newImgs, 0, this.height)
            ctx.drawImage(this, 0, 0)
          }, 0)
        })
    
    

    源:新的图形 // 默认源图形覆盖在目标图形上
    目标: 已经绘制过的图形
    globalCompositeOperation可以设置不同的覆盖模式
    在这里插入图片描述

    canvas动画 = 定时器 + 重绘 + 收集数据
    // 示例动画

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
      <style>
        body {
          background-color: black;
        }
      </style>
    </head>
    
    <body>
    
      <canvas id="canvas" width="400" height="400" color="white">
        当前浏览器不支持canvas
      </canvas>
    
      <script>
    
        var c1 = document.getElementById("canvas");
        var ctx = canvas.getContext("2d");
        c1.fillStyle = 'rgba(0,0,0,255)'
        var data = [] // 一.1:数据收集
    
        // 实现运动的
        setInterval(() => { // 二.1:开启定时器
          // 二.2对数据进行变化
          for (let i = 0; i < data.length; i++) {
            data[i].r += 1
            data[i].c4 -= 0.01 // 半径递减0.01
            if (data[i].c4 <= 0) { // 优化性能,只保留前几十个
              data.splice(i, 1)
            }
          }
          console.log(data.length)
    
          ctx.clearRect(0, 0, c1.width, c1.height)  // 三:重绘
          for (let i = 0; i < data.length; i++) {
            ctx.fillStyle = `rgba(${data[i].c1},${data[i].c2},${data[i].c3},${data[i].c4})`
            ctx.beginPath()
            ctx.arc(data[i].x, data[i].y, data[i].r, 0, 360 * Math.PI / 180)
            ctx.closePath()
            ctx.fill()
          }
        }, 16)
    
        // 一.2  每个一段时间,将数据添加到集合当中
        setInterval(() => {
          data.push({
            x: Math.floor(Math.random() * 400),
            y: Math.floor(Math.random() * 400),
            r: 5,
            c1: Math.floor(Math.random() * 255),
            c2: Math.floor(Math.random() * 255),
            c3: Math.floor(Math.random() * 255),
            c4: 1
          })
        }, 500)
    
      </script>
    
    
    </body>
    
    </html>
    

    微信场景: 下面是(刮开新页面,自动播放音乐上下切屏)
    在这里插入图片描述
    在这里插入图片描述
    传送连接: 链接

    展开全文
  • 脏区重绘(dirty rectangle)并不是一门新鲜的技术了,这在最早2D游戏诞生的时候就已经存在。 复杂的术语或概念就不多说,简单说,脏区重绘就是每一帧绘制图形界面的时候,只重新绘制有变化的区域,而不是全屏刷新。...
  • 关于CSS重排和重绘的概念,最近看到不少这方面的文章,觉得挺有用,在制作中考虑浏览器的性能,减少重排能够节省浏览器对其子元素及父类元素的重新渲染;避免过分的重绘也能节省浏览器性能;优化动画,使用3D启用GPU...
  • 性能优化之回流重绘

    千次阅读 2021-01-17 14:14:35
    引发多次回流重绘,而是将这些合并为一次,因为浏览器中有缓冲机制,通过这个缓冲机制,能够减少回流重绘的次数,比如控制在100ms周期内,多次回流重绘合并为一次,这属于浏览器自身的性能优化。</strong><br> ,type...
  • 很多人都知道要减少浏览器的重排和重绘,但对其中的具体原理以及如何具体操作并不是很了解,当突然提起这个话题的时候,还是会一脸懵逼。希望大家可以耐着性子阅读本文,仔细琢磨,彻底掌握这个知识点! 博客、前端...
  • 之前有整理过一部分知识点, 一直没有发布, 因为都是有关 CSS 方面的...1. 避免重绘与回流: 实现方式 1. 使用 translate 代替 top 改变 。 2. 使用 opacity 代替 visibility 。 3. 不要一条一条的修改 DOM 的样式,
  • 重绘 当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,不会影响布局,比如bg-color 6.3 避免重绘和回流的两种方式 1.盒模型相关的属性会触发重新布局,会触发页面回流 Wi...
  • Canvas性能优化

    千次阅读 2018-08-07 16:38:50
    渲染动画的基本原理无非是反复的擦除和重绘。 为了动画的流畅,留了一帧的时间,我们需要在16ms完成游戏逻辑的处理,对象位置、状态的计算以及把他们画出来。一旦消耗时间多了,用户就会感觉卡顿。所以提高动画的...
  • canvas性能优化

    千次阅读 2018-05-05 14:28:24
    Canvas 最佳实践(性能篇)作者: 叶斋 发表于: 2016-02-22Canvas 想必前端同学们都不陌生,它...渲染动画的基本原理,无非是反复地擦除和重绘。为了动画的流畅,留给我渲染一帧的时间,只有短短的 16ms。在这 16ms...
  • 4、拖拽式绘制(鼠标移动过程中不断进行canvas重绘) 5、图片绘制(作为背景图片时重绘会发生闪烁现象,暂时有点问题,后面继续完善) 5、清空绘制功能 6、新版本优化绘制性能(使用共享坐标变量数组,减少了大量的...
  • canvas 性能优化

    2021-04-08 14:31:04
    渲染动画的基本原理,无非是反复地擦除和重绘。为了动画的流畅,留给我渲染一帧的时间,只有短短的 16ms。在这 16ms 中,我不仅需要处理一些游戏逻辑,计算每个对象的位置、状态,还需要把它们都画出来。如果消耗的...
  • 杭州下雪了,冷到不行,在家躺在床上玩手机,打开微信进入前端交流群里日常吹水,看到大佬在群里发了一篇文章你应该要知道的重绘与重排,文章里有一段骚操作,就是为了减少重绘与重排,合并样式操作,这个骚操作成功...
  • 使用canvas绘图的前端工程师可能都会遇到过canvas绘图黑屏、白屏的问题。以前写过一篇文章描述过hybrid下canvas黑屏的一种可能性: http://blog.csdn.net/yuhk231/article/details/53560782 那么如果我们面对的...
  • 一、什么是重排和重绘 要说清重排(reflow)和重绘(repaint),首先要理解排列和绘制,浏览器渲染页面时,在获取完html、css资源之后,会大致经过以下步骤。 (1) html生成html树 (2) css形成css规则 (3) 两者形成一个...
  • 但是js 的执行最终要依赖 domTree + cssomTree的生成结果, 这样就导致了 css的执行 阻塞了js的执行,因此, 我们把css 的执行优化做好是提升页面速度的比较重要的环节 在页面发生变化的时候 可能会发生...
  • UGUI性能优化Canvas

    2020-06-23 11:24:24
    UGUI性能优化Canvas 自从Unity问世以来,UI一直都存在比较大的问题,自带的OnGUI不能所见即所得,制作过程比较麻烦。于是出现了很多第三方的优秀的UI插件,比如很多项目里面用到的NGUI,或者后来出的FairyGUI。...
  • 最近看了幕课网 web 前端性能优化的课程,其中说到了浏览器的回流(reflow) 及 重绘(repaint)。觉得以后面试或许会被问到所以做一下笔记: 课程从回流及重绘这两个点延伸出了一个知识点就是 "css 会影响 javascrip...
  • 答:会的,原因是在浏览器渲染过程渲染css和渲染js各开启一个线程去工作但是这两个线程是互斥的,当渲染css在工作,渲染js的线程将会停止工作,则如果页面css频繁进行重绘势必会降低js的渲染速度 回流的概念 当...
  • Canvas 性能优化

    千次阅读 2018-09-21 12:52:01
    ,这个选项可以帮助浏览器进行内部优化 const ctx = canvas . getContext ( '2d' , { alpha : false } ) 尽量不要频繁地调用比较耗时的API 例如 shadow 相关 API ,此类 API 包括 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,120
精华内容 2,848
关键字:

优化canvas重绘