mirror of
https://github.com/SunnyQjm/taro-cropper.git
synced 2026-06-03 08:16:46 +08:00
add: 基本实现图片的移动和缩放功能
This commit is contained in:
-1
@@ -1,7 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="Stylelint" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
Generated
+86
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MarkdownProjectSettings" wasCopied="true">
|
||||
<PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.0" maxImageWidth="0" showGitHubPageIfSynced="false" allowBrowsingInPreview="false" synchronizePreviewPosition="true" highlightPreviewType="NONE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true" verticallyAlignSourceAndPreviewSyncPosition="true" showSearchHighlightsInPreview="false" showSelectionInPreview="true" openRemoteLinks="true" replaceUnicodeEmoji="false" lastLayoutSetsDefault="false">
|
||||
<PanelProvider>
|
||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.panel" providerName="Default - Swing" />
|
||||
</PanelProvider>
|
||||
</PreviewSettings>
|
||||
<ParserSettings gitHubSyntaxChange="false" emojiShortcuts="1" emojiImages="0">
|
||||
<PegdownExtensions>
|
||||
<option name="ABBREVIATIONS" value="false" />
|
||||
<option name="ANCHORLINKS" value="true" />
|
||||
<option name="ASIDE" value="false" />
|
||||
<option name="ATXHEADERSPACE" value="true" />
|
||||
<option name="AUTOLINKS" value="true" />
|
||||
<option name="DEFINITIONS" value="false" />
|
||||
<option name="DEFINITION_BREAK_DOUBLE_BLANK_LINE" value="false" />
|
||||
<option name="FENCED_CODE_BLOCKS" value="true" />
|
||||
<option name="FOOTNOTES" value="false" />
|
||||
<option name="HARDWRAPS" value="false" />
|
||||
<option name="HTML_DEEP_PARSER" value="false" />
|
||||
<option name="INSERTED" value="false" />
|
||||
<option name="QUOTES" value="false" />
|
||||
<option name="RELAXEDHRULES" value="true" />
|
||||
<option name="SMARTS" value="false" />
|
||||
<option name="STRIKETHROUGH" value="true" />
|
||||
<option name="SUBSCRIPT" value="false" />
|
||||
<option name="SUPERSCRIPT" value="false" />
|
||||
<option name="SUPPRESS_HTML_BLOCKS" value="false" />
|
||||
<option name="SUPPRESS_INLINE_HTML" value="false" />
|
||||
<option name="TABLES" value="true" />
|
||||
<option name="TASKLISTITEMS" value="true" />
|
||||
<option name="TOC" value="false" />
|
||||
<option name="WIKILINKS" value="true" />
|
||||
</PegdownExtensions>
|
||||
<ParserOptions>
|
||||
<option name="ADMONITION_EXT" value="false" />
|
||||
<option name="ATTRIBUTES_EXT" value="false" />
|
||||
<option name="COMMONMARK_LISTS" value="true" />
|
||||
<option name="DUMMY" value="false" />
|
||||
<option name="EMOJI_SHORTCUTS" value="true" />
|
||||
<option name="ENUMERATED_REFERENCES_EXT" value="false" />
|
||||
<option name="FLEXMARK_FRONT_MATTER" value="false" />
|
||||
<option name="GFM_LOOSE_BLANK_LINE_AFTER_ITEM_PARA" value="false" />
|
||||
<option name="GFM_TABLE_RENDERING" value="true" />
|
||||
<option name="GITBOOK_URL_ENCODING" value="false" />
|
||||
<option name="GITHUB_LISTS" value="false" />
|
||||
<option name="GITHUB_WIKI_LINKS" value="true" />
|
||||
<option name="GITLAB_EXT" value="false" />
|
||||
<option name="GITLAB_MATH_EXT" value="false" />
|
||||
<option name="GITLAB_MERMAID_EXT" value="false" />
|
||||
<option name="HEADER_ID_NON_ASCII_TO_LOWERCASE" value="false" />
|
||||
<option name="HEADER_ID_NO_DUPED_DASHES" value="false" />
|
||||
<option name="JEKYLL_FRONT_MATTER" value="false" />
|
||||
<option name="MACROS_EXT" value="false" />
|
||||
<option name="NO_TEXT_ATTRIBUTES" value="false" />
|
||||
<option name="PARSE_HTML_ANCHOR_ID" value="false" />
|
||||
<option name="PLANTUML_FENCED_CODE" value="false" />
|
||||
<option name="PUML_FENCED_CODE" value="false" />
|
||||
<option name="SIM_TOC_BLANK_LINE_SPACER" value="true" />
|
||||
</ParserOptions>
|
||||
</ParserSettings>
|
||||
<HtmlSettings headerTopEnabled="false" headerBottomEnabled="false" bodyTopEnabled="false" bodyBottomEnabled="false" embedUrlContent="false" addPageHeader="true" embedImages="false" embedHttpImages="false" imageUriSerials="false" addDocTypeHtml="true" noParaTags="false" plantUmlConversion="0" mathConversion="-1">
|
||||
<GeneratorProvider>
|
||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.generator" providerName="Default Swing HTML Generator" />
|
||||
</GeneratorProvider>
|
||||
<headerTop />
|
||||
<headerBottom />
|
||||
<bodyTop />
|
||||
<bodyBottom />
|
||||
</HtmlSettings>
|
||||
<CssSettings previewScheme="UI_SCHEME" cssUri="" isCssUriEnabled="false" isCssUriSerial="true" isCssTextEnabled="false" isDynamicPageWidth="true">
|
||||
<StylesheetProvider>
|
||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.css" providerName="Default Swing Stylesheet" />
|
||||
</StylesheetProvider>
|
||||
<ScriptProviders />
|
||||
<cssText />
|
||||
<cssUriHistory />
|
||||
</CssSettings>
|
||||
<AnnotatorSettings targetHasSpaces="true" linkCaseMismatch="true" wikiCaseMismatch="true" wikiLinkHasDashes="true" notUnderWikiHome="true" targetNotWikiPageExt="true" notUnderSourceWikiHome="true" targetNameHasAnchor="true" targetPathHasAnchor="true" wikiLinkHasSlash="true" wikiLinkHasSubdir="true" wikiLinkHasOnlyAnchor="true" linkTargetsWikiHasExt="true" linkTargetsWikiHasBadExt="true" notUnderSameRepo="true" targetNotUnderVcs="false" linkNeedsExt="true" linkHasBadExt="true" linkTargetNeedsExt="true" linkTargetHasBadExt="true" wikiLinkNotInWiki="true" imageTargetNotInRaw="true" repoRelativeAcrossVcsRoots="true" multipleWikiTargetsMatch="true" unresolvedLinkReference="true" linkIsIgnored="true" anchorIsIgnored="true" anchorIsUnresolved="true" anchorLineReferenceIsUnresolved="true" anchorLineReferenceFormat="true" anchorHasDuplicates="true" abbreviationDuplicates="true" abbreviationNotUsed="true" attributeIdDuplicateDefinition="true" attributeIdNotUsed="true" footnoteDuplicateDefinition="true" footnoteUnresolved="true" footnoteDuplicates="true" footnoteNotUsed="true" macroDuplicateDefinition="true" macroUnresolved="true" macroDuplicates="true" macroNotUsed="true" referenceDuplicateDefinition="true" referenceUnresolved="true" referenceDuplicates="true" referenceNotUsed="true" referenceUnresolvedNumericId="true" enumRefDuplicateDefinition="true" enumRefUnresolved="true" enumRefDuplicates="true" enumRefNotUsed="true" enumRefLinkUnresolved="true" enumRefLinkDuplicates="true" simTocUpdateNeeded="true" simTocTitleSpaceNeeded="true" />
|
||||
<HtmlExportSettings updateOnSave="false" parentDir="" targetDir="" cssDir="css" scriptDir="js" plainHtml="false" imageDir="" copyLinkedImages="false" imageUniquifyType="0" targetPathType="2" targetExt="" useTargetExt="false" noCssNoScripts="false" useElementStyleAttribute="false" linkToExportedHtml="true" exportOnSettingsChange="true" regenerateOnProjectOpen="false" linkFormatType="HTTP_ABSOLUTE" />
|
||||
<LinkMapSettings>
|
||||
<textMaps />
|
||||
</LinkMapSettings>
|
||||
</component>
|
||||
</project>
|
||||
Generated
-83
@@ -4,87 +4,4 @@
|
||||
<option name="languageLevel" value="ES6" />
|
||||
</component>
|
||||
<component name="MarkdownNavigator.ProfileManager" plain-text-search-scope="Project Files" />
|
||||
<component name="MarkdownProjectSettings" wasCopied="true">
|
||||
<PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.0" maxImageWidth="0" showGitHubPageIfSynced="false" allowBrowsingInPreview="false" synchronizePreviewPosition="true" highlightPreviewType="NONE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true" verticallyAlignSourceAndPreviewSyncPosition="true" showSearchHighlightsInPreview="false" showSelectionInPreview="true" openRemoteLinks="true" replaceUnicodeEmoji="false" lastLayoutSetsDefault="false">
|
||||
<PanelProvider>
|
||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.panel" providerName="Default - Swing" />
|
||||
</PanelProvider>
|
||||
</PreviewSettings>
|
||||
<ParserSettings gitHubSyntaxChange="false" emojiShortcuts="1" emojiImages="0">
|
||||
<PegdownExtensions>
|
||||
<option name="ABBREVIATIONS" value="false" />
|
||||
<option name="ANCHORLINKS" value="true" />
|
||||
<option name="ASIDE" value="false" />
|
||||
<option name="ATXHEADERSPACE" value="true" />
|
||||
<option name="AUTOLINKS" value="true" />
|
||||
<option name="DEFINITIONS" value="false" />
|
||||
<option name="DEFINITION_BREAK_DOUBLE_BLANK_LINE" value="false" />
|
||||
<option name="FENCED_CODE_BLOCKS" value="true" />
|
||||
<option name="FOOTNOTES" value="false" />
|
||||
<option name="HARDWRAPS" value="false" />
|
||||
<option name="HTML_DEEP_PARSER" value="false" />
|
||||
<option name="INSERTED" value="false" />
|
||||
<option name="QUOTES" value="false" />
|
||||
<option name="RELAXEDHRULES" value="true" />
|
||||
<option name="SMARTS" value="false" />
|
||||
<option name="STRIKETHROUGH" value="true" />
|
||||
<option name="SUBSCRIPT" value="false" />
|
||||
<option name="SUPERSCRIPT" value="false" />
|
||||
<option name="SUPPRESS_HTML_BLOCKS" value="false" />
|
||||
<option name="SUPPRESS_INLINE_HTML" value="false" />
|
||||
<option name="TABLES" value="true" />
|
||||
<option name="TASKLISTITEMS" value="true" />
|
||||
<option name="TOC" value="false" />
|
||||
<option name="WIKILINKS" value="true" />
|
||||
</PegdownExtensions>
|
||||
<ParserOptions>
|
||||
<option name="ADMONITION_EXT" value="false" />
|
||||
<option name="ATTRIBUTES_EXT" value="false" />
|
||||
<option name="COMMONMARK_LISTS" value="true" />
|
||||
<option name="DUMMY" value="false" />
|
||||
<option name="EMOJI_SHORTCUTS" value="true" />
|
||||
<option name="ENUMERATED_REFERENCES_EXT" value="false" />
|
||||
<option name="FLEXMARK_FRONT_MATTER" value="false" />
|
||||
<option name="GFM_LOOSE_BLANK_LINE_AFTER_ITEM_PARA" value="false" />
|
||||
<option name="GFM_TABLE_RENDERING" value="true" />
|
||||
<option name="GITBOOK_URL_ENCODING" value="false" />
|
||||
<option name="GITHUB_LISTS" value="false" />
|
||||
<option name="GITHUB_WIKI_LINKS" value="true" />
|
||||
<option name="GITLAB_EXT" value="false" />
|
||||
<option name="GITLAB_MATH_EXT" value="false" />
|
||||
<option name="GITLAB_MERMAID_EXT" value="false" />
|
||||
<option name="HEADER_ID_NON_ASCII_TO_LOWERCASE" value="false" />
|
||||
<option name="HEADER_ID_NO_DUPED_DASHES" value="false" />
|
||||
<option name="JEKYLL_FRONT_MATTER" value="false" />
|
||||
<option name="MACROS_EXT" value="false" />
|
||||
<option name="NO_TEXT_ATTRIBUTES" value="false" />
|
||||
<option name="PARSE_HTML_ANCHOR_ID" value="false" />
|
||||
<option name="PLANTUML_FENCED_CODE" value="false" />
|
||||
<option name="PUML_FENCED_CODE" value="false" />
|
||||
<option name="SIM_TOC_BLANK_LINE_SPACER" value="true" />
|
||||
</ParserOptions>
|
||||
</ParserSettings>
|
||||
<HtmlSettings headerTopEnabled="false" headerBottomEnabled="false" bodyTopEnabled="false" bodyBottomEnabled="false" embedUrlContent="false" addPageHeader="true" embedImages="false" embedHttpImages="false" imageUriSerials="false" addDocTypeHtml="true" noParaTags="false" plantUmlConversion="0" mathConversion="-1">
|
||||
<GeneratorProvider>
|
||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.generator" providerName="Default Swing HTML Generator" />
|
||||
</GeneratorProvider>
|
||||
<headerTop />
|
||||
<headerBottom />
|
||||
<bodyTop />
|
||||
<bodyBottom />
|
||||
</HtmlSettings>
|
||||
<CssSettings previewScheme="UI_SCHEME" cssUri="" isCssUriEnabled="false" isCssUriSerial="true" isCssTextEnabled="false" isDynamicPageWidth="true">
|
||||
<StylesheetProvider>
|
||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.css" providerName="Default Swing Stylesheet" />
|
||||
</StylesheetProvider>
|
||||
<ScriptProviders />
|
||||
<cssText />
|
||||
<cssUriHistory />
|
||||
</CssSettings>
|
||||
<AnnotatorSettings targetHasSpaces="true" linkCaseMismatch="true" wikiCaseMismatch="true" wikiLinkHasDashes="true" notUnderWikiHome="true" targetNotWikiPageExt="true" notUnderSourceWikiHome="true" targetNameHasAnchor="true" targetPathHasAnchor="true" wikiLinkHasSlash="true" wikiLinkHasSubdir="true" wikiLinkHasOnlyAnchor="true" linkTargetsWikiHasExt="true" linkTargetsWikiHasBadExt="true" notUnderSameRepo="true" targetNotUnderVcs="false" linkNeedsExt="true" linkHasBadExt="true" linkTargetNeedsExt="true" linkTargetHasBadExt="true" wikiLinkNotInWiki="true" imageTargetNotInRaw="true" repoRelativeAcrossVcsRoots="true" multipleWikiTargetsMatch="true" unresolvedLinkReference="true" linkIsIgnored="true" anchorIsIgnored="true" anchorIsUnresolved="true" anchorLineReferenceIsUnresolved="true" anchorLineReferenceFormat="true" anchorHasDuplicates="true" abbreviationDuplicates="true" abbreviationNotUsed="true" attributeIdDuplicateDefinition="true" attributeIdNotUsed="true" footnoteDuplicateDefinition="true" footnoteUnresolved="true" footnoteDuplicates="true" footnoteNotUsed="true" macroDuplicateDefinition="true" macroUnresolved="true" macroDuplicates="true" macroNotUsed="true" referenceDuplicateDefinition="true" referenceUnresolved="true" referenceDuplicates="true" referenceNotUsed="true" referenceUnresolvedNumericId="true" enumRefDuplicateDefinition="true" enumRefUnresolved="true" enumRefDuplicates="true" enumRefNotUsed="true" enumRefLinkUnresolved="true" enumRefLinkDuplicates="true" simTocUpdateNeeded="true" simTocTitleSpaceNeeded="true" />
|
||||
<HtmlExportSettings updateOnSave="false" parentDir="" targetDir="" cssDir="css" scriptDir="js" plainHtml="false" imageDir="" copyLinkedImages="false" imageUniquifyType="0" targetPathType="2" targetExt="" useTargetExt="false" noCssNoScripts="false" useElementStyleAttribute="false" linkToExportedHtml="true" exportOnSettingsChange="true" regenerateOnProjectOpen="false" linkFormatType="HTTP_ABSOLUTE" />
|
||||
<LinkMapSettings>
|
||||
<textMaps />
|
||||
</LinkMapSettings>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/taro-cropper.iml" filepath="$PROJECT_DIR$/.idea/taro-cropper.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+12
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
Generated
+1
@@ -2,5 +2,6 @@
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/src/components/image-cropper" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
+4
-3
@@ -29,6 +29,9 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"we-cropper": "^1.3.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tarojs/components": "1.3.13",
|
||||
"@tarojs/router": "1.3.13",
|
||||
"@tarojs/taro": "1.3.13",
|
||||
@@ -40,9 +43,7 @@
|
||||
"@tarojs/taro-tt": "1.3.13",
|
||||
"@tarojs/taro-weapp": "1.3.13",
|
||||
"nervjs": "^1.4.0",
|
||||
"nerv-devtools": "^1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nerv-devtools": "^1.4.0",
|
||||
"@types/react": "^16.4.6",
|
||||
"@types/webpack-env": "^1.13.6",
|
||||
"@tarojs/plugin-babel": "1.3.13",
|
||||
|
||||
+6
-3
@@ -1,13 +1,16 @@
|
||||
{
|
||||
"miniprogramRoot": "./dist",
|
||||
"miniprogramRoot": "dist/",
|
||||
"projectname": "taro-cropper",
|
||||
"description": "we-cropper在Taro框架下的封装,开箱即用",
|
||||
"appid": "touristappid",
|
||||
"appid": "wx47e69a70a727989c",
|
||||
"setting": {
|
||||
"urlCheck": true,
|
||||
"es6": false,
|
||||
"postcss": false,
|
||||
"minified": false
|
||||
},
|
||||
"compileType": "miniprogram"
|
||||
"compileType": "miniprogram",
|
||||
"simulatorType": "wechat",
|
||||
"simulatorPluginLibVersion": {},
|
||||
"condition": {}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
.taro-cropper-component {
|
||||
position: relative;
|
||||
}
|
||||
@@ -0,0 +1,397 @@
|
||||
import Taro, {CanvasContext, getImageInfo, getSystemInfoSync} from '@tarojs/taro';
|
||||
import {Canvas, View} from '@tarojs/components';
|
||||
|
||||
import './index.scss';
|
||||
import {ITouch, ITouchEvent} from "@tarojs/components/types/common";
|
||||
|
||||
|
||||
interface TaroCropperComponentProps {
|
||||
bgCanvasId: string, // 背景画布id
|
||||
cropperCanvasId: string, // 裁剪框画布id
|
||||
width: number, // 组件宽度
|
||||
height: number, // 组件高度 (要求背景高度大于宽度)
|
||||
cropperWidth: number, // 裁剪框宽度
|
||||
cropperHeight: number, // 裁剪框高度
|
||||
src: string,
|
||||
}
|
||||
|
||||
interface TaroCropperComponentState {
|
||||
scale: number,
|
||||
}
|
||||
|
||||
class TaroCropperComponent extends Taro.PureComponent<TaroCropperComponentProps, TaroCropperComponentState> {
|
||||
|
||||
static defaultProps = {
|
||||
width: 750,
|
||||
height: 1200,
|
||||
cropperWidth: 300,
|
||||
cropperHeight: 300,
|
||||
bgCanvasId: 'TaroBgCanvasId',
|
||||
cropperCanvasId: 'TaroCropperCanvasId',
|
||||
src: '',
|
||||
};
|
||||
|
||||
systemInfo: getSystemInfoSync.Return;
|
||||
bgCanvasContext: CanvasContext;
|
||||
cropperCanvasContext: CanvasContext;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.update = this.update.bind(this);
|
||||
this.handleOnTouchMove = this.handleOnTouchMove.bind(this);
|
||||
this.handleOnTouchStart = this.handleOnTouchStart.bind(this);
|
||||
this.handleOnTouchEnd = this.handleOnTouchEnd.bind(this);
|
||||
this._drawCropperCorner = this._drawCropperCorner.bind(this);
|
||||
this._drawCropperContent = this._drawCropperContent.bind(this);
|
||||
this.systemInfo = Taro.getSystemInfoSync();
|
||||
this.state = {
|
||||
scale: 1,
|
||||
}
|
||||
}
|
||||
|
||||
imageLeft: number = 0;
|
||||
imageTop: number = 0;
|
||||
imageLeftOrigin: number = 0;
|
||||
imageTopOrigin: number = 0;
|
||||
width: number = 0;
|
||||
height: number = 0;
|
||||
cropperWidth: number = 0;
|
||||
cropperHeight: number = 0;
|
||||
imageInfo: getImageInfo.Promised;
|
||||
realImageWidth: number = 0;
|
||||
realImageHeight: number = 0;
|
||||
scaleImageWidth: number = 0;
|
||||
scaleImageHeight: number = 0;
|
||||
|
||||
/**
|
||||
* 根据props更新长等信息
|
||||
*/
|
||||
updateInfo(props: TaroCropperComponentProps) {
|
||||
const {
|
||||
width,
|
||||
height,
|
||||
cropperWidth,
|
||||
cropperHeight,
|
||||
src
|
||||
} = props;
|
||||
this.width = this._getRealPx(width);
|
||||
this.height = this._getRealPx(height);
|
||||
this.cropperWidth = this._getRealPx(cropperWidth);
|
||||
this.cropperHeight = this._getRealPx(cropperHeight);
|
||||
if (!src)
|
||||
return Promise.reject();
|
||||
return Taro.getImageInfo({
|
||||
src: src
|
||||
})
|
||||
.then((res: getImageInfo.Promised) => {
|
||||
this.imageInfo = res;
|
||||
const imageWidth = res.width;
|
||||
const imageHeight = res.height;
|
||||
|
||||
if (imageWidth / imageHeight < this.cropperWidth / this.cropperHeight) { // 宽度充满
|
||||
this.scaleImageWidth = this.realImageWidth = this.cropperWidth;
|
||||
this.scaleImageHeight = this.realImageHeight = this.realImageWidth * imageHeight / imageWidth;
|
||||
this.imageLeftOrigin = this.imageLeft = (this.width - this.cropperWidth) / 2;
|
||||
this.imageTopOrigin = this.imageTop = (this.height - this.realImageHeight) / 2;
|
||||
} else {
|
||||
this.scaleImageHeight = this.realImageHeight = this.cropperHeight;
|
||||
this.scaleImageWidth = this.realImageWidth = this.realImageHeight * imageWidth / imageHeight;
|
||||
this.imageLeftOrigin = this.imageLeft = (this.width - this.realImageWidth) / 2;
|
||||
this.imageTopOrigin = this.imageTop = (this.height - this.cropperHeight) / 2;
|
||||
}
|
||||
|
||||
return Promise.resolve()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
componentDidMount(): void {
|
||||
const {
|
||||
cropperCanvasId,
|
||||
bgCanvasId
|
||||
} = this.props;
|
||||
this.bgCanvasContext = Taro.createCanvasContext(bgCanvasId, this);
|
||||
this.cropperCanvasContext = Taro.createCanvasContext(cropperCanvasId, this);
|
||||
this.updateInfo(this.props)
|
||||
.then(() => {
|
||||
this.update();
|
||||
})
|
||||
.catch(() => {
|
||||
this.update();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 单位转换
|
||||
* @param value
|
||||
* @private
|
||||
*/
|
||||
_getRealPx(value: number) {
|
||||
return value / 750 * this.systemInfo.screenWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制裁剪框的四个角
|
||||
* @private
|
||||
*/
|
||||
_drawCropperCorner() {
|
||||
const cropperStartX = (this.width - this.cropperWidth) / 2;
|
||||
const cropperStartY = (this.height - this.cropperHeight) / 2;
|
||||
|
||||
const lineWidth = 2;
|
||||
const lineLength = 10;
|
||||
this.cropperCanvasContext.beginPath();
|
||||
this.cropperCanvasContext.setStrokeStyle('#0f0');
|
||||
this.cropperCanvasContext.setLineWidth(lineWidth);
|
||||
// 左上角
|
||||
this.cropperCanvasContext.moveTo(cropperStartX, cropperStartY);
|
||||
this.cropperCanvasContext.lineTo(cropperStartX + lineLength, cropperStartY);
|
||||
this.cropperCanvasContext.moveTo(cropperStartX, cropperStartY - lineWidth / 2);
|
||||
this.cropperCanvasContext.lineTo(cropperStartX, cropperStartY + lineLength);
|
||||
// 右上角
|
||||
this.cropperCanvasContext.moveTo(cropperStartX + this.cropperWidth, cropperStartY);
|
||||
this.cropperCanvasContext.lineTo(cropperStartX + this.cropperWidth - lineLength, cropperStartY);
|
||||
this.cropperCanvasContext.moveTo(cropperStartX + this.cropperWidth, cropperStartY - lineWidth / 2);
|
||||
this.cropperCanvasContext.lineTo(cropperStartX + this.cropperWidth, cropperStartY + lineLength);
|
||||
// 左下角
|
||||
this.cropperCanvasContext.moveTo(cropperStartX, cropperStartY + this.cropperHeight);
|
||||
this.cropperCanvasContext.lineTo(cropperStartX + lineLength, cropperStartY + this.cropperHeight);
|
||||
this.cropperCanvasContext.moveTo(cropperStartX, cropperStartY + this.cropperHeight + lineWidth / 2);
|
||||
this.cropperCanvasContext.lineTo(cropperStartX, cropperStartY + this.cropperHeight - lineLength);
|
||||
// 右下角
|
||||
this.cropperCanvasContext.moveTo(cropperStartX + this.cropperWidth, cropperStartY + this.cropperHeight);
|
||||
this.cropperCanvasContext.lineTo(cropperStartX + this.cropperWidth - lineLength, cropperStartY + this.cropperHeight);
|
||||
this.cropperCanvasContext.moveTo(cropperStartX + this.cropperWidth, cropperStartY + this.cropperHeight + lineWidth / 2);
|
||||
this.cropperCanvasContext.lineTo(cropperStartX + this.cropperWidth, cropperStartY + this.cropperHeight - lineLength);
|
||||
this.cropperCanvasContext.closePath();
|
||||
this.cropperCanvasContext.stroke();
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制裁剪框区域的图片
|
||||
* @param props
|
||||
* @param src 待绘制的图片路径
|
||||
* @param deviationX 图片绘制x向偏移
|
||||
* @param deviationY 图片绘制y向偏移
|
||||
* @param imageWidth 图片的原始宽度
|
||||
* @param imageHeight 图片的原始高度
|
||||
* @param drawWidth 图片的绘制宽度
|
||||
* @param drawHeight 图片的绘制高度
|
||||
* @param reverse
|
||||
* @private
|
||||
*/
|
||||
_drawCropperContent(
|
||||
// props: TaroCropperComponentProps,
|
||||
src: string,
|
||||
deviationX: number,
|
||||
deviationY: number,
|
||||
imageWidth: number,
|
||||
imageHeight: number,
|
||||
drawWidth: number,
|
||||
drawHeight: number) {
|
||||
const cropperStartX = (this.width - this.cropperWidth) / 2;
|
||||
const cropperStartY = (this.height - this.cropperHeight) / 2;
|
||||
|
||||
const cropperImageX = (cropperStartX - deviationX) / drawWidth * imageWidth;
|
||||
const cropperImageY = (cropperStartY - deviationY) / drawHeight * imageHeight;
|
||||
const cropperImageWidth = this.cropperWidth / drawWidth * imageWidth;
|
||||
const cropperImageHeight = this.cropperHeight / drawHeight * imageHeight;
|
||||
// 绘制裁剪框内裁剪的图片
|
||||
this.cropperCanvasContext.drawImage(src, cropperImageX, cropperImageY, cropperImageWidth, cropperImageHeight,
|
||||
cropperStartX, cropperStartY, this.cropperWidth, this.cropperHeight);
|
||||
this._drawCropperCorner();
|
||||
}
|
||||
|
||||
update() {
|
||||
if (!this.imageInfo) { // 图片资源无效则不执行更新操作
|
||||
this._drawCropperCorner();
|
||||
this.cropperCanvasContext.draw();
|
||||
return;
|
||||
}
|
||||
|
||||
this.cropperCanvasContext.drawImage(this.imageInfo.path, 0, 0, this.imageInfo.width, this.imageInfo.height,
|
||||
this.imageLeft, this.imageTop, this.scaleImageWidth, this.scaleImageHeight);
|
||||
// 绘制半透明层
|
||||
this.cropperCanvasContext.beginPath();
|
||||
this.cropperCanvasContext.setFillStyle('rgba(0, 0, 0, 0.3)');
|
||||
this.cropperCanvasContext.fillRect(0, 0, this.width, this.height);
|
||||
this.cropperCanvasContext.fill();
|
||||
|
||||
// 绘制裁剪框内部的区域
|
||||
this._drawCropperContent(this.imageInfo.path, this.imageLeft, this.imageTop,
|
||||
this.imageInfo.width, this.imageInfo.height, this.scaleImageWidth, this.scaleImageHeight);
|
||||
this.cropperCanvasContext.draw(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片资源有更新则重新绘制
|
||||
* @param nextProps
|
||||
* @param nextContext
|
||||
*/
|
||||
componentWillReceiveProps(nextProps: Readonly<TaroCropperComponentProps>, nextContext: any): void {
|
||||
if (JSON.stringify(nextProps) != JSON.stringify(this.props)) {
|
||||
this.updateInfo(nextProps)
|
||||
.then(() => {
|
||||
this.update();
|
||||
});
|
||||
}
|
||||
return super.componentWillReceiveProps && super.componentWillReceiveProps(nextProps, nextContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片移动边界检测
|
||||
* @param imageLeft
|
||||
* @param imageRight
|
||||
* @private
|
||||
*/
|
||||
_outsideBound(imageLeft: number, imageTop: number) {
|
||||
this.imageLeft =
|
||||
imageLeft > (this.width - this.cropperWidth) / 2
|
||||
?
|
||||
(this.width - this.cropperWidth) / 2
|
||||
:
|
||||
(
|
||||
(imageLeft + this.scaleImageWidth) >= (this.width + this.cropperWidth) / 2
|
||||
?
|
||||
imageLeft
|
||||
:
|
||||
(this.width + this.cropperWidth) / 2 - this.scaleImageWidth
|
||||
);
|
||||
this.imageTop =
|
||||
imageTop > (this.height - this.cropperHeight) / 2
|
||||
?
|
||||
(this.height - this.cropperHeight) / 2
|
||||
:
|
||||
(
|
||||
(imageTop + this.scaleImageHeight) >= (this.height + this.cropperHeight) / 2
|
||||
?
|
||||
imageTop
|
||||
:
|
||||
(this.height + this.cropperHeight) / 2 - this.scaleImageHeight
|
||||
)
|
||||
}
|
||||
|
||||
touch0X = 0;
|
||||
touch0Y = 0;
|
||||
oldDistance = 0;
|
||||
oldScale = 1;
|
||||
newScale = 1;
|
||||
lastScaleImageWidth = 0;
|
||||
lastScaleImageHeight = 0;
|
||||
|
||||
_oneTouchStart(touch: ITouch) {
|
||||
this.touch0X = touch.x;
|
||||
this.touch0Y = touch.y;
|
||||
}
|
||||
|
||||
_twoTouchStart(touch0: ITouch, touch1: ITouch) {
|
||||
const xMove = touch1.x - touch0.x;
|
||||
const yMove = touch1.y - touch0.y;
|
||||
this.lastScaleImageWidth = this.scaleImageWidth;
|
||||
this.lastScaleImageHeight = this.scaleImageHeight;
|
||||
|
||||
// 计算得到初始时两指的距离
|
||||
this.oldDistance = Math.sqrt(xMove * xMove + yMove * yMove);
|
||||
}
|
||||
|
||||
_oneTouchMove(touch: ITouch) {
|
||||
const xMove = touch.x - this.touch0X;
|
||||
const yMove = touch.y - this.touch0Y;
|
||||
this._outsideBound(this.imageLeftOrigin + xMove, this.imageTopOrigin + yMove);
|
||||
this.update();
|
||||
}
|
||||
|
||||
_getNewScale(oldScale: number, oldDistance: number, touch0: ITouch, touch1: ITouch) {
|
||||
const xMove = touch1.x - touch0.x;
|
||||
const yMove = touch1.y - touch0.y;
|
||||
const newDistance = Math.sqrt(xMove * xMove + yMove * yMove);
|
||||
return oldScale + 0.02 * (newDistance - oldDistance);
|
||||
}
|
||||
|
||||
_twoTouchMove(touch0: ITouch, touch1: ITouch) {
|
||||
const oldScale = this.oldScale;
|
||||
const oldDistance = this.oldDistance;
|
||||
this.newScale = this._getNewScale(oldScale, oldDistance, touch0, touch1);
|
||||
|
||||
// 限制缩放
|
||||
this.newScale <= 1 && (this.newScale = 1);
|
||||
this.newScale > 3 && (this.newScale = 3);
|
||||
|
||||
this.scaleImageWidth = this.realImageWidth * this.newScale;
|
||||
this.scaleImageHeight = this.realImageHeight * this.newScale;
|
||||
const imageLeft = this.imageLeftOrigin - (this.scaleImageWidth - this.lastScaleImageWidth) / 2;
|
||||
const imageTop = this.imageTopOrigin - (this.scaleImageHeight - this.lastScaleImageHeight) / 2;
|
||||
|
||||
this._outsideBound(imageLeft, imageTop);
|
||||
|
||||
this.update();
|
||||
}
|
||||
|
||||
|
||||
handleOnTouchEnd() {
|
||||
this.oldScale = this.newScale;
|
||||
this.imageLeftOrigin = this.imageLeft;
|
||||
this.imageTopOrigin = this.imageTop
|
||||
}
|
||||
|
||||
|
||||
handleOnTouchStart(e: ITouchEvent) {
|
||||
const {
|
||||
src
|
||||
} = this.props;
|
||||
if (!src)
|
||||
return;
|
||||
const touch0 = e.touches[0];
|
||||
const touch1 = e.touches[1];
|
||||
|
||||
// 计算第一个触摸点的位置,并参照改点进行缩放
|
||||
this._oneTouchStart(touch0);
|
||||
|
||||
// 两指手势触发
|
||||
if (e.touches.length >= 2) {
|
||||
this._twoTouchStart(touch0, touch1);
|
||||
}
|
||||
}
|
||||
|
||||
handleOnTouchMove(e: ITouchEvent) {
|
||||
const {
|
||||
src
|
||||
} = this.props;
|
||||
if (!src)
|
||||
return;
|
||||
|
||||
// 单指手势触发
|
||||
if (e.touches.length === 1) {
|
||||
this._oneTouchMove(e.touches[0]);
|
||||
} else if (e.touches.length >= 2) {// 双指手势触发
|
||||
this._twoTouchMove(e.touches[0], e.touches[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
render(): any {
|
||||
const {
|
||||
width,
|
||||
height,
|
||||
cropperCanvasId,
|
||||
} = this.props;
|
||||
return (
|
||||
<View className='taro-cropper-component'>
|
||||
<Canvas
|
||||
onTouchStart={this.handleOnTouchStart}
|
||||
onTouchMove={this.handleOnTouchMove}
|
||||
onTouchEnd={this.handleOnTouchEnd}
|
||||
canvasId={cropperCanvasId}
|
||||
style={{
|
||||
width: `${width / 750 * this.systemInfo.screenWidth}px`,
|
||||
height: `${height / 750 * this.systemInfo.screenWidth}px`,
|
||||
background: 'rgba(0, 0, 0, 0.8)',
|
||||
}}
|
||||
disableScroll
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TaroCropperComponent;
|
||||
@@ -1,8 +1,17 @@
|
||||
import Taro, {Component, Config} from '@tarojs/taro'
|
||||
import { View, Text } from '@tarojs/components'
|
||||
import {View, Button} from '@tarojs/components'
|
||||
import './index.scss'
|
||||
import TaroCropper from '../../components/taro-cropper';
|
||||
|
||||
export default class Index extends Component {
|
||||
interface IndexProps {
|
||||
|
||||
}
|
||||
|
||||
interface IndexState {
|
||||
src: string,
|
||||
}
|
||||
|
||||
export default class Index extends Component<IndexProps, IndexState> {
|
||||
|
||||
/**
|
||||
* 指定config的类型声明为: Taro.Config
|
||||
@@ -12,23 +21,46 @@ export default class Index extends Component {
|
||||
* 提示和声明 navigationBarTextStyle: 'black' | 'white' 类型冲突, 需要显示声明类型
|
||||
*/
|
||||
config: Config = {
|
||||
navigationBarTitleText: '首页'
|
||||
navigationBarTitleText: '首页',
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
src: ''
|
||||
}
|
||||
}
|
||||
|
||||
componentWillMount () { }
|
||||
componentWillMount() {
|
||||
}
|
||||
|
||||
componentDidMount () { }
|
||||
componentDidMount() {
|
||||
}
|
||||
|
||||
componentWillUnmount () { }
|
||||
componentWillUnmount() {
|
||||
}
|
||||
|
||||
componentDidShow () { }
|
||||
componentDidShow() {
|
||||
}
|
||||
|
||||
componentDidHide () { }
|
||||
componentDidHide() {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
src
|
||||
} = this.state;
|
||||
return (
|
||||
<View className='index'>
|
||||
<Text>Hello world!</Text>
|
||||
<TaroCropper height={1000} src={src} cropperWidth={400} cropperHeight={400}/>
|
||||
<Button onClick={() => {
|
||||
Taro.chooseImage()
|
||||
.then(res => {
|
||||
this.setState({
|
||||
src: res.tempFilePaths[0]
|
||||
});
|
||||
})
|
||||
}}>选择图片</Button>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user