导出d的图片支持background-size/position/repeat属性效果

This commit is contained in:
wanglin2 2023-02-01 16:25:57 +08:00
parent 9914eef5b9
commit 74a52ea386
10 changed files with 543 additions and 75 deletions

View File

@ -1,6 +1,7 @@
import { imgToDataUrl, downloadFile } from './utils' import { imgToDataUrl, downloadFile } from './utils'
import JsPDF from 'jspdf' import JsPDF from 'jspdf'
import { SVG } from '@svgdotjs/svg.js' import { SVG } from '@svgdotjs/svg.js'
import drawBackgroundImageToCanvas from './utils/simulateCSSBackgroundInCanvas'
const URL = window.URL || window.webkitURL || window const URL = window.URL || window.webkitURL || window
// 导出类 // 导出类
@ -85,7 +86,9 @@ class Export {
let { let {
backgroundColor = '#fff', backgroundColor = '#fff',
backgroundImage, backgroundImage,
backgroundRepeat = 'repeat' backgroundRepeat = 'no-repeat',
backgroundPosition = 'center center',
backgroundSize = 'cover',
} = this.mindMap.themeConfig } = this.mindMap.themeConfig
// 背景颜色 // 背景颜色
ctx.save() ctx.save()
@ -96,19 +99,18 @@ class Export {
// 背景图片 // 背景图片
if (backgroundImage && backgroundImage !== 'none') { if (backgroundImage && backgroundImage !== 'none') {
ctx.save() ctx.save()
let img = new Image() drawBackgroundImageToCanvas(ctx, width, height, backgroundImage, {
img.src = backgroundImage backgroundRepeat,
img.onload = () => { backgroundPosition,
let pat = ctx.createPattern(img, backgroundRepeat) backgroundSize
ctx.rect(0, 0, width, height) }, (err) => {
ctx.fillStyle = pat if (err) {
ctx.fill() reject(err)
} else {
resolve()
}
ctx.restore() ctx.restore()
resolve() })
}
img.onerror = e => {
reject(e)
}
} else { } else {
resolve() resolve()
} }

View File

@ -0,0 +1,354 @@
// 将以空格分隔的字符串值转换成成数字/单位/值数组
const getNumberValueFromStr = value => {
let arr = String(value).split(/\s+/)
return arr.map(item => {
if (/^[\d.]+/.test(item)) {
// 数字+单位
let res = /^([\d.]+)(.*)$/.exec(item)
return [Number(res[1]), res[2]]
} else {
// 单个值
return item
}
})
}
// 缩放宽度
const zoomWidth = (ratio, height) => {
// w / height = ratio
return ratio * height
}
// 缩放高度
const zoomHeight = (ratio, width) => {
// width / h = ratio
return width / ratio
}
// 关键词到百分比值的映射
const keyWordToPercentageMap = {
left: 0,
top: 0,
center: 50,
bottom: 100,
right: 100
}
// 模拟background-size
const handleBackgroundSize = ({
backgroundSize,
drawOpt,
imageRatio,
canvasWidth,
canvasHeight,
canvasRatio
}) => {
if (backgroundSize) {
// 将值转换成数组
let backgroundSizeValueArr = getNumberValueFromStr(backgroundSize)
// 两个值都为auto那就相当于不设置
if (
backgroundSizeValueArr[0] === 'auto' &&
backgroundSizeValueArr[1] === 'auto'
) {
return
}
// 值为cover
if (backgroundSizeValueArr[0] === 'cover') {
if (imageRatio > canvasRatio) {
// 图片的宽高比大于canvas的宽高比那么图片高度缩放到和canvas的高度一致宽度自适应
drawOpt.height = canvasHeight
drawOpt.width = zoomWidth(imageRatio, canvasHeight)
} else {
// 否则图片宽度缩放到和canvas的宽度一致高度自适应
drawOpt.width = canvasWidth
drawOpt.height = zoomHeight(imageRatio, canvasWidth)
}
return
}
// 值为contain
if (backgroundSizeValueArr[0] === 'contain') {
if (imageRatio > canvasRatio) {
// 图片的宽高比大于canvas的宽高比那么图片宽度缩放到和canvas的宽度一致高度自适应
drawOpt.width = canvasWidth
drawOpt.height = zoomHeight(imageRatio, canvasWidth)
} else {
// 否则图片高度缩放到和canvas的高度一致宽度自适应
drawOpt.height = canvasHeight
drawOpt.width = zoomWidth(imageRatio, canvasHeight)
}
return
}
// 图片宽度
let newNumberWidth = -1
if (backgroundSizeValueArr[0]) {
if (Array.isArray(backgroundSizeValueArr[0])) {
// 数字+单位类型
if (backgroundSizeValueArr[0][1] === '%') {
// %单位
drawOpt.width = (backgroundSizeValueArr[0][0] / 100) * canvasWidth
newNumberWidth = drawOpt.width
} else {
// 其他都认为是px单位
drawOpt.width = backgroundSizeValueArr[0][0]
newNumberWidth = backgroundSizeValueArr[0][0]
}
} else if (backgroundSizeValueArr[0] === 'auto') {
// auto类型那么根据设置的新高度以图片原宽高比进行自适应
if (backgroundSizeValueArr[1]) {
if (backgroundSizeValueArr[1][1] === '%') {
// 高度为%单位
drawOpt.width = zoomWidth(
imageRatio,
(backgroundSizeValueArr[1][0] / 100) * canvasHeight
)
} else {
// 其他都认为是px单位
drawOpt.width = zoomWidth(imageRatio, backgroundSizeValueArr[1][0])
}
}
}
}
// 设置了图片高度
if (backgroundSizeValueArr[1] && Array.isArray(backgroundSizeValueArr[1])) {
// 数字+单位类型
if (backgroundSizeValueArr[1][1] === '%') {
// 高度为%单位
drawOpt.height = (backgroundSizeValueArr[1][0] / 100) * canvasHeight
} else {
// 其他都认为是px单位
drawOpt.height = backgroundSizeValueArr[1][0]
}
} else if (newNumberWidth !== -1) {
// 没有设置图片高度或者设置为auto那么根据设置的新宽度以图片原宽高比进行自适应
drawOpt.height = zoomHeight(imageRatio, newNumberWidth)
}
}
}
// 模拟background-position
const handleBackgroundPosition = ({
backgroundPosition,
drawOpt,
imgWidth,
imgHeight,
canvasWidth,
canvasHeight
}) => {
if (backgroundPosition) {
// 将值转换成数组
let backgroundPositionValueArr = getNumberValueFromStr(backgroundPosition)
// 将关键词转为百分比
backgroundPositionValueArr = backgroundPositionValueArr.map(item => {
if (typeof item === 'string') {
return keyWordToPercentageMap[item] !== undefined
? [keyWordToPercentageMap[item], '%']
: item
}
return item
})
if (Array.isArray(backgroundPositionValueArr[0])) {
if (backgroundPositionValueArr.length === 1) {
// 如果只设置了一个值第二个默认为50%
backgroundPositionValueArr.push([50, '%'])
}
// 水平位置
if (backgroundPositionValueArr[0][1] === '%') {
// 单位为%
let canvasX = (backgroundPositionValueArr[0][0] / 100) * canvasWidth
let imgX = (backgroundPositionValueArr[0][0] / 100) * imgWidth
// 计算差值
drawOpt.x = canvasX - imgX
} else {
// 其他单位默认都为px
drawOpt.x = backgroundPositionValueArr[0][0]
}
// 垂直位置
if (backgroundPositionValueArr[1][1] === '%') {
// 单位为%
let canvasY = (backgroundPositionValueArr[1][0] / 100) * canvasHeight
let imgY = (backgroundPositionValueArr[1][0] / 100) * imgHeight
// 计算差值
drawOpt.y = canvasY - imgY
} else {
// 其他单位默认都为px
drawOpt.y = backgroundPositionValueArr[1][0]
}
}
}
}
// 模拟background-repeat
const handleBackgroundRepeat = ({
ctx,
image,
backgroundRepeat,
drawOpt,
imgWidth,
imgHeight,
canvasWidth,
canvasHeight
}) => {
if (backgroundRepeat) {
// 保存在handleBackgroundPosition中计算出来的x、y
let ox = drawOpt.x
let oy = drawOpt.y
// 计算ox和oy能平铺的图片数量
let oxRepeatNum = Math.ceil(ox / imgWidth)
let oyRepeatNum = Math.ceil(oy / imgHeight)
// 计算ox和oy第一张图片的位置
let oxRepeatX = ox - oxRepeatNum * imgWidth
let oxRepeatY = oy - oyRepeatNum * imgHeight
// 将值转换成数组
let backgroundRepeatValueArr = getNumberValueFromStr(backgroundRepeat)
// 不处理
if (
backgroundRepeatValueArr[0] === 'no-repeat' ||
(imgWidth >= canvasWidth && imgHeight >= canvasHeight)
) {
return
}
// 水平平铺
if (backgroundRepeatValueArr[0] === 'repeat-x') {
if (canvasWidth > imgWidth) {
let x = oxRepeatX
while (x < canvasWidth) {
drawImage(ctx, image, {
...drawOpt,
x
})
x += imgWidth
}
return true
}
}
// 垂直平铺
if (backgroundRepeatValueArr[0] === 'repeat-y') {
if (canvasHeight > imgHeight) {
let y = oxRepeatY
while (y < canvasHeight) {
drawImage(ctx, image, {
...drawOpt,
y
})
y += imgHeight
}
return true
}
}
// 平铺
if (backgroundRepeatValueArr[0] === 'repeat') {
let x = oxRepeatX
while (x < canvasWidth) {
if (canvasHeight > imgHeight) {
let y = oxRepeatY
while (y < canvasHeight) {
drawImage(ctx, image, {
...drawOpt,
x,
y
})
y += imgHeight
}
}
x += imgWidth
}
return true
}
}
}
// 根据参数绘制图片
const drawImage = (ctx, image, drawOpt) => {
ctx.drawImage(
image,
drawOpt.sx,
drawOpt.sy,
drawOpt.swidth,
drawOpt.sheight,
drawOpt.x,
drawOpt.y,
drawOpt.width,
drawOpt.height
)
}
const drawBackgroundImageToCanvas = (
ctx,
width,
height,
img,
{ backgroundSize, backgroundPosition, backgroundRepeat },
callback = () => {}
) => {
// 画布的长宽比
let canvasRatio = width / height
// 加载图片
let image = new Image()
image.src = img
image.onload = () => {
// 图片的宽度及长宽比
let imgWidth = image.width
let imgHeight = image.height
let imageRatio = imgWidth / imgHeight
// 绘制图片
// drawImage方法的参数值
let drawOpt = {
sx: 0,
sy: 0,
swidth: imgWidth,
sheight: imgHeight,
x: 0,
y: 0,
width: imgWidth,
height: imgHeight
}
// 模拟background-size
handleBackgroundSize({
backgroundSize,
drawOpt,
imageRatio,
canvasWidth: width,
canvasHeight: height,
canvasRatio
})
// 模拟background-position
handleBackgroundPosition({
backgroundPosition,
drawOpt,
imgWidth: drawOpt.width,
imgHeight: drawOpt.height,
imageRatio,
canvasWidth: width,
canvasHeight: height,
canvasRatio
})
// 模拟background-repeat
let notNeedDraw = handleBackgroundRepeat({
ctx,
image,
backgroundRepeat,
drawOpt,
imgWidth: drawOpt.width,
imgHeight: drawOpt.height,
imageRatio,
canvasWidth: width,
canvasHeight: height,
canvasRatio
})
// 绘制图片
if (!notNeedDraw) {
drawImage(ctx, image, drawOpt)
}
callback()
}
image.onerror = e => {
callback(e)
}
}
export default drawBackgroundImageToCanvas

View File

@ -4,7 +4,7 @@
Fix: 1.The problem that deleting the background image does not take effect; 2.The problem that the connector runs above the root node when the node is dragged to the root node. Fix: 1.The problem that deleting the background image does not take effect; 2.The problem that the connector runs above the root node when the node is dragged to the root node.
New: Add position and size settings for background image display. New: Add position and size settings for background image display. This setting is also supported for exported pictures.
## 0.3.0 ## 0.3.0

View File

@ -3,7 +3,7 @@
<h1>Changelog</h1> <h1>Changelog</h1>
<h2>0.3.1</h2> <h2>0.3.1</h2>
<p>Fix: 1.The problem that deleting the background image does not take effect; 2.The problem that the connector runs above the root node when the node is dragged to the root node.</p> <p>Fix: 1.The problem that deleting the background image does not take effect; 2.The problem that the connector runs above the root node when the node is dragged to the root node.</p>
<p>New: Add position and size settings for background image display.</p> <p>New: Add position and size settings for background image display. This setting is also supported for exported pictures.</p>
<h2>0.3.0</h2> <h2>0.3.0</h2>
<p>Upgrade to plugin architecture, pull out some non-core functions as plugins, register as needed, and reduce the overall volume.</p> <p>Upgrade to plugin architecture, pull out some non-core functions as plugins, register as needed, and reduce the overall volume.</p>
<h2>0.2.24</h2> <h2>0.2.24</h2>

View File

@ -1,14 +1,16 @@
# Utility Methods # Utility Methods
## Base utility Methods
Reference: Reference:
```js ```js
import {walk, ...} from 'simple-mind-map/src/utils' import {walk, ...} from 'simple-mind-map/src/utils'
``` ```
## Methods ### Methods
### walk(root, parent, beforeCallback, afterCallback, isRoot, layerIndex = 0, index = 0) #### walk(root, parent, beforeCallback, afterCallback, isRoot, layerIndex = 0, index = 0)
Depth-first traversal of a tree Depth-first traversal of a tree
@ -34,11 +36,11 @@ Example:
walk(tree, null, () => {}, () => {}, false, 0, 0); walk(tree, null, () => {}, () => {}, false, 0, 0);
``` ```
### bfsWalk(root, callback) #### bfsWalk(root, callback)
Breadth-first traversal of a tree Breadth-first traversal of a tree
### resizeImgSize(width, height, maxWidth, maxHeight) #### resizeImgSize(width, height, maxWidth, maxHeight)
Resize image size Resize image size
@ -52,17 +54,17 @@ Resize image size
`maxWidth` and `maxHeight` can both be passed, or only one of them can be passed `maxWidth` and `maxHeight` can both be passed, or only one of them can be passed
### resizeImg(imgUrl, maxWidth, maxHeight) #### resizeImg(imgUrl, maxWidth, maxHeight)
Resize image, internally loads the image first, then calls the `resizeImgSize` Resize image, internally loads the image first, then calls the `resizeImgSize`
method, and returns a `promise` method, and returns a `promise`
### simpleDeepClone(data) #### simpleDeepClone(data)
Extremely simple deep copy method, can only be used for objects that are all Extremely simple deep copy method, can only be used for objects that are all
basic data, otherwise it will throw an error basic data, otherwise it will throw an error
### copyRenderTree(tree, root) #### copyRenderTree(tree, root)
Copy render tree data, example: Copy render tree data, example:
@ -70,7 +72,7 @@ Copy render tree data, example:
copyRenderTree({}, this.mindMap.renderer.renderTree); copyRenderTree({}, this.mindMap.renderer.renderTree);
``` ```
### copyNodeTree(tree, root) #### copyNodeTree(tree, root)
Copy node tree data, mainly eliminating the reference `node` instance `_node` Copy node tree data, mainly eliminating the reference `node` instance `_node`
and copying the `data` of the data object, example: and copying the `data` of the data object, example:
@ -79,30 +81,60 @@ and copying the `data` of the data object, example:
copyNodeTree({}, node); copyNodeTree({}, node);
``` ```
### imgToDataUrl(src) #### imgToDataUrl(src)
Convert image to dataURL Convert image to dataURL
### downloadFile(file, fileName) #### downloadFile(file, fileName)
Download file Download file
### throttle(fn, time = 300, ctx) #### throttle(fn, time = 300, ctx)
Throttle function Throttle function
### asyncRun(taskList, callback = () => {}) #### asyncRun(taskList, callback = () => {})
Run tasks in task list asynchronously, tasks are run synchronously without order Run tasks in task list asynchronously, tasks are run synchronously without order
### degToRad(deg) #### degToRad(deg)
> v0.2.24+ > v0.2.24+
Angle to radian Angle to radian
### camelCaseToHyphen(str) #### camelCaseToHyphen(str)
> v0.2.24+ > v0.2.24+
CamelCase to hyphen CamelCase to hyphen
## Simulate CSS background in Canvas
Import:
```js
import drawBackgroundImageToCanvas from 'simple-mind-map/src/utils/simulateCSSBackgroundInCanvas'
```
Usage
```js
let width = 500
let height = 500
let img = '/1.jpg'
let canvas = document.createElement('canvas')
canvas.width = width
canvas.height = height
drawBackgroundImageToCanvas(ctx, width, height, img, {
backgroundRepeat: 'repeat-y',
backgroundSize: '60%',
backgroundPosition: 'center center'
}, (err) => {
if (err) {
// fail
} else {
// success
}
})
```

View File

@ -1,11 +1,12 @@
<template> <template>
<div> <div>
<h1>Utility Methods</h1> <h1>Utility Methods</h1>
<h2>Base utility Methods</h2>
<p>Reference:</p> <p>Reference:</p>
<pre class="hljs"><code><span class="hljs-keyword">import</span> {walk, ...} <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/utils&#x27;</span> <pre class="hljs"><code><span class="hljs-keyword">import</span> {walk, ...} <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/utils&#x27;</span>
</code></pre> </code></pre>
<h2>Methods</h2> <h3>Methods</h3>
<h3>walk(root, parent, beforeCallback, afterCallback, isRoot, layerIndex = 0, index = 0)</h3> <h4>walk(root, parent, beforeCallback, afterCallback, isRoot, layerIndex = 0, index = 0)</h4>
<p>Depth-first traversal of a tree</p> <p>Depth-first traversal of a tree</p>
<p><code>root</code>: the root node of the tree to be traversed</p> <p><code>root</code>: the root node of the tree to be traversed</p>
<p><code>parent</code>: parent node</p> <p><code>parent</code>: parent node</p>
@ -19,48 +20,71 @@ root, parent, isRoot, layerIndex, index</p>
<p>Example:</p> <p>Example:</p>
<pre class="hljs"><code>walk(tree, <span class="hljs-literal">null</span>, <span class="hljs-function">() =&gt;</span> {}, <span class="hljs-function">() =&gt;</span> {}, <span class="hljs-literal">false</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>); <pre class="hljs"><code>walk(tree, <span class="hljs-literal">null</span>, <span class="hljs-function">() =&gt;</span> {}, <span class="hljs-function">() =&gt;</span> {}, <span class="hljs-literal">false</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>);
</code></pre> </code></pre>
<h3>bfsWalk(root, callback)</h3> <h4>bfsWalk(root, callback)</h4>
<p>Breadth-first traversal of a tree</p> <p>Breadth-first traversal of a tree</p>
<h3>resizeImgSize(width, height, maxWidth, maxHeight)</h3> <h4>resizeImgSize(width, height, maxWidth, maxHeight)</h4>
<p>Resize image size</p> <p>Resize image size</p>
<p><code>width</code>: original width of the image</p> <p><code>width</code>: original width of the image</p>
<p><code>height</code>: original height of the image</p> <p><code>height</code>: original height of the image</p>
<p><code>maxWidth</code>: the width to resize to</p> <p><code>maxWidth</code>: the width to resize to</p>
<p><code>maxHeight</code>: the height to resize to</p> <p><code>maxHeight</code>: the height to resize to</p>
<p><code>maxWidth</code> and <code>maxHeight</code> can both be passed, or only one of them can be passed</p> <p><code>maxWidth</code> and <code>maxHeight</code> can both be passed, or only one of them can be passed</p>
<h3>resizeImg(imgUrl, maxWidth, maxHeight)</h3> <h4>resizeImg(imgUrl, maxWidth, maxHeight)</h4>
<p>Resize image, internally loads the image first, then calls the <code>resizeImgSize</code> <p>Resize image, internally loads the image first, then calls the <code>resizeImgSize</code>
method, and returns a <code>promise</code></p> method, and returns a <code>promise</code></p>
<h3>simpleDeepClone(data)</h3> <h4>simpleDeepClone(data)</h4>
<p>Extremely simple deep copy method, can only be used for objects that are all <p>Extremely simple deep copy method, can only be used for objects that are all
basic data, otherwise it will throw an error</p> basic data, otherwise it will throw an error</p>
<h3>copyRenderTree(tree, root)</h3> <h4>copyRenderTree(tree, root)</h4>
<p>Copy render tree data, example:</p> <p>Copy render tree data, example:</p>
<pre class="hljs"><code>copyRenderTree({}, <span class="hljs-built_in">this</span>.mindMap.renderer.renderTree); <pre class="hljs"><code>copyRenderTree({}, <span class="hljs-built_in">this</span>.mindMap.renderer.renderTree);
</code></pre> </code></pre>
<h3>copyNodeTree(tree, root)</h3> <h4>copyNodeTree(tree, root)</h4>
<p>Copy node tree data, mainly eliminating the reference <code>node</code> instance <code>_node</code> <p>Copy node tree data, mainly eliminating the reference <code>node</code> instance <code>_node</code>
and copying the <code>data</code> of the data object, example:</p> and copying the <code>data</code> of the data object, example:</p>
<pre class="hljs"><code>copyNodeTree({}, node); <pre class="hljs"><code>copyNodeTree({}, node);
</code></pre> </code></pre>
<h3>imgToDataUrl(src)</h3> <h4>imgToDataUrl(src)</h4>
<p>Convert image to dataURL</p> <p>Convert image to dataURL</p>
<h3>downloadFile(file, fileName)</h3> <h4>downloadFile(file, fileName)</h4>
<p>Download file</p> <p>Download file</p>
<h3>throttle(fn, time = 300, ctx)</h3> <h4>throttle(fn, time = 300, ctx)</h4>
<p>Throttle function</p> <p>Throttle function</p>
<h3>asyncRun(taskList, callback = () =&gt; {})</h3> <h4>asyncRun(taskList, callback = () =&gt; {})</h4>
<p>Run tasks in task list asynchronously, tasks are run synchronously without order</p> <p>Run tasks in task list asynchronously, tasks are run synchronously without order</p>
<h3>degToRad(deg)</h3> <h4>degToRad(deg)</h4>
<blockquote> <blockquote>
<p>v0.2.24+</p> <p>v0.2.24+</p>
</blockquote> </blockquote>
<p>Angle to radian</p> <p>Angle to radian</p>
<h3>camelCaseToHyphen(str)</h3> <h4>camelCaseToHyphen(str)</h4>
<blockquote> <blockquote>
<p>v0.2.24+</p> <p>v0.2.24+</p>
</blockquote> </blockquote>
<p>CamelCase to hyphen</p> <p>CamelCase to hyphen</p>
<h2>Simulate CSS background in Canvas</h2>
<p>Import:</p>
<pre class="hljs"><code><span class="hljs-keyword">import</span> drawBackgroundImageToCanvas <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/utils/simulateCSSBackgroundInCanvas&#x27;</span>
</code></pre>
<p>Usage</p>
<pre class="hljs"><code><span class="hljs-keyword">let</span> width = <span class="hljs-number">500</span>
<span class="hljs-keyword">let</span> height = <span class="hljs-number">500</span>
<span class="hljs-keyword">let</span> img = <span class="hljs-string">&#x27;/1.jpg&#x27;</span>
<span class="hljs-keyword">let</span> canvas = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">&#x27;canvas&#x27;</span>)
canvas.width = width
canvas.height = height
drawBackgroundImageToCanvas(ctx, width, height, img, {
<span class="hljs-attr">backgroundRepeat</span>: <span class="hljs-string">&#x27;repeat-y&#x27;</span>,
<span class="hljs-attr">backgroundSize</span>: <span class="hljs-string">&#x27;60%&#x27;</span>,
<span class="hljs-attr">backgroundPosition</span>: <span class="hljs-string">&#x27;center center&#x27;</span>
}, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
<span class="hljs-keyword">if</span> (err) {
<span class="hljs-comment">// fail</span>
} <span class="hljs-keyword">else</span> {
<span class="hljs-comment">// success</span>
}
})
</code></pre>
</div> </div>
</template> </template>

View File

@ -4,7 +4,7 @@
修复1.删除背景图片不生效的问题2.节点拖拽到根节点时连接线跑到根节点上方的问题。 修复1.删除背景图片不生效的问题2.节点拖拽到根节点时连接线跑到根节点上方的问题。
新增:背景图片展示增加位置和大小设置。 新增:背景图片展示增加位置和大小设置。导出的图片也同步支持该设置。
## 0.3.0 ## 0.3.0

View File

@ -3,7 +3,7 @@
<h1>Changelog</h1> <h1>Changelog</h1>
<h2>0.3.1</h2> <h2>0.3.1</h2>
<p>修复1.删除背景图片不生效的问题2.节点拖拽到根节点时连接线跑到根节点上方的问题</p> <p>修复1.删除背景图片不生效的问题2.节点拖拽到根节点时连接线跑到根节点上方的问题</p>
<p>新增背景图片展示增加位置和大小设置</p> <p>新增背景图片展示增加位置和大小设置导出的图片也同步支持该设置</p>
<h2>0.3.0</h2> <h2>0.3.0</h2>
<p>升级为插件化架构将一些非核心功能抽离出来作为插件按需注册减小整体体积</p> <p>升级为插件化架构将一些非核心功能抽离出来作为插件按需注册减小整体体积</p>
<h2>0.2.24</h2> <h2>0.2.24</h2>

View File

@ -1,14 +1,16 @@
# 内置工具方法 # 内置工具方法
## 基础工具方法
引用: 引用:
```js ```js
import {walk, ...} from 'simple-mind-map/src/utils' import {walk, ...} from 'simple-mind-map/src/utils'
``` ```
## 方法 ### 方法
### walk(root, parent, beforeCallback, afterCallback, isRoot, layerIndex = 0, index = 0) #### walk(root, parent, beforeCallback, afterCallback, isRoot, layerIndex = 0, index = 0)
深度优先遍历树 深度优先遍历树
@ -32,11 +34,11 @@ import {walk, ...} from 'simple-mind-map/src/utils'
walk(tree, null, () => {}, () => {}, false, 0, 0) walk(tree, null, () => {}, () => {}, false, 0, 0)
``` ```
### bfsWalk(root, callback) #### bfsWalk(root, callback)
广度优先遍历树 广度优先遍历树
### resizeImgSize(width, height, maxWidth, maxHeight) #### resizeImgSize(width, height, maxWidth, maxHeight)
缩放图片的尺寸 缩放图片的尺寸
@ -50,15 +52,15 @@ walk(tree, null, () => {}, () => {}, false, 0, 0)
`maxWidth``maxHeight`可以同时都传,也可以只传一个 `maxWidth``maxHeight`可以同时都传,也可以只传一个
### resizeImg(imgUrl, maxWidth, maxHeight) #### resizeImg(imgUrl, maxWidth, maxHeight)
缩放图片,内部先加载图片,然后调用`resizeImgSize`方法,返回一个`promise` 缩放图片,内部先加载图片,然后调用`resizeImgSize`方法,返回一个`promise`
### simpleDeepClone(data) #### simpleDeepClone(data)
极简的深拷贝方法,只能针对全是基本数据的对象,否则会报错 极简的深拷贝方法,只能针对全是基本数据的对象,否则会报错
### copyRenderTree(tree, root) #### copyRenderTree(tree, root)
复制渲染树数据,示例: 复制渲染树数据,示例:
@ -66,7 +68,7 @@ walk(tree, null, () => {}, () => {}, false, 0, 0)
copyRenderTree({}, this.mindMap.renderer.renderTree) copyRenderTree({}, this.mindMap.renderer.renderTree)
``` ```
### copyNodeTree(tree, root) #### copyNodeTree(tree, root)
复制节点树数据,主要是剔除其中的引用`node`实例的`_node`,然后复制`data`对象的数据,示例: 复制节点树数据,主要是剔除其中的引用`node`实例的`_node`,然后复制`data`对象的数据,示例:
@ -74,30 +76,60 @@ copyRenderTree({}, this.mindMap.renderer.renderTree)
copyNodeTree({}, node) copyNodeTree({}, node)
``` ```
### imgToDataUrl(src) #### imgToDataUrl(src)
图片转成dataURL 图片转成dataURL
### downloadFile(file, fileName) #### downloadFile(file, fileName)
下载文件 下载文件
### throttle(fn, time = 300, ctx) #### throttle(fn, time = 300, ctx)
节流函数 节流函数
### asyncRun(taskList, callback = () => {}) #### asyncRun(taskList, callback = () => {})
异步执行任务队列,多个任务是同步执行的,没有先后顺序 异步执行任务队列,多个任务是同步执行的,没有先后顺序
### degToRad(deg) #### degToRad(deg)
> v0.2.24+ > v0.2.24+
角度转弧度 角度转弧度
### camelCaseToHyphen(str) #### camelCaseToHyphen(str)
> v0.2.24+ > v0.2.24+
驼峰转连字符 驼峰转连字符
## 在canvas中模拟css的背景属性
引入:
```js
import drawBackgroundImageToCanvas from 'simple-mind-map/src/utils/simulateCSSBackgroundInCanvas'
```
使用:
```js
let width = 500
let height = 500
let img = '/1.jpg'
let canvas = document.createElement('canvas')
canvas.width = width
canvas.height = height
drawBackgroundImageToCanvas(ctx, width, height, img, {
backgroundRepeat: 'repeat-y',
backgroundSize: '60%',
backgroundPosition: 'center center'
}, (err) => {
if (err) {
// 失败
} else {
// 成功
}
})
```

View File

@ -1,11 +1,12 @@
<template> <template>
<div> <div>
<h1>内置工具方法</h1> <h1>内置工具方法</h1>
<h2>基础工具方法</h2>
<p>引用</p> <p>引用</p>
<pre class="hljs"><code><span class="hljs-keyword">import</span> {walk, ...} <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/utils&#x27;</span> <pre class="hljs"><code><span class="hljs-keyword">import</span> {walk, ...} <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/utils&#x27;</span>
</code></pre> </code></pre>
<h2>方法</h2> <h3>方法</h3>
<h3>walk(root, parent, beforeCallback, afterCallback, isRoot, layerIndex = 0, index = 0)</h3> <h4>walk(root, parent, beforeCallback, afterCallback, isRoot, layerIndex = 0, index = 0)</h4>
<p>深度优先遍历树</p> <p>深度优先遍历树</p>
<p><code>root</code>要遍历的树的根节点</p> <p><code>root</code>要遍历的树的根节点</p>
<p><code>parent</code>父节点</p> <p><code>parent</code>父节点</p>
@ -17,45 +18,68 @@
<p>示例</p> <p>示例</p>
<pre class="hljs"><code>walk(tree, <span class="hljs-literal">null</span>, <span class="hljs-function">() =&gt;</span> {}, <span class="hljs-function">() =&gt;</span> {}, <span class="hljs-literal">false</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>) <pre class="hljs"><code>walk(tree, <span class="hljs-literal">null</span>, <span class="hljs-function">() =&gt;</span> {}, <span class="hljs-function">() =&gt;</span> {}, <span class="hljs-literal">false</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>)
</code></pre> </code></pre>
<h3>bfsWalk(root, callback)</h3> <h4>bfsWalk(root, callback)</h4>
<p>广度优先遍历树</p> <p>广度优先遍历树</p>
<h3>resizeImgSize(width, height, maxWidth, maxHeight)</h3> <h4>resizeImgSize(width, height, maxWidth, maxHeight)</h4>
<p>缩放图片的尺寸</p> <p>缩放图片的尺寸</p>
<p><code>width</code>图片原本的宽</p> <p><code>width</code>图片原本的宽</p>
<p><code>height</code>图片原本的高</p> <p><code>height</code>图片原本的高</p>
<p><code>maxWidth</code>要缩放到的宽</p> <p><code>maxWidth</code>要缩放到的宽</p>
<p><code>maxHeight</code>要缩放到的高</p> <p><code>maxHeight</code>要缩放到的高</p>
<p><code>maxWidth</code><code>maxHeight</code>可以同时都传也可以只传一个</p> <p><code>maxWidth</code><code>maxHeight</code>可以同时都传也可以只传一个</p>
<h3>resizeImg(imgUrl, maxWidth, maxHeight)</h3> <h4>resizeImg(imgUrl, maxWidth, maxHeight)</h4>
<p>缩放图片内部先加载图片然后调用<code>resizeImgSize</code>方法返回一个<code>promise</code></p> <p>缩放图片内部先加载图片然后调用<code>resizeImgSize</code>方法返回一个<code>promise</code></p>
<h3>simpleDeepClone(data)</h3> <h4>simpleDeepClone(data)</h4>
<p>极简的深拷贝方法只能针对全是基本数据的对象否则会报错</p> <p>极简的深拷贝方法只能针对全是基本数据的对象否则会报错</p>
<h3>copyRenderTree(tree, root)</h3> <h4>copyRenderTree(tree, root)</h4>
<p>复制渲染树数据示例</p> <p>复制渲染树数据示例</p>
<pre class="hljs"><code>copyRenderTree({}, <span class="hljs-built_in">this</span>.mindMap.renderer.renderTree) <pre class="hljs"><code>copyRenderTree({}, <span class="hljs-built_in">this</span>.mindMap.renderer.renderTree)
</code></pre> </code></pre>
<h3>copyNodeTree(tree, root)</h3> <h4>copyNodeTree(tree, root)</h4>
<p>复制节点树数据主要是剔除其中的引用<code>node</code>实例的<code>_node</code>然后复制<code>data</code>对象的数据示例</p> <p>复制节点树数据主要是剔除其中的引用<code>node</code>实例的<code>_node</code>然后复制<code>data</code>对象的数据示例</p>
<pre class="hljs"><code>copyNodeTree({}, node) <pre class="hljs"><code>copyNodeTree({}, node)
</code></pre> </code></pre>
<h3>imgToDataUrl(src)</h3> <h4>imgToDataUrl(src)</h4>
<p>图片转成dataURL</p> <p>图片转成dataURL</p>
<h3>downloadFile(file, fileName)</h3> <h4>downloadFile(file, fileName)</h4>
<p>下载文件</p> <p>下载文件</p>
<h3>throttle(fn, time = 300, ctx)</h3> <h4>throttle(fn, time = 300, ctx)</h4>
<p>节流函数</p> <p>节流函数</p>
<h3>asyncRun(taskList, callback = () =&gt; {})</h3> <h4>asyncRun(taskList, callback = () =&gt; {})</h4>
<p>异步执行任务队列多个任务是同步执行的没有先后顺序</p> <p>异步执行任务队列多个任务是同步执行的没有先后顺序</p>
<h3>degToRad(deg)</h3> <h4>degToRad(deg)</h4>
<blockquote> <blockquote>
<p>v0.2.24+</p> <p>v0.2.24+</p>
</blockquote> </blockquote>
<p>角度转弧度</p> <p>角度转弧度</p>
<h3>camelCaseToHyphen(str)</h3> <h4>camelCaseToHyphen(str)</h4>
<blockquote> <blockquote>
<p>v0.2.24+</p> <p>v0.2.24+</p>
</blockquote> </blockquote>
<p>驼峰转连字符</p> <p>驼峰转连字符</p>
<h2>在canvas中模拟css的背景属性</h2>
<p>引入</p>
<pre class="hljs"><code><span class="hljs-keyword">import</span> drawBackgroundImageToCanvas <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/utils/simulateCSSBackgroundInCanvas&#x27;</span>
</code></pre>
<p>使用</p>
<pre class="hljs"><code><span class="hljs-keyword">let</span> width = <span class="hljs-number">500</span>
<span class="hljs-keyword">let</span> height = <span class="hljs-number">500</span>
<span class="hljs-keyword">let</span> img = <span class="hljs-string">&#x27;/1.jpg&#x27;</span>
<span class="hljs-keyword">let</span> canvas = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">&#x27;canvas&#x27;</span>)
canvas.width = width
canvas.height = height
drawBackgroundImageToCanvas(ctx, width, height, img, {
<span class="hljs-attr">backgroundRepeat</span>: <span class="hljs-string">&#x27;repeat-y&#x27;</span>,
<span class="hljs-attr">backgroundSize</span>: <span class="hljs-string">&#x27;60%&#x27;</span>,
<span class="hljs-attr">backgroundPosition</span>: <span class="hljs-string">&#x27;center center&#x27;</span>
}, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
<span class="hljs-keyword">if</span> (err) {
<span class="hljs-comment">// </span>
} <span class="hljs-keyword">else</span> {
<span class="hljs-comment">// </span>
}
})
</code></pre>
</div> </div>
</template> </template>