canvas在线画图-绘图软件有哪些?
canvas绘制箭头路径效果

前几天有很多人问到了如何绘制高德地图那样的
导航箭头线
效果,当时想了想并不难就先用canvas 做了,然后集成到了mapbox 上。 在线体验地址 ,迁移到其他map lib 也只需要应用相应的
地理转屏幕坐标
函数。
在canvas 的应用中我们经常会遇到各种线样式的绘制,比如虚线,渐变线,带pattern 线(箭头,铁轨图标等),或者虚线与pattern 的动画效果。如下图所示,总结下实现方法。
比如 ([10, 5]),就可以画出上图的虚线效果。发挥想象可以做出更多奇特效果。比如让虚线动起来,有走马灯的感觉。。
通过 createLinearGradient 函数创建渐变,然后设定其渐变色段, 赋值给strokeStyle,渐变效果如开头图所示
有个问题就是如果需要
渐变方向符合线条走向
,这是常见需求,只需要提前算下每条线的范围和方向,创建对应的LinearGradient 即可,其实类似于下面的箭头绘制,需要
反算 atan 角度
一样的。
最后这个算是综合的应用,我写了些canvas functions 放到了之前的canvasOverlay 里面去用,可以方便的集成到各种支持canvas 的lib 里面用。
基本思路就是:(懒得画图了,思路比较简单)
需要注意的是
,atan弧度角的计算在第二三象限,会跟第一四象限混淆。比如向左下角的
有向线的向量
是两个负值,但是tan 值是正的,跟第一象限一样,所以反算的时候也会算出来小于90度的角,实际上是大于180 的角度了,需要 +
大概的绘制过程,code as follow:
就简单写到这里。
最近还有个问题提到比较多,关于canvas 上的图标如何贴合地图的倾斜,这也是个视觉上的问题。大抵上可以通过CSS3d 或者 canvas 的透视去做,前者应该更简单些。有空再实践下
绘图软件有哪些?

您好,现如今,市面上的绘图软件是多种多样的,有的侧重于艺术设计,有的侧重于工业图,还有的侧重于3D画图,每一款绘图软件都有它自身的特点。下面看看有哪些主流绘图软件?
1.Inkscape
Inkscape是一款国外的矢量图形编辑软件,该软件的开发目标是成为一套强力的绘图软件,且能完全遵循与支持XML、SVG及CSS等开放性的标准格式。
2.Lucidchart
Lucidchart是一个基于Html5的在线流程图绘制和协作应用平台,用户可以通过它快速的实现流程图标的绘制,还能实时的进行团队协作。
3.3D MAX
3D MAX是一款专业的室内设计效果图制作软件,也是世界上应用最为广泛的三维建模,动画,渲染软件,它被广泛的应用到游戏开发、角色动画、电影电视视觉效果和设计行业等领域。
4.SmartDraw
SmartDraw是一款老牌的绘图软件了,它可以轻松创建数据流程图、程序流程图、网络结构图、室内设计图等等。只需利用鼠标拖放相应的图形、线条即可以快速创建出漂亮而又专业的设计图。对于程序设计、网络结构设计等领域的应用来说,SmartDraw绝对算得上是一个短小而又精悍的得力工具了。
5.CorelDraw
CorelDraw是一款专业的图形设计软件,它专用于矢量图形的编辑和排版,借助其丰富的内容和专业的图形设计、照片编辑和网站设计软件,能够让你随心所欲地表达自己的风格与创意,轻松创作徽标标志、广告标牌、Web图形或任何原创项目。
6.CAD
CAD在设计中通常要用计算机对不同方案进行大量的计算、分析和比较,以决定最优方案。各种设计信息,不管是数字的、文字的或图形的,都可以存放在计算机的内存,并能快速地检索。设计人员通常用草图开始设计,将草图变为工作图的繁重工作可以交给计算机完成。利用计算机可以进行与图形的编辑、放大、缩小、平移和旋转等有关的图形数据加工工作。
7.Visio
Visio是微软旗下的一款绘图软件,它可以帮助IT程序员和商务专业人员轻松地可视化、分析和交流复杂信息,让难以理解的复杂文本和表格转换为一目了然的Visio图表,提高工作的效率。
8.Adobe illustrator
Adobe illustrator其实与PS有些类似,但它是专业的矢量图形处理软件,为用户提供着丰富的像素描绘功能和顺畅灵活的矢量图编辑功能,并能够快速的创建设计工作流程。
9.Photoshop
Photoshop是一款十分强大的图形图像处理软件,其也一直占据着图像处理软件的领袖地位,是平面设计、建筑装修设计、三维动画制作和网页设计的必用软件。
整理了这么多,希望对您有帮助,望采纳~
vuepc电脑可以获取设备吗

VUE2实现录像(PC端)可拍照 下载 预览 选取指定摄像头和麦克风设备 源代码可直接使用 原创
2022-10-16 17:57:44

嗯呐FT 
码龄1年
关注
2022.10月份 谷歌是最新版本 使用vue2写

下面的这些代码可以在谷歌浏览器的本地(localhost)和https环境下执行。中间有大量的注释可查看,基本上看一遍就懂,前面的坑我基本都踩过了。
如果是http环境的话,我下面这些代码是执行不了的,因为我做了获取指定设备的功能,如果要http环境中使用,需要把获取指定设备的相关代码删掉才能用,而且需要去谷歌的这个地址配置一下才能用,最下面我会介绍怎么在http环境中用。
功能如下:
1.可获取多个摄像头设备并选择其一进行录制
2.录制的过程中拔掉摄像头监听结束录制
3.可在录制中进行拍照生成png图片 可预览 可下载
4.录制完成会生成一个有声音和画面的webm格式视频 可在线预览下载
5.录制的过程中计时(最小误差)
界面展示(界面我就做个小Demo 没有过多去弄好看点 重要是script部分)

先上代码 -- html部分
<template>
<div class="publish">
<div class="box">
<div class="videoPart">
<div class="videoRecord" @mouseenter="hoverVideo(0)" @mouseleave="hoverVideo(1)">
<video id="videoCamera" :width="videoWidth" :height="videoHeight" autoPlay></video>
<div class="hoverVideoOutside" v-if="ifHoverVideo && ifStartRecord" >
<div class="hoverVideoInside">
<div class="hoverVideoInsideInside">
<div class="hoverVideoBtn"><div class="hoverVideoBtnInside"></div></div>
<span>{{recordHMSTime}}</span>
</div>
</div>
</div>
</div>
<canvas id="canvasCamera" class="canvas" :width="videoWidth" :height="videoHeight"></canvas>
<video v-if="showVideo" :src="videoSrc" autoplay controls></video>
<img v-if="showImg" class="imgClass" :src="imgSrc" alt="">
</div>
<div>
<el-select v-model="deviceId" placeholder="请选择摄像头" @change="selectVideoChange" @focus="findVideoDevice" :disabled="ifStartRecord">
<el-option
v-for="item in deviceArr"
:key=""
:label=""
:value="">
</el-option>
</el-select>
<el-button v-if="!ifStartRecord" @click="startRecord" icon="el-icon-video-camera" size="small">开始录制</el-button>
<el-button v-else @click="stopRecord" icon="el-icon-switch-button" size="small">结束录制</el-button>
<el-button @click="photographBtn" icon="el-icon-camera" size="small">拍照</el-button>
</div>
<vxe-table
border
resizable
show-overflow
ref="xTable"
height="500"
:row-config="{isHover: true}"
:data="tableData">
<vxe-column type="seq" width="60"></vxe-column>
<vxe-column field="name" title="Name"></vxe-column>
<vxe-column title="操作" width="200" show-overflow>
<template #default="{ row }">
<vxe-button type="text" icon="vxe-icon-edit" @click="preview(row)">预览</vxe-button>
<vxe-button type="text" icon="vxe-icon-edit" @click="download(row)">下载</vxe-button>
</template>
</vxe-column>
</vxe-table>
</div>
</div>
</template>
CSS代码
<style scoped>
.canvas{
opacity: 0!important;
}
.videoPart{
position: relative;
display: flex;
align-items: center;
}
.hoverVideoOutside{
position: absolute;
top: 0px;
left: 0px;
width: 500px;
height: 300px;
background:linear-gradient(#000,transparent 20%);
z-index: 999;
}
.hoverVideoInside{
position: relative;
width: 100%;
height: 100%;
}
.hoverVideoInsideInside{
position: absolute;
top: 10px;
left: 380px;
padding: 2px;
display: flex;
justify-content: center;
align-items: center;
}
.hoverVideoBtn{
width: 30px;
height: 30px;
border-radius: 50%;
border: 2px solid red;
padding: 3px;
box-sizing: border-box;
margin-right: 4px;
}
.hoverVideoBtnInside{
background: red;
width: 20px;
height: 20px;
border-radius: 50%;
box-sizing: 50%;
}
span{
color: #fff;
}
.videoRecord{
position: relative;
}
.imgClass{
width: 500px;
height: 300px;
}
</style>
逻辑部分
<script>
export default {
name: 'HelloWorld',
data() {
return {
ifOpenCamera: false,//控制摄像头开关
ifStartRecord:false, //是否开始录制
thisVideo: null,
thisContext: null, //canvas
thisCanvas: null,
videoWidth: 500,
videoHeight: 300,
videoCecorded: [], //接受的数据流
mediaRecorderData: {},
videoSrc:'', //录制完的视频预览
imgSrc:'',//录制完预览的图片地址
deviceArr:[],//获取该电脑的摄像头
deviceId:'', //选择哪个摄像头
tableData:[], //录制完 制作表格数据
showVideo:false, //录制完预览视频
showImg:false,//录制完预览图片
recordTime:0, //监听录像的时间
recordHMSTime:'00:00:00', //监听录像的时间
ifHoverVideo:false, //监听是否鼠标在视频的上面 显示录制时间
timer:null, //每一秒执行一次计算录像的时间 这个是有误差的
startTime:'', //记录开始录制的时间戳
stream:null,
}
},
created() {
();
},
methods: {
initDevice(){
this.$nextTick(() => {
= []
= null
= ('canvasCamera');
= ('2d');
= ('videoCamera');
// 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
('', )
if ( === undefined) {
= {}
= !;
('http环境下没开那个谷歌权限 所以有点问题 得弹出提示弹窗 如果是本地或者https环境就基本不会走到这里')
this.$message({
message: '去谷歌浏览器配置网址',
type: 'error'
})
}
// 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
// 使用getUserMedia,因为它会覆盖现有的属性。
// 这里,如果缺少getUserMedia属性,就添加它。
if ( === undefined) {
= function (constraints) {
// 首先获取现存的getUserMedia(如果存在)
let getUserMedia = || || ;
// 有些浏览器不支持,会返回错误信息
// 保持接口一致
if (!getUserMedia) {
return (new Error('getUserMedia is not implemented in this browser'))
}
// 否则,使用Promise将调用包装到旧的
return new Promise(function (resolve, reject) {
(navigator, constraints, resolve, reject)
})
}
}
()
})
},
// 每次点开下拉框的时候都要去获取现在有多少个设备 以防在打开这个网站之后把摄像头拔了等情况
async findVideoDevice(){
= ''
= []
const _this = this
try{
// 获取你电脑中有什么设备
let deviceArr = await ();
if( == 0){
this.$message({
message: '没有摄像头设备',
type: 'error'
})
= []
return
}
('设备',deviceArr)
(item=>{
if( == 'videoinput'){
(item) //获取你电脑中有多少个摄像头设备
}
})
}catch(error){
(error)
= []
}
},
// 选择完是哪个摄像头以后执行的方法
selectVideoChange(){
this.$nextTick(() => {
const _this = this;
const constraints = {
audio: true,
video: {
width: _,
height: _,
transform: 'scaleX(-1)',
deviceId:{exact:}
},
};
(constraints).then(async(stream)=>{
// 旧的浏览器可能没有srcObject
if ('srcObject' in _) {
_ = stream
} else {
// 避免在新的浏览器中使用它,因为它正在被弃用。
_ = && (stream)
}
_ = function (e) {
_()
}
_ = true
}).catch(err => {
(err)
});
});
},
// 开始录制
startRecord() {
if( == ''){
this.$message({
message: '请选择摄像头',
type: 'error'
})
return
}
const _this = this
= null
= []
this.$nextTick(()=>{
const constraints = {
audio: true,
video: {
width: ,
height: ,
transform: 'scaleX(-1)',
deviceId:{exact:} //选取指定的设备来录制
},
};
//必须在model中render后才可获取到dom节点,直接获取无法获取到model中的dom节点
(constraints).then(function (stream) {
_ = stream
// 这个要重写一次
// 我插第三方的视频录像设备的情况下 点击录像 然后把设备拔出来 这个时候画面是黑色的
// 如果没有重写下面的方法 插进设备后 点击录像 画面依然是黑色的 但是能录像 只是界面上不显示
if ('srcObject' in _) {
_ = stream
} else {
// 避免在新的浏览器中使用它,因为它正在被弃用。
_ = && (stream)
}
_ = function (e) {
_ = true
_()
}
_(stream);//调用录制控件方法,触发开始录制
}).catch(err => {
// 点录制之前断开设备连接 但选择框已经选了设备 就会触发这个err
(err)
});
})
},
//拍照按钮
photographBtn() {
//先判断是否开启了摄像头
if(!){
this.$message({
message: '摄像头都还没开呢 傻猪猪',
type: 'error'
})
return
}
// 点击,canvas画图
(, 0, 0, , );
// 如果图片尺寸不想 500 300 那就写下面这个
// (, 0, 0, , ,0,0,1000, 600);
const fileName = (new Date).toISOString().replace(/:|\./g,'-')
const a = ('image/png')
const file = (a,fileName + 'png')
({
id:2,
name:fileName + 'png',
url:('image/png'),
type:'png'
})
},
//停止录制
stopRecord() {
if ( && !== null) {
(); //结束录制
}
},
// 开始录制中
startRecording(stream) {
('stream 在开始的时候的',stream)
let _this = this
= new MediaRecorder(stream, {
mimeType: 'video/webm;codecs=vp8,opus' //不加这个codecs=vp8,opus有时候下载下来之后看几秒就没了 残缺的视频
});
("dataavailable", (e) => {
if (e. > 0) {
_(e.data);//视频录制视频流数据
};
});
("stop", () => {
("结束录制");
_();//上传实时录制的视频
_ = false
_ = 0
_ = '00:00:00'
clearTimeout(_)
_ = null
});
("start", (e) => {
("开始 录制");
_ = true
_ = 0
_ = new Date().getTime();
_ = setTimeout(_,1000)
});
()
},
// 上传录制视频方法,获取视频地址
updataVideo() {
const blob = new Blob(, {
type: 'video/webm'
});
const fileName = (new Date).toISOString().replace(/:|\./g,'-')
({
id:2,
type:'webm',
name:fileName + '.webm',
url:(blob)
})
},
// 预览视频 图片
preview(row){
if( == 'png'){
= true
= false
=
}else if( == 'webm'){
= true
= false
=
}else{
this.$message({
message: '无法预览',
type: 'error'
})
}
},
download(row){
let aTag = ('a');//创建一个a标签
= ;
= ;
();
},
hoverVideo(num){
if(num){
// 移出
= false
}else{
// 移入
= true
}
},
secondChangeMinute(second){
const hour = parseInt(second / 3600)
const min = parseInt(second / 60)
const se = parseInt(second % 60)
const cHour = hour<10?'0'+hour:hour
const cMin = min<10?'0'+min:min
const cSe = se<10?'0'+se:se
return cHour + ':' + cMin + ':' + cSe
},
fixed(){
+= 1
= ()
if(!){
()
}
var offset = new Date().getTime() - ( + * 1000);
var nextTime = 1000 - offset;
if (nextTime < 0) nextTime = 0;
= setTimeout(, nextTime);
},
errReponse(err){
const message = || err
const response = {
'permission denied': '浏览器禁止本页面使用摄像头或麦克风,请开启相关的权限',
'requested device not found': '未检测到摄像头'
}
(response[ () ] || '未知错误');
this.$message({
message: response[ () ] || '未知错误',
type: 'warning'
})
},
dataURLtoFile: function(dataurl, filename) {
let arr = (','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = ,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = (n);
}
return new File([u8arr], filename, { type: mime });
},
// 这个方法是给需要的人看的 演示打开摄像头的方法
async openCamera(){
await ({audio:true,video:true}).then(()=>{
//我这个时候已经打开摄像头了
}).catch(err=>{
(err)
})
},
// 这个方法是给需要的人看的 演示关闭摄像头的方法
closeCamera(){
().forEach(item => {
// 关闭当前所有已打开的设备(你刚刚选择的摄像头设备和你默认的麦克风)
()
})
},
}
}
</script>
问题解答区域:
1.录制的视频只能是webm格式吗?进度条呢?
答:我在写程序的时候发现只能写webm格式,如果是写MP4或者其他类型,视频下载下来是没有办法播放的,可能在移动端就没有问题,我还没有去尝试在移动端做这个功能。webm格式我所知道的有两个弊端,下载下来的时候无法拖动进度条,而且要在指定播放器中才能播放。如果想要解决这个进度条的问题,可以去看这个地址的解决方法。前端 mediaRecorder 录制视频源代码实例,和本地播放器无法定位进度条问题分析和解决_anne都的博客-CSDN博客_mediarecorder 进度条
2.http问题
答:在http环境下是可以录制的,但是我上面的代码运行不了就是了。因为我添加了一个获取用户电脑中设备的功能,该功能在http环境下没有办法获取,可能是浏览器出于安全的问题。如果想要在http环境下录制,可以参考下面的这个地址,我也是百度了很久,看了很多别人的博客才得出的最终代码结果。地址如下:
=>1.JS调用媒体设备失败 --- getUserMedia undefine 问题(各浏览器配置方法)_<!--玄德-->的博客-CSDN博客_浏览器不支持getusermedia
=>2.
PC端调用摄像头录制视频――vue标准写法_前端_森森的博客-CSDN博客_vue调用摄像头录像
=>3.
JS基于页面实现音视频的录制(一)_画虎成鳖的博客-CSDN博客_js录制视频
3.表格不一定要用vxetable,随便用
4.如果还有什么问题再在评论区问吧。。
-
果盘绘画图片大全简单创作方法快速制作技巧2024-01-02 16:57:54
-
小年插画图片创作方法快速制作技巧2024-01-02 16:57:20
-
小年绘画作品制作技巧2024-01-02 16:55:45
-
小年插画图片创作方法快速制作技巧2024-01-02 16:55:02
-
立春插画图片如何制作2024-01-02 16:54:19
-
立春插画图片创作方法快速制作技巧2024-01-02 16:53:32






扫描二维码添加客服微信
扫描二维码关注