Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
CoderSmallfan
uni-app
提交
62facd69
U
uni-app
项目概览
CoderSmallfan
/
uni-app
与 Fork 源项目一致
Fork自
DCloud / uni-app
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
U
uni-app
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
62facd69
编写于
4月 18, 2019
作者:
fxy060608
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat(h5): canvas 高清处理
上级
849687ff
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
623 addition
and
443 deletion
+623
-443
src/core/view/components/canvas/hidpi.js
src/core/view/components/canvas/hidpi.js
+168
-0
src/core/view/components/canvas/index.vue
src/core/view/components/canvas/index.vue
+455
-443
未找到文件。
src/core/view/components/canvas/hidpi.js
0 → 100644
浏览文件 @
62facd69
const
pixelRatio
=
(
function
()
{
const
canvas
=
document
.
createElement
(
'
canvas
'
)
const
context
=
canvas
.
getContext
(
'
2d
'
)
const
backingStore
=
context
.
backingStorePixelRatio
||
context
.
webkitBackingStorePixelRatio
||
context
.
mozBackingStorePixelRatio
||
context
.
msBackingStorePixelRatio
||
context
.
oBackingStorePixelRatio
||
context
.
backingStorePixelRatio
||
1
return
(
window
.
devicePixelRatio
||
1
)
/
backingStore
})()
const
forEach
=
function
(
obj
,
func
)
{
for
(
let
key
in
obj
)
{
if
(
obj
.
hasOwnProperty
(
key
))
{
func
(
obj
[
key
],
key
)
}
}
}
const
ratioArgs
=
{
'
fillRect
'
:
'
all
'
,
'
clearRect
'
:
'
all
'
,
'
strokeRect
'
:
'
all
'
,
'
moveTo
'
:
'
all
'
,
'
lineTo
'
:
'
all
'
,
'
arc
'
:
[
0
,
1
,
2
],
'
arcTo
'
:
'
all
'
,
'
bezierCurveTo
'
:
'
all
'
,
'
isPointinPath
'
:
'
all
'
,
'
isPointinStroke
'
:
'
all
'
,
'
quadraticCurveTo
'
:
'
all
'
,
'
rect
'
:
'
all
'
,
'
translate
'
:
'
all
'
,
'
createRadialGradient
'
:
'
all
'
,
'
createLinearGradient
'
:
'
all
'
,
'
setTransform
'
:
[
4
,
5
]
}
if
(
pixelRatio
!==
1
)
{
const
proto
=
CanvasRenderingContext2D
.
prototype
forEach
(
ratioArgs
,
function
(
value
,
key
)
{
proto
[
key
]
=
(
function
(
_super
)
{
return
function
()
{
if
(
this
.
__ignore__
)
{
return
_super
.
apply
(
this
,
arguments
)
}
let
args
=
Array
.
prototype
.
slice
.
call
(
arguments
)
if
(
value
===
'
all
'
)
{
args
=
args
.
map
(
function
(
a
)
{
return
a
*
pixelRatio
})
}
else
if
(
Array
.
isArray
(
value
))
{
for
(
let
i
=
0
;
i
<
value
.
length
;
i
++
)
{
args
[
value
[
i
]]
*=
pixelRatio
}
}
return
_super
.
apply
(
this
,
args
)
}
})(
proto
[
key
])
})
proto
.
stroke
=
(
function
(
_super
)
{
return
function
()
{
if
(
this
.
__ignore__
)
{
return
_super
.
apply
(
this
,
arguments
)
}
this
.
lineWidth
*=
pixelRatio
_super
.
apply
(
this
,
arguments
)
this
.
lineWidth
/=
pixelRatio
}
})(
proto
.
stroke
)
proto
.
fillText
=
(
function
(
_super
)
{
return
function
()
{
if
(
this
.
__ignore__
)
{
return
_super
.
apply
(
this
,
arguments
)
}
const
args
=
Array
.
prototype
.
slice
.
call
(
arguments
)
args
[
1
]
*=
pixelRatio
args
[
2
]
*=
pixelRatio
this
.
font
=
this
.
font
.
replace
(
/
(\d
+
)(
px|em|rem|pt
)
/g
,
function
(
w
,
m
,
u
)
{
return
(
m
*
pixelRatio
)
+
u
}
)
_super
.
apply
(
this
,
args
)
this
.
font
=
this
.
font
.
replace
(
/
(\d
+
)(
px|em|rem|pt
)
/g
,
function
(
w
,
m
,
u
)
{
return
(
m
/
pixelRatio
)
+
u
}
)
}
})(
proto
.
fillText
)
proto
.
strokeText
=
(
function
(
_super
)
{
return
function
()
{
if
(
this
.
__ignore__
)
{
return
_super
.
apply
(
this
,
arguments
)
}
var
args
=
Array
.
prototype
.
slice
.
call
(
arguments
)
args
[
1
]
*=
pixelRatio
// x
args
[
2
]
*=
pixelRatio
// y
this
.
font
=
this
.
font
.
replace
(
/
(\d
+
)(
px|em|rem|pt
)
/g
,
function
(
w
,
m
,
u
)
{
return
(
m
*
pixelRatio
)
+
u
}
)
_super
.
apply
(
this
,
args
)
this
.
font
=
this
.
font
.
replace
(
/
(\d
+
)(
px|em|rem|pt
)
/g
,
function
(
w
,
m
,
u
)
{
return
(
m
/
pixelRatio
)
+
u
}
)
}
})(
proto
.
strokeText
)
proto
.
drawImageByCanvas
=
(
function
(
_super
)
{
return
function
(
canvas
,
srcx
,
srcy
,
srcw
,
srch
,
desx
,
desy
,
desw
,
desh
,
isScale
)
{
if
(
this
.
__ignore__
)
{
return
_super
.
apply
(
this
,
arguments
)
}
srcx
*=
pixelRatio
srcy
*=
pixelRatio
srcw
*=
pixelRatio
srch
*=
pixelRatio
desx
*=
pixelRatio
desy
*=
pixelRatio
desw
=
isScale
?
desw
*
pixelRatio
:
desw
desh
=
isScale
?
desh
*
pixelRatio
:
desh
_super
.
call
(
this
,
canvas
,
srcx
,
srcy
,
srcw
,
srch
,
desx
,
desy
,
desw
,
desh
)
}
})(
proto
.
drawImage
)
proto
.
drawImage
=
(
function
(
_super
)
{
return
function
()
{
if
(
this
.
__ignore__
)
{
return
_super
.
apply
(
this
,
arguments
)
}
this
.
scale
(
pixelRatio
,
pixelRatio
)
_super
.
apply
(
this
,
arguments
)
this
.
scale
(
1
/
pixelRatio
,
1
/
pixelRatio
)
}
})(
proto
.
drawImage
)
}
export
function
wrapper
(
canvas
)
{
canvas
.
style
.
height
=
canvas
.
height
+
'
px
'
canvas
.
style
.
width
=
canvas
.
width
+
'
px
'
canvas
.
width
*=
pixelRatio
canvas
.
height
*=
pixelRatio
console
.
log
(
canvas
.
width
)
console
.
log
(
canvas
.
height
)
}
src/core/view/components/canvas/index.vue
浏览文件 @
62facd69
<
template
>
<
template
>
<uni-canvas
:canvas-id=
"canvasId"
:disable-scroll=
"disableScroll"
v-on=
"_listeners"
>
v-on=
"_listeners"
>
<canvas
ref=
"canvas"
width=
"300"
height=
"150"
/>
<div
style=
"position: absolute; top: 0; left: 0; width: 100%; height: 100%; overflow: hidden;"
>
<slot/>
</div>
<v-uni-resize-sensor
ref=
"sensor"
@
resize=
"_resize"
/>
</uni-canvas>
</
template
>
<
script
>
import
{
subscriber
}
from
'
uni-mixins
'
function
resolveColor
(
color
)
{
color
=
color
.
slice
(
0
)
color
[
3
]
=
color
[
3
]
/
255
return
'
rgba(
'
+
color
.
join
(
'
,
'
)
+
'
)
'
}
function
processTouches
(
target
,
touches
)
{
return
([]).
map
.
call
(
touches
,
(
touche
)
=>
{
var
boundingClientRect
=
target
.
getBoundingClientRect
()
return
{
identifier
:
touche
.
identifier
,
x
:
touche
.
clientX
-
boundingClientRect
.
x
,
y
:
touche
.
clientY
-
boundingClientRect
.
y
}
})
}
export
default
{
name
:
'
Canvas
'
,
mixins
:
[
subscriber
],
props
:
{
canvasId
:
{
type
:
String
,
default
:
''
},
disableScroll
:
{
type
:
[
Boolean
,
String
],
default
:
false
}
},
data
()
{
return
{
actionsWaiting
:
false
}
},
computed
:
{
id
()
{
return
this
.
canvasId
},
_listeners
()
{
var
$listeners
=
Object
.
assign
({},
this
.
$listeners
)
var
events
=
[
'
touchstart
'
,
'
touchmove
'
,
'
touchend
'
]
events
.
forEach
(
event
=>
{
var
existing
=
$listeners
[
event
]
var
eventHandler
=
[]
if
(
existing
)
{
eventHandler
.
push
((
$event
)
=>
{
this
.
$trigger
(
event
,
Object
.
assign
({},
$event
,
{
touches
:
processTouches
(
$event
.
currentTarget
,
$event
.
touches
),
changedTouches
:
processTouches
(
$event
.
currentTarget
,
$event
.
changedTouches
)
}))
})
}
if
(
this
.
disableScroll
&&
event
===
'
touchmove
'
)
{
eventHandler
.
push
(
this
.
_touchmove
)
}
$listeners
[
event
]
=
eventHandler
})
return
$listeners
}
},
created
()
{
this
.
_actionsDefer
=
[]
this
.
_images
=
{}
},
mounted
()
{
this
.
_resize
({
width
:
this
.
$refs
.
sensor
.
$el
.
offsetWidth
,
height
:
this
.
$refs
.
sensor
.
$el
.
offsetHeight
})
},
methods
:
{
_handleSubscribe
({
type
,
data
=
{}
})
{
var
method
=
this
[
type
]
if
(
type
.
indexOf
(
'
_
'
)
!==
0
&&
typeof
method
===
'
function
'
)
{
method
(
data
)
}
},
_resize
({
width
,
height
})
{
var
canvas
=
this
.
$refs
.
canvas
if
(
canvas
.
width
!==
width
||
canvas
.
height
!==
height
)
{
canvas
.
width
=
width
canvas
.
height
=
height
}
},
_touchmove
(
event
)
{
event
.
preventDefault
()
},
actionsChanged
({
actions
,
reserve
,
callbackId
})
{
var
self
=
this
if
(
!
actions
)
{
return
}
if
(
this
.
actionsWaiting
)
{
this
.
_actionsDefer
.
push
([
actions
,
reserve
,
callbackId
])
return
}
var
canvas
=
this
.
$refs
.
canvas
var
c2d
=
canvas
.
getContext
(
'
2d
'
)
if
(
!
reserve
)
{
c2d
.
fillStyle
=
'
#000000
'
c2d
.
strokeStyle
=
'
#000000
'
c2d
.
shadowColor
=
'
#000000
'
c2d
.
shadowBlur
=
0
c2d
.
shadowOffsetX
=
0
c2d
.
shadowOffsetY
=
0
c2d
.
setTransform
(
1
,
0
,
0
,
1
,
0
,
0
)
c2d
.
clearRect
(
0
,
0
,
canvas
.
width
,
canvas
.
height
)
}
this
.
preloadImage
(
actions
)
for
(
let
index
=
0
;
index
<
actions
.
length
;
index
++
)
{
let
action
=
actions
[
index
]
let
method
=
action
.
method
let
data
=
action
.
data
if
(
/^set/
.
test
(
method
)
&&
method
!==
'
setTransform
'
)
{
let
method1
=
method
[
3
].
toLowerCase
()
+
method
.
slice
(
4
)
let
color
if
(
method1
===
'
fillStyle
'
||
method1
===
'
strokeStyle
'
)
{
if
(
data
[
0
]
===
'
normal
'
)
{
color
=
resolveColor
(
data
[
1
])
}
else
if
(
data
[
0
]
===
'
linear
'
)
{
let
LinearGradient
=
c2d
.
createLinearGradient
(...
data
[
1
])
data
[
2
].
forEach
(
function
(
data2
)
{
let
offset
=
data2
[
0
]
let
color
=
resolveColor
(
data2
[
1
])
LinearGradient
.
addColorStop
(
offset
,
color
)
})
}
else
if
(
data
[
0
]
===
'
radial
'
)
{
let
x
=
data
[
1
][
0
]
let
y
=
data
[
1
][
1
]
let
r
=
data
[
1
][
2
]
let
LinearGradient
=
c2d
.
createRadialGradient
(
x
,
y
,
0
,
x
,
y
,
r
)
data
[
2
].
forEach
(
function
(
data2
)
{
let
offset
=
data2
[
0
]
let
color
=
resolveColor
(
data2
[
1
])
LinearGradient
.
addColorStop
(
offset
,
color
)
})
}
else
if
(
data
[
0
]
===
'
pattern
'
)
{
let
loaded
=
this
.
checkImageLoaded
(
data
[
1
],
actions
.
slice
(
index
+
1
),
callbackId
,
function
(
image
)
{
if
(
image
)
{
c2d
[
method1
]
=
c2d
.
createPattern
(
image
,
data
[
2
])
}
})
if
(
!
loaded
)
{
break
}
continue
}
c2d
[
method1
]
=
color
}
else
if
(
method1
===
'
globalAlpha
'
)
{
c2d
[
method1
]
=
data
[
0
]
/
255
}
else
if
(
method1
===
'
shadow
'
)
{
var
_
=
[
'
shadowOffsetX
'
,
'
shadowOffsetY
'
,
'
shadowBlur
'
,
'
shadowColor
'
]
data
.
forEach
(
function
(
color_
,
method_
)
{
c2d
[
_
[
method_
]]
=
_
[
method_
]
===
'
shadowColor
'
?
resolveColor
(
color_
)
:
color_
})
}
else
{
if
(
method1
===
'
fontSize
'
)
{
c2d
.
font
=
c2d
.
font
.
replace
(
/
\d
+
\.?\d
*px/
,
data
[
0
]
+
'
px
'
)
}
else
{
if
(
method1
===
'
lineDash
'
)
{
c2d
.
setLineDash
(
data
[
0
])
c2d
.
lineDashOffset
=
data
[
1
]
||
0
}
else
{
if
(
method1
===
'
textBaseline
'
)
{
if
(
data
[
0
]
===
'
normal
'
)
{
data
[
0
]
=
'
alphabetic
'
}
c2d
[
method1
]
=
data
[
0
]
}
else
{
c2d
[
method1
]
=
data
[
0
]
}
}
}
}
}
else
if
(
method
===
'
fillPath
'
||
method
===
'
strokePath
'
)
{
method
=
method
.
replace
(
/Path/
,
''
)
c2d
.
beginPath
()
data
.
forEach
(
function
(
data_
)
{
c2d
[
data_
.
method
].
apply
(
c2d
,
data_
.
data
)
})
c2d
[
method
]()
}
else
if
(
method
===
'
fillText
'
)
{
c2d
.
fillText
.
apply
(
c2d
,
data
)
}
else
if
(
method
===
'
drawImage
'
)
{
var
A
=
(
function
()
{
var
dataArray
=
[...
data
]
var
url
=
dataArray
[
0
]
var
otherData
=
dataArray
.
slice
(
1
)
self
.
_images
=
self
.
_images
||
{}
if
(
!
self
.
checkImageLoaded
(
url
,
actions
.
slice
(
index
+
1
),
callbackId
,
function
(
image
)
{
if
(
image
)
{
c2d
.
drawImage
.
apply
(
c2d
,
[
image
].
concat
([...
otherData
.
slice
(
4
,
8
)],
[...
otherData
.
slice
(
0
,
4
)]))
}
}))
return
'
break
'
}())
if
(
A
===
'
break
'
)
{
break
}
}
else
{
if
(
method
===
'
clip
'
)
{
data
.
forEach
(
function
(
data_
)
{
c2d
[
data_
.
method
].
apply
(
c2d
,
data_
.
data
)
})
c2d
.
clip
()
}
else
{
c2d
[
method
].
apply
(
c2d
,
data
)
}
}
}
if
(
!
this
.
actionsWaiting
&&
callbackId
)
{
UniViewJSBridge
.
publishHandler
(
'
onDrawCanvas
'
,
{
callbackId
,
data
:
{
errMsg
:
'
drawCanvas:ok
'
}
},
this
.
$page
.
id
)
}
},
preloadImage
:
function
(
actions
)
{
var
sefl
=
this
actions
.
forEach
(
function
(
action
)
{
var
method
=
action
.
method
var
data
=
action
.
data
var
src
=
''
if
(
method
===
'
drawImage
'
)
{
src
=
data
[
0
]
src
=
sefl
.
$getRealPath
(
src
)
data
[
0
]
=
src
}
else
if
(
method
===
'
setFillStyle
'
&&
data
[
0
]
===
'
pattern
'
)
{
src
=
data
[
1
]
src
=
sefl
.
$getRealPath
(
src
)
data
[
1
]
=
src
}
if
(
src
&&
!
sefl
.
_images
[
src
])
{
loadImage
()
}
/**
* 加载图像
*/
function
loadImage
()
{
sefl
.
_images
[
src
]
=
new
Image
()
sefl
.
_images
[
src
].
onload
=
function
()
{
sefl
.
_images
[
src
].
ready
=
true
}
/**
* 从Blob加载
* @param {Blob} blob
*/
function
loadBlob
(
blob
)
{
sefl
.
_images
[
src
].
src
=
(
window
.
URL
||
window
.
webkitURL
).
createObjectURL
(
blob
)
}
/**
* 从本地文件加载
* @param {string} path 文件路径
*/
function
loadFile
(
path
)
{
var
bitmap
=
new
plus
.
nativeObj
.
Bitmap
(
'
bitmap
'
+
Date
.
now
())
bitmap
.
load
(
path
,
function
()
{
sefl
.
_images
[
src
].
src
=
bitmap
.
toBase64Data
()
bitmap
.
clear
()
},
function
()
{
bitmap
.
clear
()
console
.
error
(
'
preloadImage error
'
)
})
}
/**
* 从网络加载
* @param {string} url 文件地址
*/
function
loadUrl
(
url
)
{
function
plusDownload
()
{
plus
.
downloader
.
createDownload
(
url
,
{
filename
:
'
_doc/uniapp_temp/download/
'
},
function
(
d
,
status
)
{
if
(
status
===
200
)
{
loadFile
(
d
.
filename
)
}
else
{
sefl
.
_images
[
src
].
src
=
src
}
}).
start
()
}
var
xhr
=
new
XMLHttpRequest
()
xhr
.
open
(
'
GET
'
,
url
,
true
)
xhr
.
responseType
=
'
blob
'
xhr
.
onload
=
function
()
{
if
(
this
.
status
===
200
)
{
loadBlob
(
this
.
response
)
}
}
xhr
.
onerror
=
window
.
plus
?
plusDownload
:
function
()
{
sefl
.
_images
[
src
].
src
=
src
}
xhr
.
send
()
}
if
(
window
.
plus
&&
(
!
window
.
webkit
||
!
window
.
webkit
.
messageHandlers
))
{
sefl
.
_images
[
src
].
src
=
src
}
else
{
// 解决 PLUS-APP(wkwebview)以及 H5 图像跨域问题(H5图像响应头需包含access-control-allow-origin)
if
(
window
.
plus
&&
src
.
indexOf
(
'
http://
'
)
!==
0
&&
src
.
indexOf
(
'
https://
'
)
!==
0
)
{
loadFile
(
src
)
}
else
if
(
/^data:
[
a-z-
]
+
\/[
a-z-
]
+;base64,/
.
test
(
src
))
{
sefl
.
_images
[
src
].
src
=
src
}
else
{
loadUrl
(
src
)
}
}
}
})
},
checkImageLoaded
:
function
(
src
,
actions
,
callbackId
,
fn
)
{
var
self
=
this
var
image
=
this
.
_images
[
src
]
if
(
image
.
ready
)
{
fn
(
image
)
return
true
}
else
{
this
.
_actionsDefer
.
unshift
([
actions
,
true
])
this
.
actionsWaiting
=
true
image
.
onload
=
function
()
{
image
.
ready
=
true
fn
(
image
)
self
.
actionsWaiting
=
false
var
actions
=
self
.
_actionsDefer
.
slice
(
0
)
self
.
_actionsDefer
=
[]
for
(
var
action
=
actions
.
shift
();
action
;)
{
self
.
actionsChanged
({
actions
:
action
[
0
],
reserve
:
action
[
1
],
callbackId
})
action
=
actions
.
shift
()
}
}
return
false
}
},
getImageData
({
x
,
y
,
width
,
height
,
callbackId
})
{
var
imgData
var
canvas
=
this
.
$refs
.
canvas
if
(
!
width
)
{
width
=
canvas
.
width
}
if
(
!
height
)
{
height
=
canvas
.
height
}
try
{
imgData
=
canvas
.
getContext
(
'
2d
'
).
getImageData
(
x
,
y
,
width
,
height
)
}
catch
(
error
)
{
UniViewJSBridge
.
publishHandler
(
'
onCanvasMethodCallback
'
,
{
callbackId
,
data
:
{
errMsg
:
'
canvasGetImageData:fail
'
}
},
this
.
$page
.
id
)
return
}
UniViewJSBridge
.
publishHandler
(
'
onCanvasMethodCallback
'
,
{
callbackId
,
data
:
{
errMsg
:
'
canvasGetImageData:ok
'
,
data
:
[...
imgData
.
data
],
width
,
height
}
},
this
.
$page
.
id
)
},
putImageData
({
data
,
x
,
y
,
width
,
height
,
callbackId
})
{
try
{
if
(
!
height
)
{
height
=
Math
.
round
(
data
.
length
/
4
/
width
)
}
this
.
$refs
.
canvas
.
getContext
(
'
2d
'
).
putImageData
(
new
ImageData
(
new
Uint8ClampedArray
(
data
),
width
,
height
),
x
,
y
)
}
catch
(
error
)
{
UniViewJSBridge
.
publishHandler
(
'
onCanvasMethodCallback
'
,
{
callbackId
,
data
:
{
errMsg
:
'
canvasPutImageData:fail
'
}
},
this
.
$page
.
id
)
return
}
UniViewJSBridge
.
publishHandler
(
'
onCanvasMethodCallback
'
,
{
callbackId
,
data
:
{
errMsg
:
'
canvasPutImageData:ok
'
}
},
this
.
$page
.
id
)
}
}
}
</
script
>
<
style
>
uni-canvas
{
width
:
300px
;
height
:
150px
;
display
:
block
;
position
:
relative
;
}
uni-canvas
>
canvas
{
position
:
absolute
;
top
:
0
;
left
:
0
;
width
:
100%
;
height
:
100%
;
}
height=
"150"
/>
<div
style=
"position: absolute; top: 0; left: 0; width: 100%; height: 100%; overflow: hidden;"
>
<slot
/>
</div>
</uni-canvas>
</
template
>
<
script
>
import
{
subscriber
}
from
'
uni-mixins
'
import
{
wrapper
}
from
'
./hidpi
'
function
resolveColor
(
color
)
{
color
=
color
.
slice
(
0
)
color
[
3
]
=
color
[
3
]
/
255
return
'
rgba(
'
+
color
.
join
(
'
,
'
)
+
'
)
'
}
function
processTouches
(
target
,
touches
)
{
return
([]).
map
.
call
(
touches
,
(
touche
)
=>
{
var
boundingClientRect
=
target
.
getBoundingClientRect
()
return
{
identifier
:
touche
.
identifier
,
x
:
touche
.
clientX
-
boundingClientRect
.
x
,
y
:
touche
.
clientY
-
boundingClientRect
.
y
}
})
}
export
default
{
name
:
'
Canvas
'
,
mixins
:
[
subscriber
],
props
:
{
canvasId
:
{
type
:
String
,
default
:
''
},
disableScroll
:
{
type
:
[
Boolean
,
String
],
default
:
false
}
},
data
()
{
return
{
actionsWaiting
:
false
}
},
computed
:
{
id
()
{
return
this
.
canvasId
},
_listeners
()
{
var
$listeners
=
Object
.
assign
({},
this
.
$listeners
)
var
events
=
[
'
touchstart
'
,
'
touchmove
'
,
'
touchend
'
]
events
.
forEach
(
event
=>
{
var
existing
=
$listeners
[
event
]
var
eventHandler
=
[]
if
(
existing
)
{
eventHandler
.
push
((
$event
)
=>
{
this
.
$trigger
(
event
,
Object
.
assign
({},
$event
,
{
touches
:
processTouches
(
$event
.
currentTarget
,
$event
.
touches
),
changedTouches
:
processTouches
(
$event
.
currentTarget
,
$event
.
changedTouches
)
}))
})
}
if
(
this
.
disableScroll
&&
event
===
'
touchmove
'
)
{
eventHandler
.
push
(
this
.
_touchmove
)
}
$listeners
[
event
]
=
eventHandler
})
return
$listeners
}
},
created
()
{
this
.
_actionsDefer
=
[]
this
.
_images
=
{}
},
mounted
()
{
this
.
_resize
({
width
:
this
.
$el
.
offsetWidth
,
height
:
this
.
$el
.
offsetHeight
})
},
methods
:
{
_handleSubscribe
({
type
,
data
=
{}
})
{
var
method
=
this
[
type
]
if
(
type
.
indexOf
(
'
_
'
)
!==
0
&&
typeof
method
===
'
function
'
)
{
method
(
data
)
}
},
_resize
({
width
,
height
})
{
var
canvas
=
this
.
$refs
.
canvas
if
(
canvas
.
width
!==
width
||
canvas
.
height
!==
height
)
{
canvas
.
width
=
width
canvas
.
height
=
height
}
wrapper
(
canvas
)
},
_touchmove
(
event
)
{
event
.
preventDefault
()
},
actionsChanged
({
actions
,
reserve
,
callbackId
})
{
var
self
=
this
if
(
!
actions
)
{
return
}
if
(
this
.
actionsWaiting
)
{
this
.
_actionsDefer
.
push
([
actions
,
reserve
,
callbackId
])
return
}
var
canvas
=
this
.
$refs
.
canvas
var
c2d
=
canvas
.
getContext
(
'
2d
'
)
if
(
!
reserve
)
{
c2d
.
fillStyle
=
'
#000000
'
c2d
.
strokeStyle
=
'
#000000
'
c2d
.
shadowColor
=
'
#000000
'
c2d
.
shadowBlur
=
0
c2d
.
shadowOffsetX
=
0
c2d
.
shadowOffsetY
=
0
c2d
.
setTransform
(
1
,
0
,
0
,
1
,
0
,
0
)
c2d
.
clearRect
(
0
,
0
,
canvas
.
width
,
canvas
.
height
)
}
this
.
preloadImage
(
actions
)
for
(
let
index
=
0
;
index
<
actions
.
length
;
index
++
)
{
let
action
=
actions
[
index
]
let
method
=
action
.
method
let
data
=
action
.
data
if
(
/^set/
.
test
(
method
)
&&
method
!==
'
setTransform
'
)
{
let
method1
=
method
[
3
].
toLowerCase
()
+
method
.
slice
(
4
)
let
color
if
(
method1
===
'
fillStyle
'
||
method1
===
'
strokeStyle
'
)
{
if
(
data
[
0
]
===
'
normal
'
)
{
color
=
resolveColor
(
data
[
1
])
}
else
if
(
data
[
0
]
===
'
linear
'
)
{
let
LinearGradient
=
c2d
.
createLinearGradient
(...
data
[
1
])
data
[
2
].
forEach
(
function
(
data2
)
{
let
offset
=
data2
[
0
]
let
color
=
resolveColor
(
data2
[
1
])
LinearGradient
.
addColorStop
(
offset
,
color
)
})
}
else
if
(
data
[
0
]
===
'
radial
'
)
{
let
x
=
data
[
1
][
0
]
let
y
=
data
[
1
][
1
]
let
r
=
data
[
1
][
2
]
let
LinearGradient
=
c2d
.
createRadialGradient
(
x
,
y
,
0
,
x
,
y
,
r
)
data
[
2
].
forEach
(
function
(
data2
)
{
let
offset
=
data2
[
0
]
let
color
=
resolveColor
(
data2
[
1
])
LinearGradient
.
addColorStop
(
offset
,
color
)
})
}
else
if
(
data
[
0
]
===
'
pattern
'
)
{
let
loaded
=
this
.
checkImageLoaded
(
data
[
1
],
actions
.
slice
(
index
+
1
),
callbackId
,
function
(
image
)
{
if
(
image
)
{
c2d
[
method1
]
=
c2d
.
createPattern
(
image
,
data
[
2
])
}
})
if
(
!
loaded
)
{
break
}
continue
}
c2d
[
method1
]
=
color
}
else
if
(
method1
===
'
globalAlpha
'
)
{
c2d
[
method1
]
=
data
[
0
]
/
255
}
else
if
(
method1
===
'
shadow
'
)
{
var
_
=
[
'
shadowOffsetX
'
,
'
shadowOffsetY
'
,
'
shadowBlur
'
,
'
shadowColor
'
]
data
.
forEach
(
function
(
color_
,
method_
)
{
c2d
[
_
[
method_
]]
=
_
[
method_
]
===
'
shadowColor
'
?
resolveColor
(
color_
)
:
color_
})
}
else
{
if
(
method1
===
'
fontSize
'
)
{
c2d
.
font
=
c2d
.
font
.
replace
(
/
\d
+
\.?\d
*px/
,
data
[
0
]
+
'
px
'
)
}
else
{
if
(
method1
===
'
lineDash
'
)
{
c2d
.
setLineDash
(
data
[
0
])
c2d
.
lineDashOffset
=
data
[
1
]
||
0
}
else
{
if
(
method1
===
'
textBaseline
'
)
{
if
(
data
[
0
]
===
'
normal
'
)
{
data
[
0
]
=
'
alphabetic
'
}
c2d
[
method1
]
=
data
[
0
]
}
else
{
c2d
[
method1
]
=
data
[
0
]
}
}
}
}
}
else
if
(
method
===
'
fillPath
'
||
method
===
'
strokePath
'
)
{
method
=
method
.
replace
(
/Path/
,
''
)
c2d
.
beginPath
()
data
.
forEach
(
function
(
data_
)
{
c2d
[
data_
.
method
].
apply
(
c2d
,
data_
.
data
)
})
c2d
[
method
]()
}
else
if
(
method
===
'
fillText
'
)
{
c2d
.
fillText
.
apply
(
c2d
,
data
)
}
else
if
(
method
===
'
drawImage
'
)
{
var
A
=
(
function
()
{
var
dataArray
=
[...
data
]
var
url
=
dataArray
[
0
]
var
otherData
=
dataArray
.
slice
(
1
)
self
.
_images
=
self
.
_images
||
{}
if
(
!
self
.
checkImageLoaded
(
url
,
actions
.
slice
(
index
+
1
),
callbackId
,
function
(
image
)
{
if
(
image
)
{
c2d
.
drawImage
.
apply
(
c2d
,
[
image
].
concat
([...
otherData
.
slice
(
4
,
8
)],
[...
otherData
.
slice
(
0
,
4
)]))
}
}))
return
'
break
'
}())
if
(
A
===
'
break
'
)
{
break
}
}
else
{
if
(
method
===
'
clip
'
)
{
data
.
forEach
(
function
(
data_
)
{
c2d
[
data_
.
method
].
apply
(
c2d
,
data_
.
data
)
})
c2d
.
clip
()
}
else
{
c2d
[
method
].
apply
(
c2d
,
data
)
}
}
}
if
(
!
this
.
actionsWaiting
&&
callbackId
)
{
UniViewJSBridge
.
publishHandler
(
'
onDrawCanvas
'
,
{
callbackId
,
data
:
{
errMsg
:
'
drawCanvas:ok
'
}
},
this
.
$page
.
id
)
}
},
preloadImage
:
function
(
actions
)
{
var
sefl
=
this
actions
.
forEach
(
function
(
action
)
{
var
method
=
action
.
method
var
data
=
action
.
data
var
src
=
''
if
(
method
===
'
drawImage
'
)
{
src
=
data
[
0
]
src
=
sefl
.
$getRealPath
(
src
)
data
[
0
]
=
src
}
else
if
(
method
===
'
setFillStyle
'
&&
data
[
0
]
===
'
pattern
'
)
{
src
=
data
[
1
]
src
=
sefl
.
$getRealPath
(
src
)
data
[
1
]
=
src
}
if
(
src
&&
!
sefl
.
_images
[
src
])
{
loadImage
()
}
/**
* 加载图像
*/
function
loadImage
()
{
sefl
.
_images
[
src
]
=
new
Image
()
sefl
.
_images
[
src
].
onload
=
function
()
{
sefl
.
_images
[
src
].
ready
=
true
}
/**
* 从Blob加载
* @param {Blob} blob
*/
function
loadBlob
(
blob
)
{
sefl
.
_images
[
src
].
src
=
(
window
.
URL
||
window
.
webkitURL
).
createObjectURL
(
blob
)
}
/**
* 从本地文件加载
* @param {string} path 文件路径
*/
function
loadFile
(
path
)
{
var
bitmap
=
new
plus
.
nativeObj
.
Bitmap
(
'
bitmap
'
+
Date
.
now
())
bitmap
.
load
(
path
,
function
()
{
sefl
.
_images
[
src
].
src
=
bitmap
.
toBase64Data
()
bitmap
.
clear
()
},
function
()
{
bitmap
.
clear
()
console
.
error
(
'
preloadImage error
'
)
})
}
/**
* 从网络加载
* @param {string} url 文件地址
*/
function
loadUrl
(
url
)
{
function
plusDownload
()
{
plus
.
downloader
.
createDownload
(
url
,
{
filename
:
'
_doc/uniapp_temp/download/
'
},
function
(
d
,
status
)
{
if
(
status
===
200
)
{
loadFile
(
d
.
filename
)
}
else
{
sefl
.
_images
[
src
].
src
=
src
}
}).
start
()
}
var
xhr
=
new
XMLHttpRequest
()
xhr
.
open
(
'
GET
'
,
url
,
true
)
xhr
.
responseType
=
'
blob
'
xhr
.
onload
=
function
()
{
if
(
this
.
status
===
200
)
{
loadBlob
(
this
.
response
)
}
}
xhr
.
onerror
=
window
.
plus
?
plusDownload
:
function
()
{
sefl
.
_images
[
src
].
src
=
src
}
xhr
.
send
()
}
if
(
window
.
plus
&&
(
!
window
.
webkit
||
!
window
.
webkit
.
messageHandlers
))
{
sefl
.
_images
[
src
].
src
=
src
}
else
{
// 解决 PLUS-APP(wkwebview)以及 H5 图像跨域问题(H5图像响应头需包含access-control-allow-origin)
if
(
window
.
plus
&&
src
.
indexOf
(
'
http://
'
)
!==
0
&&
src
.
indexOf
(
'
https://
'
)
!==
0
)
{
loadFile
(
src
)
}
else
if
(
/^data:
[
a-z-
]
+
\/[
a-z-
]
+;base64,/
.
test
(
src
))
{
sefl
.
_images
[
src
].
src
=
src
}
else
{
loadUrl
(
src
)
}
}
}
})
},
checkImageLoaded
:
function
(
src
,
actions
,
callbackId
,
fn
)
{
var
self
=
this
var
image
=
this
.
_images
[
src
]
if
(
image
.
ready
)
{
fn
(
image
)
return
true
}
else
{
this
.
_actionsDefer
.
unshift
([
actions
,
true
])
this
.
actionsWaiting
=
true
image
.
onload
=
function
()
{
image
.
ready
=
true
fn
(
image
)
self
.
actionsWaiting
=
false
var
actions
=
self
.
_actionsDefer
.
slice
(
0
)
self
.
_actionsDefer
=
[]
for
(
var
action
=
actions
.
shift
();
action
;)
{
self
.
actionsChanged
({
actions
:
action
[
0
],
reserve
:
action
[
1
],
callbackId
})
action
=
actions
.
shift
()
}
}
return
false
}
},
getImageData
({
x
,
y
,
width
,
height
,
callbackId
})
{
var
imgData
var
canvas
=
this
.
$refs
.
canvas
if
(
!
width
)
{
width
=
canvas
.
width
}
if
(
!
height
)
{
height
=
canvas
.
height
}
try
{
imgData
=
canvas
.
getContext
(
'
2d
'
).
getImageData
(
x
,
y
,
width
,
height
)
}
catch
(
error
)
{
UniViewJSBridge
.
publishHandler
(
'
onCanvasMethodCallback
'
,
{
callbackId
,
data
:
{
errMsg
:
'
canvasGetImageData:fail
'
}
},
this
.
$page
.
id
)
return
}
UniViewJSBridge
.
publishHandler
(
'
onCanvasMethodCallback
'
,
{
callbackId
,
data
:
{
errMsg
:
'
canvasGetImageData:ok
'
,
data
:
[...
imgData
.
data
],
width
,
height
}
},
this
.
$page
.
id
)
},
putImageData
({
data
,
x
,
y
,
width
,
height
,
callbackId
})
{
try
{
if
(
!
height
)
{
height
=
Math
.
round
(
data
.
length
/
4
/
width
)
}
this
.
$refs
.
canvas
.
getContext
(
'
2d
'
).
putImageData
(
new
ImageData
(
new
Uint8ClampedArray
(
data
),
width
,
height
),
x
,
y
)
}
catch
(
error
)
{
UniViewJSBridge
.
publishHandler
(
'
onCanvasMethodCallback
'
,
{
callbackId
,
data
:
{
errMsg
:
'
canvasPutImageData:fail
'
}
},
this
.
$page
.
id
)
return
}
UniViewJSBridge
.
publishHandler
(
'
onCanvasMethodCallback
'
,
{
callbackId
,
data
:
{
errMsg
:
'
canvasPutImageData:ok
'
}
},
this
.
$page
.
id
)
}
}
}
</
script
>
<
style
>
uni-canvas
{
width
:
300px
;
height
:
150px
;
display
:
block
;
position
:
relative
;
}
uni-canvas
>
canvas
{
position
:
absolute
;
top
:
0
;
left
:
0
;
width
:
100%
;
height
:
100%
;
}
</
style
>
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录