Tag Archives: front end

Cesium uses mediastreamrecorder or mediarecorder to record and download videos, and turn on the camera for recording.

Cesium recording canvas video

Using H5 API Mediarecorder and borrow canvas.capturestream to record the screen.

Direct upper code (Vue lower)

recorderCanvas () {
      let that = this
      let viewer = window.earth
      const stream = viewer.canvas.captureStream()
      const recorder = new MediaRecorder(stream, { MimeType: 'video/webm' })
      that.data = []
      recorder.ondataavailable = function (event) {
        if (event.data && event.data.size) {
          that.data.push(event.data)
        }
      }
      recorder.onstop = () => {
        that.url = URL.createObjectURL(new Blob(that.data, { type: 'video/webm' }))
        that.startDownload(that.url) 
      }
      recorder.start()
      setTimeout(() => {
        recorder.stop()
      }, 10000)
    },

Disadvantages: only canvas can be recorded, and other DOM pages cannot be recorded.

Add a camera to open the video, also using mediarecorder or   Mediastreamrecorder, mediastreamrecorder provides more control means, and the corresponding JS files need to be imported.

Mediastreamrecorder GitHub address

Mediarecorder mode

Note that when creating a mediarecorder instance, you should correctly set the value of mimeType. Otherwise, the downloaded video will be black. In addition, the video format chrome seems to only support WEMP format.

Calling mediarecorder. Stop() does not turn off the camera. You need to manually turn off video and audio by stream.gettracks.

makeRecordes () {
      if (navigator.mediaDevices) {
        console.log('getUserMedia supported.')

        var constraints = { audio: true, video: { width: 1280, height: 720 } }
        var chunks = []
        let that = this
        navigator.mediaDevices.getUserMedia(constraints)
          .then(function (stream) {
            var mediaRecorder = new MediaRecorder(stream, { mimeType: 'video/webm;codecs=vp8,opus' })

            mediaRecorder.start()
            mediaRecorder.ondataavailable = function (e) {
              chunks.push(e.data)
            }
            setTimeout(() => {
              mediaRecorder.stop()
              stream.getTracks().forEach(function (track) {
                track.stop()
              })
              mediaRecorder.onstop = () => {
                const videoBlob = new Blob(chunks, { 'type': 'video/webm' })
                let videoUrl = window.URL.createObjectURL(videoBlob)
                that.startDownload(videoUrl)
              }
            }, 10000)
          })
          .catch(function (err) {
            console.log('The following error occurred: ' + err)
          })
      }
    },

If you need more control, such as pause, and don’t want to implement it yourself, use mediastreamrecorder

Also set the value mimeType correctly, otherwise the recorded video will be black.

makeRecordesByMSR () {
      if (navigator.mediaDevices) {
        console.log('getUserMedia supported.')

        var constraints = { audio: true, video: { width: 1280, height: 720 } }
        navigator.mediaDevices.getUserMedia(constraints)
          .then(function (stream) {
            // eslint-disable-next-line no-undef
            var mediaRecorder = new MediaStreamRecorder(stream)
            mediaRecorder.stream = stream
            mediaRecorder.width = window.screen.width
            mediaRecorder.height = window.screen.height
            mediaRecorder.mimeType = 'video/webm;codecs=vp8,opus'
            mediaRecorder.ondataavailable = function (blob) {
              mediaRecorder.save(blob, 'myName.webm')
            }
            mediaRecorder.start(6000)

            setTimeout(() => {
              mediaRecorder.stream.stop()
            }, 12000)
          })
          .catch(function (err) {
            console.log('The following error occurred: ' + err)
          })
      }
    }

Solve the problem that better scroll lateral scrolling has no effect

The official suggestion is to add a fixed width to the parent element to scroll,

The first scheme

Get the width of each element, ele. Offsetwidth , and add it up. Finally, add ele. Style. Width = 'cumulative width' to the parent element

The second scheme

It is recommended to use this scheme directly, so it is not necessary to calculate the width of each sub element

Parent element: Display: inline block; white-space: nowrap; sub element: Display: inline block

You can scroll directly ~.

Vue modifies the value passed by props error: Avoid mutating a prop directly since the value will be overwritten whenever the par

When doing a project, you will sometimes encounter this kind of error
this sentence means to avoid changing the prop directly, because as long as the parent component is re rendered, the value will be overridden. Instead, use data or calculate properties based on the prop value
you can’t directly change the props passed by the parent component, so what can you do?You can use emit to trigger the events of the parent component
parent component

<template>
    <div class="class">
        <Student :show="isShow" @hideStudent="hideStudent" />
        <button @click="showStudent">点我显示学生</button>
    </div>
</template>

<script>
import Student from "./student";
export default {
    name: "class",
    components: { Student },
    data() {
        return {
            isShow: false,
        };
    },

    methods: {
        showStudent() {
            this.isShow = true;
        },
        hideStudent() {
            this.isShow = false;
        },
    },
};
</script>

Subcomponents

<template>
    <div class="student" v-show="show">
        <nav>Mike</nav>
        <button @click="close">点我关闭student</button>
    </div>
</template>

<script>
export default {
    name: "student",
    props: {
        show: {
            type: Boolean,
            default:false
        },
    },
    methods: {
        close() {
            this.$emit("hideStudent");
        },
    },
};
</script>

Of course, subcomponents can also write like this, using watch to listen

<template>
    <div class="student" v-show="showStudent">
        <nav>Mike</nav>
        <button @click="close">点我关闭student</button>
    </div>
</template>

<script>
export default {
    name: "student",
    props: {
        show: {
            type: Boolean,
            default:false
        },
    },
    data() {
        return {
            showStudent:false
        };
    },
    watch:{
        show(){
            this.showStudent=this.show
        },
    },
    methods: {
        close() {
            this.$emit("hideStudent");
        },
    },
};
</script>

Finally, let’s take a look at the rendering


for more details about the value transmission of vueprops, see the value transmission of Vue parent-child components

Solve Google browser font reduction to 12px

The solution of browser font less than 12px

1. Zoom through transform: scale()

<div class="box text1">The font size is 12px</div>
<! -- inside before adding the span tag, because transform:scale scales the width and height of the outer div -->
<div class="box text2">
    <span> The font size is 8px</span> 
</div>
Copy code
.box{
    width: 200px;
    height:100px;
    margin-bottom: 10px; 
    border: 1px solid red ;
}
.text1{
    font-size: 12px;
}
.text2 span{
    display: inline-block;/*transform:scale()这This attribute scales only the elements whose width and height can be defined. */
    font-size: 16px;
    transform: scale(0.5) ;/* font-size: 16*0.5=8px  */
    transform-origin: left top;/* Adjustment of position*/
}

The problem of cursor skipping in wangeditor

Problem description

When using wangeditor, input content, and press enter to switch to the next line, the cursor cuts over and automatically jumps back.

Cause of the problem

After encapsulating a component, the onchange event of wangeditor will be triggered every time the content passed in from the parent is used. In the onchange event, the modified value is assigned to the parent component by passing the child to the parent. After the value of the parent component changes, the value of the child component wangeditor will also be modified. Therefore, the cursor always jumps to the last. At this point, there is another problem of concurrency, that is, it is invalid after the undo and resume click.

Solution

When the child component watch listens to the value passed in by the parent component, it adds judgment to ensure that the input content is zero and the assignment will not be triggered

Instead of using the official recommended catchdata, the child component uses the method of passing the value to the parent component (that is, $emit) to synchronize the value to the parent component, so as to ensure that the value of the parent component is consistent with the content of the rich text when saving

if it can help you, please use your little hand to like it
thank you.

[Solved] Vue3 Configuration routing error: Catch all routes (“*“) must now be defined using a param with a custom regexp.

@[TOC] (vue3) catch all routes (“*”) must now be defined using a param with a custom regexp.)

Background

When the vue3 project specifies an unrecognized path to automatically jump to the 404 page when configuring the route, it reports an error catch all routes (“*”) must now be defined using a param with a custom regexp. </ font>
this means that all routes (“) must now be defined with a parameter with a self-defined regular expression

Solution

Change to the following configuration mode:

{
    path: "/:catchAll(.*)", // Unrecognized path automatically matches 404
    redirect: '/404',
},

Full routing configuration:

import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';

const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    name: 'Index',
    component: () => import('@/views/Index/Index.vue'),
  },
  // {
  //   path: '/', // Root directory auto-match/home
  //   redirect: '/index',
  // },
  {
    path: '/404',
    name: 'PageNotExist',
    component: () => import('@/views/PageNotExist/PageNotExist.vue'),
  },
  {
    path: "/:catchAll(.*)", // Unrecognized path automatically matches 404
    redirect: '/404',
  },
];

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes,
});

export default router;

Anti card limited Drag Based on react draggable drag

Recently, a project requirement is to click the question mark to display the prompt window. The window is fixed, does not scroll with the scroll bar, and can be dragged within the scope. It does not affect the lower form input.

I think of using anti card combined with react draggable. Record the implementation code here:

import React from 'react';
import { Modal, Button, Card, Icon } from 'antd';
import Draggable from 'react-draggable';

export default class App extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            cardShow: false,
            disabled: true,
            bounds: { left: 0, top: 0, bottom: 0, right: 0 }, // Initialize drag boundary
        };
        this.draggleRef = React.createRef();
    }

    onStart = (event, uiData) => {
        const { clientWidth, clientHeight } = window.document.documentElement;
        const targetRect = this.draggleRef.current.getBoundingClientRect();
        this.setState({
            // Set the drag boundary to limit the dragging distance from the top, bottom, left and right of the initial position, the following setting is draggable in the browser window
            // If the page has a fixed display header, it must be draggable below the header, you can set top: -targetRect.top + uiData.y + height of the header.
            bounds: {
                left: -targetRect.left + uiData.x,
                right: clientWidth - 300,
                top: -targetRect.top + uiData.y,
                bottom: clientHeight - (targetRect.bottom - uiData.y),
            },
        });
    };

    onClickShow = () => {
        this.setState({
            cardShow: true,
        })
    }

    onClickClose = () => {
        this.setState({
            cardShow: false,
            bounds: { left: 0, top: 0, bottom: 0, right: 0 },
        })
    }

    render() {
        const {disabled, bounds, cardShow} = this.state;
        return (
            <div style={{width: '100%'}}>
                <Draggable
                    disabled={disabled}
                    bounds={bounds}
                    onStart={(event, uiData) => this.onStart(event, uiData)}
                >
                    <div ref={this.draggleRef}>
                        {cardShow &&
                        <Card
                            title={
                                <div
                                    style={{
                                        width: '100%',
                                        cursor: 'move',
                                    }}
                                    onMouseOver={() => {
                                        this.setState({
                                            disabled: false,
                                        });
                                    }}
                                    onMouseOut={() => {
                                        this.setState({
                                            disabled: true,
                                        });
                                    }}
                                    onFocus={() => {}}
                                    onBlur={() => {}}
                                >
                                    {'Title'}
                                </div>
                            }
                            extra={
                                <span onClick={() => this.onClickClose()}>
                                    <Icon type={'close'} style={{fontSize:'16px'}}/>
                                </span>
                            }
                            style={{ width: 300, position: 'fixed', zIndex: 999 }}>
                            <p>Conetent</p>
                        </Card>}
                    </div>
                </Draggable>
                <span >{'Help'}</span><Icon onClick={() => this.onClickShow()} type="question-circle" />
            </div>
        );
    }

}

Realization of breakpoint download based on DIO in flutter

As there are not many articles downloaded from the shutter breakpoint, and there are few cases, I found them on the DIO case after searching for them for a long time, and it took me some time to be wronged
based on DIO: ^ 4.0.0 and Path_ Provider: ^ 2.0.2 implements the function of downloading a large file

Core code

import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:dio/dio.dart';
import 'package:path_provider/path_provider.dart';

class DownloadFile {
  /// Used to record the url being downloaded to avoid duplicate downloads
  static var downloadingUrls = Map<String, CancelToken>();

  /// Breakpoint downloading of large files
  static Future<void> download({
    required String url,
    required String savePath,
    ProgressCallback?onReceiveProgress,
    void Function()?done,
    void Function(DioError)?failed,
  }) async {
    int downloadStart = 0;
    bool fileExists = false;
    File f = File(savePath);
    if (await f.exists()) {
      downloadStart = f.lengthSync();
      fileExists = true;
    }
    print("start: $downloadStart");
    if (fileExists && downloadingUrls.containsKey(url)) {
      return;
    }
    var dio = Dio();
    CancelToken cancelToken = CancelToken();
    downloadingUrls[url] = cancelToken;
    try {
      var response = await dio.get<ResponseBody>(
        url,
        options: Options(
          /// Receive response data as a stream
          responseType: ResponseType.stream,
          followRedirects: false,
          headers: {
            /// Downloading key locations in segments
            "range": "bytes=$downloadStart-",
          },
        ),
      );
      File file = File(savePath);
      RandomAccessFile raf = file.openSync(mode: FileMode.append);
      int received = downloadStart;
      int total = await _getContentLength(response);
      Stream<Uint8List> stream = response.data!.stream;
      StreamSubscription<Uint8List>?subscription;
      subscription = stream.listen(
        (data) {
          /// Write files must be synchronized
          raf.writeFromSync(data);
          received += data.length;
          onReceiveProgress?.call(received, total);
        },
        onDone: () async {
          downloadingUrls.remove(url);
          await raf.close();
          done?.call();
        },
        onError: (e) async {
          await raf.close();
          downloadingUrls.remove(url);
          failed?.call(e as DioError);
        },
        cancelOnError: true,
      );
      cancelToken.whenCancel.then((_) async {
        await subscription?.cancel();
        await raf.close();
      });
    } on DioError catch (error) {
      /// The request has been sent and the server responds with a status code that it is not in the range of 200
      if (CancelToken.isCancel(error)) {
        print("Download cancelled");
      } else {
        failed?.call(error);
      }
      downloadingUrls.remove(url);
    }
  }

  /// Get the size of the downloaded file
  static Future<int> _getContentLength(Response<ResponseBody> response) async {
    try {
      var headerContent =
          response.headers.value(HttpHeaders.contentRangeHeader);
      print("download files: $headerContent");
      if (headerContent != null) {
        return int.parse(headerContent.split('/').last);
      } else {
        return 0;
      }
    } catch (e) {
      return 0;
    }
  }

  /// Cancel Mission
  static void cancelDownload(String url) {
    downloadingUrls[url]?.cancel();
    downloadingUrls.remove(url);
  }
}

Call case

void main() {
  runApp(TestMyApp());
}

class TestMyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _TestMyAppState();
  }
}

class _TestMyAppState extends State<TestMyApp> {
  void download() async {
    var url = "mp4";
    Directory dir = await getApplicationDocumentsDirectory();
    var sDCardDir = dir.path;
    var savePath = sDCardDir + "/video/1.mp4";
    File f = File(sDCardDir + "/video");
    if (!await f.exists()) {
      new Directory(sDCardDir + "/video").createSync();
    }

    await DownLoadManage().download(
      url: url,
      savePath: savePath,
      onReceiveProgress: (received, total) {
        if (total != -1) {
          print("Download1Received:" +
              received.toString() +
              "Total:" +
              total.toString() +
              "Progress.+${(received/total * 100).floor()}%");
        }
      },
      done: () {
        print("Download 1 completed");
      },
      failed: (e) {
        print("Download 1 failed:" + e.toString());
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: Center(
        child: GestureDetector(
          onTap: () {
            download();
          },
          child: Container(
            width: 150,
            height: 150,
            color: Colors.red,
          ),
        ),
      ),
    );
  }
}

How to Solve Error: The emulator process for AVD was killed.

How to solve the problem of the emulator process for AVD was killed.
my error report:

looking at the error report means that the process has been killed
trying to start from the command line

looking at the error report means that there is no more space
so it’s easy to do
Modify pixel.ini in the directory of C: (users/administrator. Android/AVD

it used to be C: (use) rs\Administrator.android\avd\Pixel_ 2_ API_ 28. AVD
the screenshot is my configured directory

There’s enough space here
restart the simulator and start it immediately