| | |
| | | return request.get(`/business/member/batchBlock?ids=${ids}`) |
| | | } |
| | | |
| | | // éæ°ææ |
| | | export function roleAuth (id) { |
| | | return request.get(`/business/member/roleAuth/${id}`) |
| | | } |
| | | |
| | | // å é¤ |
| | | export function deleteById (id) { |
| | | return request.get(`/business/member/delete/${id}`) |
| | |
| | | <GlobalWindow |
| | | :title="title" |
| | | :visible.sync="visible" |
| | | width="50%" |
| | | width="900px" |
| | | :confirm-working="isWorking" |
| | | @confirm="confirm" |
| | | > |
| | | <el-form :model="form" ref="form" :rules="rules"> |
| | | <el-form-item label="é¨ç¦ç»åç§°" prop="name"> |
| | | <el-form-item label="é¨ç¦ç¹åç»åç§°" prop="name"> |
| | | <el-input v-model="form.name" placeholder="请è¾å
¥åç§°" v-trim/> |
| | | </el-form-item> |
| | | <el-form-item label="é»è®¤é¨ç¦ç»" prop="isDefault"> |
| | | <el-form-item label="é»è®¤é¨ç¦ç¹åç»" prop="isDefault"> |
| | | <el-switch |
| | | v-model="form.isDefault" |
| | | active-color="#13ce66" |
| | |
| | | <el-transfer |
| | | v-if="form.radio === 1" |
| | | style="margin-top: 15px;" |
| | | :titles="['æªéé¨ç¦ç»', 'å·²éé¨ç¦ç»']" |
| | | :titles="['æªéé¨ç¦ç¹', 'å·²éé¨ç¦ç¹']" |
| | | filterable |
| | | filter-placeholder="请è¾å
¥é¨ç¦ç»åç§°" |
| | | :filter-method="filterMethod" |
| | | filter-placeholder="请è¾å
¥é¨ç¦ç¹æåºååç§°" |
| | | v-model="form.doorIds" |
| | | :data="device"> |
| | | </el-transfer> |
| | |
| | | } |
| | | } |
| | | callback() |
| | | } |
| | | }; |
| | | return { |
| | | // è¡¨åæ°æ® |
| | | form: { |
| | |
| | | radio: 0 |
| | | }, |
| | | device: [], |
| | | filterMethod(query, item) { |
| | | if (!query) return item; |
| | | return item.label.indexOf(query) > -1 || item.area.indexOf(query) > -1; |
| | | }, |
| | | // éªè¯è§å |
| | | rules: { |
| | | name: [ |
| | |
| | | .then(res => { |
| | | this.device = res.map(item => { |
| | | return { |
| | | label: item.name, |
| | | label: item.doorName, |
| | | area: item.regionPathName, |
| | | key: item.id |
| | | } |
| | | }) |
| | |
| | | |
| | | <style> |
| | | .el-transfer-panel { |
| | | width: 350px; |
| | | width: 350px !important; |
| | | } |
| | | </style> |
| | |
| | | <div class="list_item_label">æè®¿ä¿¡æ¯</div> |
| | | <div class="list_item_val" v-if="info" style="display: inline-block"> |
| | | <div class="list_item_val_item">æè®¿å¯¹æ¹ï¼{{info.receptMemberName}} - {{info.receptMemberDepartment}}</div> |
| | | <div class="list_item_val_item">æè®¿æ¶é´ï¼{{info.starttime}} è³ {{info.endtime}}</div> |
| | | <div class="list_item_val_item">é¢çº¦æ¶é´ï¼{{info.starttime}} è³ {{info.endtime}}</div> |
| | | <div class="list_item_val_item" v-if="info.inDate && info.outDate">ç¾å°æ¶é´ï¼{{info.inDate}} è³ {{info.outDate}}</div> |
| | | <div class="list_item_val_item" v-else>ç¾å°æ¶é´ï¼-</div> |
| | | <div class="list_item_val_item">æè®¿äºç±ï¼{{info.reason}}</div> |
| | | <div class="list_item_val_item">ç³è¯·äººåï¼{{info.name}} {{info.companyName}}</div> |
| | | <div class="list_item_val_item">ç³è¯·é¨ç¦ï¼{{info.deviceRoleList ? info.deviceRoleList.map(item => item.name).join(' | ') : ''}}</div> |
| | | <div class="list_item_val_item">ç³è¯·é¨ç¦ï¼{{info.deviceRoleList ? info.deviceRoleList.map(item => item.name).join(' | ') : '-'}}</div> |
| | | <div class="list_item_val_item">å建æ¶é´ï¼{{info.createDate}}</div> |
| | | </div> |
| | | <div class="list_item_val" v-if="info" style="display: inline-block;float: right"> |
| | |
| | | <!-- <li><el-button type="primary" v-permissions="['business:member:create']" @click="thaws">离åº</el-button></li>--> |
| | | <!-- </ul>--> |
| | | <el-table |
| | | v-loading="isWorking.search" |
| | | :data="tableData.list" |
| | | stripe |
| | | @selection-change="handleSelectionChange" |
| | | v-loading="isWorking.search" |
| | | :data="tableData.list" |
| | | stripe |
| | | @selection-change="handleSelectionChange" |
| | | > |
| | | <!-- <el-table-column type="selection" width="55"></el-table-column>--> |
| | | <el-table-column prop="name" label="å§å" min-width="100px"></el-table-column> |
| | |
| | | <span v-if="row.type === 2">å
é¨äººå</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="inDate" label="å
¥åºæ¶é´" min-width="100px"></el-table-column> |
| | | <el-table-column prop="outDate" label="ææå°ææ¶é´" min-width="100px"></el-table-column> |
| | | <el-table-column label="è¶
æ¶æ¶é¿" min-width="100px"> |
| | | <template slot-scope="{row}"> |
| | | <span v-if="row.outStatus === 1">{{row.timeOut.toString().replace('-', '')}}åé</span> |
| | | <span v-else>-</span> |
| | | </template> |
| | | </el-table-column> |
| | | <!-- <el-table-column prop="inDate" label="å
¥åºæ¶é´" min-width="100px"></el-table-column>--> |
| | | <!-- <el-table-column prop="outDate" label="ææå°ææ¶é´" min-width="100px"></el-table-column>--> |
| | | <!-- <el-table-column label="è¶
æ¶æ¶é¿" min-width="100px">--> |
| | | <!-- <template slot-scope="{row}">--> |
| | | <!-- <span v-if="row.outStatus === 1">{{row.timeOut.toString().replace('-', '')}}åé</span>--> |
| | | <!-- <span v-else>-</span>--> |
| | | <!-- </template>--> |
| | | <!-- </el-table-column>--> |
| | | <el-table-column label="ç¶æ" min-width="100px"> |
| | | <template slot-scope="{row}"> |
| | | <span v-if="row.outStatus === 0">æªè¶
æ¶</span> |
| | | <span style="color: red;" v-else-if="row.outStatus === 1">å·²è¶
æ¶</span> |
| | | <span v-else-if="row.outStatus === 2">å³å°è¶
æ¶</span> |
| | | <span v-if="row.hkStatus === 0">æªåæ¥</span> |
| | | <span v-else-if="row.hkStatus === 1">已忥</span> |
| | | <span v-else-if="row.hkStatus === 2">åæ¥å¤±è´¥</span> |
| | | <span v-else-if="row.hkStatus === 3">ä¸ç¬¦åä¸åæ¡ä»¶</span> |
| | | <span v-else-if="row.hkStatus === 4">çå¾
å 餿é</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | v-if="containPermissions(['business:member:update', 'business:member:delete'])" |
| | | label="æä½" |
| | | min-width="120" |
| | | fixed="right" |
| | | > |
| | | <template slot-scope="{row}"> |
| | | <el-button type="text" icon="el-icon-edit" v-permissions="['business:member:update']" @click="departure(row.id)">离å</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | <!-- <el-table-column--> |
| | | <!-- v-if="containPermissions(['business:member:update', 'business:member:delete'])"--> |
| | | <!-- label="æä½"--> |
| | | <!-- min-width="120"--> |
| | | <!-- fixed="right"--> |
| | | <!-- >--> |
| | | <!-- <template slot-scope="{row}">--> |
| | | <!-- <el-button type="text" icon="el-icon-edit" v-permissions="['business:member:update']" @click="departure(row.id)">离å</el-button>--> |
| | | <!-- </template>--> |
| | | <!-- </el-table-column>--> |
| | | </el-table> |
| | | <pagination |
| | | @size-change="handleSizeChange" |
| | | @current-change="handlePageChange" |
| | | :pagination="tableData.pagination" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handlePageChange" |
| | | :pagination="tableData.pagination" |
| | | > |
| | | </pagination> |
| | | </template> |
| | |
| | | created () { |
| | | this.config({ |
| | | module: '人åä¿¡æ¯è¡¨', |
| | | api: '/business/strandedPersonnel', |
| | | api: '/business/member', |
| | | 'field.id': 'id', |
| | | 'field.main': 'id' |
| | | }) |
| | |
| | | <TableLayout :permissions="['business:device:query']"> |
| | | <!-- æç´¢è¡¨å --> |
| | | <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline> |
| | | <el-form-item label="é¨ç¦åç§°" prop="name"> |
| | | <el-input v-model="searchForm.name" placeholder="请è¾å
¥é¨ç¦åç§°" @keypress.enter.native="search"></el-input> |
| | | <el-form-item label="é¨ç¦ç¹åç§°" prop="doorName"> |
| | | <el-input v-model="searchForm.doorName" placeholder="请è¾å
¥é¨ç¦ç¹åç§°" @keypress.enter.native="search"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="é¨ç¦ç级" prop="level"> |
| | | <el-select v-model="searchForm.level" placeholder="è¯·éæ©é¨ç¦ç级" @keypress.enter.native="search"> |
| | | <el-option label="ä¸çº§é¨ç¦" value="1"></el-option> |
| | | <el-option label="äºçº§é¨ç¦" value="2"></el-option> |
| | | <el-option label="ä¸çº§é¨ç¦" value="3"></el-option> |
| | | </el-select> |
| | | <el-form-item label="åºååç§°" prop="regionPathName"> |
| | | <el-input v-model="searchForm.regionPathName" placeholder="请è¾å
¥åºååç§°" @keypress.enter.native="search"></el-input> |
| | | </el-form-item> |
| | | <section> |
| | | <el-button type="primary" @click="search">æç´¢</el-button> |
| | |
| | | :data="tableData.list" |
| | | stripe |
| | | > |
| | | <el-table-column prop="name" label="设å¤åç§°" min-width="100px"></el-table-column> |
| | | <el-table-column prop="doorName" label="é¨ç¦ç¹åç§°" min-width="100px"></el-table-column> |
| | | <el-table-column prop="regionPathName" label="åºååç§°" min-width="100px"></el-table-column> |
| | | <el-table-column prop="doorNo" label="é¨ç¦ç¹ç¼å·" min-width="100px"></el-table-column> |
| | | <el-table-column prop="manufature" label="åå" min-width="100px"></el-table-column> |
| | | <el-table-column prop="no" label="设å¤ç¼å·" min-width="100px"></el-table-column> |
| | | <el-table-column prop="name" label="é¨ç¦åç§°" min-width="100px"></el-table-column> |
| | | <el-table-column prop="level" label="é¨ç¦ç级" min-width="100px"></el-table-column> |
| | | <el-table-column prop="status" label="设å¤ç¶æ" min-width="100px"> |
| | | <template slot-scope="{row}"> |
| | | <span v-if="row.status === 0">ç¦ç¨</span> |
| | | <span v-if="row.status === 1">å¯ç¨</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="no" label="设å¤å·" min-width="100px"></el-table-column> |
| | | <!-- <el-table-column--> |
| | | <!-- v-if="containPermissions(['business:device:update'])"--> |
| | | <!-- label="æä½"--> |
| | |
| | | return { |
| | | // æç´¢ |
| | | searchForm: { |
| | | name: '', |
| | | level: '' |
| | | doorName: '', |
| | | regionPathName: '' |
| | | }, |
| | | options: [] |
| | | } |
| | |
| | | <template> |
| | | <TableLayout :permissions="['business:devicerole:query']"> |
| | | <!-- æç´¢è¡¨å --> |
| | | <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline> |
| | | <el-form-item label="é¨ç¦ç»åç§°" prop="name"> |
| | | <el-input v-model="searchForm.name" placeholder="请è¾å
¥é¨ç¦ç»åç§°" @keypress.enter.native="search"></el-input> |
| | | <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="110px" inline> |
| | | <el-form-item label="é¨ç¦ç¹åç»åç§°" prop="name"> |
| | | <el-input v-model="searchForm.name" placeholder="请è¾å
¥é¨ç¦ç¹åç»åç§°" @keypress.enter.native="search"></el-input> |
| | | </el-form-item> |
| | | <section> |
| | | <el-button type="primary" @click="search">æç´¢</el-button> |
| | |
| | | <!-- è¡¨æ ¼åå页 --> |
| | | <template v-slot:table-wrap> |
| | | <ul class="toolbar" v-permissions="['business:devicerole:create', 'business:devicerole:delete']"> |
| | | <li><el-button type="primary" @click="$refs.operaDeviceRoleWindow.open('æ°å»ºé¨ç¦è§è²')" icon="el-icon-plus" v-permissions="['business:devicerole:create']">æ°å»º</el-button></li> |
| | | <li><el-button type="primary" @click="$refs.operaDeviceRoleWindow.open('æ°å»ºé¨ç¦ç¹åç»')" icon="el-icon-plus" v-permissions="['business:devicerole:create']">æ°å»º</el-button></li> |
| | | <li><el-button @click="deleteByIdInBatch" icon="el-icon-delete" v-permissions="['business:devicerole:delete']">å é¤</el-button></li> |
| | | </ul> |
| | | <el-table |
| | |
| | | @selection-change="handleSelectionChange" |
| | | > |
| | | <el-table-column type="selection" width="55"></el-table-column> |
| | | <el-table-column prop="name" label="é¨ç¦ç»åç§°" min-width="100px"></el-table-column> |
| | | <el-table-column prop="name" label="é¨ç¦ç¹åç»" min-width="100px"></el-table-column> |
| | | <el-table-column prop="memberNum" label="使ç¨äººæ°" min-width="100px"></el-table-column> |
| | | <el-table-column prop="isDefault" label="æ¯å¦é»è®¤" min-width="100px"> |
| | | <template slot-scope="{row}"> |
| | |
| | | }, |
| | | created () { |
| | | this.config({ |
| | | module: 'é¨ç¦è§è²', |
| | | module: 'é¨ç¦ç¹åç»', |
| | | api: '/business/deviceRole', |
| | | 'field.id': 'id', |
| | | 'field.main': 'name' |
| | |
| | | row.radio = 0 |
| | | row.doorIds = [] |
| | | } |
| | | this.$refs.operaDeviceRoleWindow.open('ç¼è¾é¨ç¦è§è²', row) |
| | | this.$refs.operaDeviceRoleWindow.open('ç¼è¾é¨ç¦ç¹åç»', row) |
| | | } |
| | | } |
| | | } |
| | |
| | | <el-table-column prop="memberPhone" label="ææºå·" min-width="120px"></el-table-column> |
| | | <el-table-column prop="memberidCard" label="身份è¯å·ç " min-width="130px"></el-table-column> |
| | | <el-table-column prop="companyName" label="æå±å
¬å¸" min-width="150px"></el-table-column> |
| | | <el-table-column prop="deviceName" label="设å¤åç§°" min-width="150px"></el-table-column> |
| | | <el-table-column label="é¨ç¦æææ" min-width="170px"> |
| | | <template slot-scope="{row}"> |
| | | <span>èµ·ï¼{{row.startTime}}</span><br /> |
| | | <span>æ¢ï¼{{row.endTime}}</span> |
| | | <span v-if="!row.startTime || !row.endTime">é¿æ</span> |
| | | <div v-else> |
| | | <span>èµ·ï¼{{row.startTime}}</span><br /> |
| | | <span>æ¢ï¼{{row.endTime}}</span> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="sendDate" label="å建æ¶é´" min-width="150px"></el-table-column> |
| | |
| | | <el-table-column label="ç±»å" min-width="100px"> |
| | | <template slot-scope="{row}"> |
| | | <span v-if="row.type == 0">è°ç¨</span> |
| | | <span v-if="row.type == 1">æ¨éæ¥å</span> |
| | | <span v-if="row.type == 1">æ¨éæ¥æ¶</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å¹³å°" min-width="100px"> |
| | |
| | | <el-button @click="$refs.cardOpeningRecord.open('å¼å¡è®°å½', row.id)" type="text">{{row.memberCardCount || '0'}}</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | <!-- <el-table-column--> |
| | | <!-- v-if="containPermissions(['business:member:update', 'business:member:delete'])"--> |
| | | <!-- label="æä½"--> |
| | | <!-- min-width="120"--> |
| | | <!-- fixed="right"--> |
| | | <!-- >--> |
| | | <!-- <template slot-scope="{row}">--> |
| | | <!-- <el-button type="text" @click="$refs.operaMemberWindow.open('ç¼è¾äººåä¿¡æ¯è¡¨', row)" icon="el-icon-edit" v-permissions="['business:member:update']">ç¼è¾</el-button>--> |
| | | <!-- <el-button type="text" @click="deleteById(row)" icon="el-icon-delete" v-permissions="['business:member:delete']">å é¤</el-button>--> |
| | | <!-- </template>--> |
| | | <!-- </el-table-column>--> |
| | | <el-table-column |
| | | v-if="containPermissions(['business:member:update', 'business:member:delete'])" |
| | | label="æä½" |
| | | min-width="120" |
| | | fixed="right" |
| | | > |
| | | <template slot-scope="{row}"> |
| | | <el-button type="text" @click="empower(row.id)" v-permissions="['business:empower:create']">éæ°ææ</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <pagination |
| | | @size-change="handleSizeChange" |
| | |
| | | import cardOpeningRecord from '@/components/business/cardOpeningRecord' |
| | | import Tree from '@/components/common/Tree' |
| | | import { fetchList } from '@/api/business/company' |
| | | import { memberSync } from '@/api/business/member' |
| | | import { memberSync, roleAuth } from '@/api/business/member' |
| | | export default { |
| | | name: 'internalMember', |
| | | extends: BaseTable, |
| | |
| | | this.getfindCompanyTreePage() |
| | | }, |
| | | methods: { |
| | | empower(id) { |
| | | var that = this |
| | | this.$confirm('ç¡®å®éæ°ææå?', 'æç¤º', { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | roleAuth(id) |
| | | .then(res => { |
| | | that.search() |
| | | }) |
| | | }).catch(() => { |
| | | |
| | | }); |
| | | }, |
| | | // è·åç»ç»æ |
| | | getfindCompanyTreePage () { |
| | | fetchList(1) |
| | |
| | | <el-table-column prop="companyName" label="å
¬å¸åç§°" min-width="100px"></el-table-column> |
| | | <el-table-column prop="receptMemberName" label="被访人" min-width="100px"></el-table-column> |
| | | <el-table-column prop="reason" label="æè®¿äºç±" min-width="100px"></el-table-column> |
| | | <el-table-column label="æè®¿æ¶é´" min-width="170px"> |
| | | <el-table-column label="é¢çº¦æ¶é´" min-width="170px"> |
| | | <template slot-scope="{row}"> |
| | | <span>èµ·ï¼{{row.starttime}}</span><br/> |
| | | <span>æ¢ï¼{{row.endtime}}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ç¾å°æ¶é´" min-width="170px"> |
| | | <template slot-scope="{row}"> |
| | | <div v-if="row.inDate && row.outDate"> |
| | | <span>èµ·ï¼{{row.inDate}}</span><br/> |
| | | <span>æ¢ï¼{{row.outDate}}</span> |
| | | </div> |
| | | <span v-else>-</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="é访人å" min-width="100px"> |
| | | <template slot-scope="{row}"> |
| | | <span>{{row.memberNum || '-'}}</span> |
| | |
| | | // http://192.168.0.134:10028 任康 |
| | | // http://192.168.0.110:10013 ç£ç£ |
| | | // http://192.168.0.132:10013 å¸
å¥ |
| | | // http://192.168.0.126:10033 èå§ |
| | | // http://192.168.0.176:10028 èå§ |
| | | // http://192.168.0.186:10028 任康 |
| | | // https://dmtest.ahapp.net/admin_api æµè¯æ |
| | | // http://10.10.99.63/admin_interface/ ææ°æµè¯æï¼å
ç½ï¼ |
| | |
| | | }).then(res => { |
| | | if (res.code === 200) { |
| | | that.$store.commit('setOpenId', res.data.openid) |
| | | if (res.data.member) { |
| | | that.$store.commit('setMember', res.data.member) |
| | | } |
| | | } |
| | | }) |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template name="yq-avatar"> |
| | | <view class="croppage"> |
| | | <canvas canvas-id="avatar-canvas" id="avatar-canvas" class="my-canvas" :style="{top: sT, height: csH}" |
| | | :disable-scroll="false"></canvas> |
| | | <canvas canvas-id="oper-canvas" id="oper-canvas" class="oper-canvas" :style="{top: sT1, height: csH1}" |
| | | :disable-scroll="false" @touchstart="fStart" @touchmove="fMove" @touchend="fEnd"> |
| | | </canvas> |
| | | <canvas canvas-id="prv-canvas" id="prv-canvas" class="prv-canvas" :disable-scroll="false" @touchstart="fHideImg" |
| | | :style="{ height: csH, top: pT }"> |
| | | </canvas> |
| | | <view class="oper-wrapper" :style="{top:tp}"> |
| | | <view class="oper"> |
| | | <view class="btn-wrapper"> |
| | | <view @click="rechoose" hover-class="hover" :style="{width: bW}"><text>éé</text></view> |
| | | <view @click="fUpload" hover-class="hover" :style="{width: bW}"><text>ç¡®å®</text></view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | const tH = 50; |
| | | export default { |
| | | data() { |
| | | return { |
| | | sT1num: 0, |
| | | csH1: '0px', |
| | | sT1: 0, |
| | | csH: '0px', |
| | | sD: 'none', |
| | | sT: '-10000px', |
| | | pT: '-10000px', |
| | | iS: {}, |
| | | sS: {}, |
| | | bW: '19%', |
| | | bD: 'flex', |
| | | tp: 0, |
| | | }; |
| | | }, |
| | | props: { |
| | | avatarSrc: '', |
| | | avatarStyle: '', |
| | | selWidth: '', |
| | | selHeight: '', |
| | | expWidth: '', |
| | | expHeight: '', |
| | | minScale: '', |
| | | maxScale: '', |
| | | canScale: '', |
| | | canRotate: '', |
| | | lockWidth: '', |
| | | lockHeight: '', |
| | | stretch: '', |
| | | lock: '', |
| | | fileType: '', |
| | | noTab: '', |
| | | inner: '', |
| | | quality: '', |
| | | index: '', |
| | | bgImage: '', |
| | | }, |
| | | created() { |
| | | this.cc = uni.createCanvasContext('avatar-canvas', this); |
| | | this.cco = uni.createCanvasContext('oper-canvas', this); |
| | | this.ccp = uni.createCanvasContext('prv-canvas', this); |
| | | this.qlty = parseFloat(this.quality) || 1; //ç»è´¨ |
| | | this.letRotate = (this.canRotate === false || this.inner === true || this.inner === 'true' || this |
| | | .canRotate === 'false') ? 0 : 1; //æ¯å¦æè½¬ |
| | | this.letScale = (this.canScale === false || this.canScale === 'false') ? 0 : 1; //æ¯å¦æ¾å¤§ |
| | | this.isin = (this.inner === true || this.inner === 'true') ? 1 : 0; |
| | | this.indx = this.index || undefined; //ç¦æ¢æè½¬å¹¶å¨å¾çèå´å
ç§»å¨ |
| | | this.mnScale = parseFloat(this.minScale) || 0.3; //ç¼©å°æ¯ä¾ |
| | | this.mxScale = parseFloat(this.maxScale) || 4; //æ¾å¤§æ¯å |
| | | this.noBar = (this.noTab === true || this.noTab === 'true') ? 1 : 0; //æ¯å¦åå¨nobar |
| | | this.stc = this.stretch; //èªå¨éºæ»¡ |
| | | this.lck = this.lock; //éå®å¾æ¹å x y long short longSel shortSel |
| | | this.fType = this.fileType === 'jpg' ? 'jpg' : 'png'; |
| | | if (this.isin || !this.letRotate) { |
| | | this.bW = '24%'; |
| | | this.bD = 'none'; |
| | | } else { |
| | | this.bW = '19%'; |
| | | this.bD = 'flex'; |
| | | } |
| | | if (this.noBar) { |
| | | this.fWindowResize(); |
| | | } else { |
| | | uni.showTabBar({ |
| | | fail: () => { |
| | | this.noBar = 1; |
| | | }, |
| | | success: () => { |
| | | this.noBar = 0; |
| | | }, |
| | | complete: (res) => { |
| | | this.fWindowResize(); |
| | | } |
| | | }); |
| | | } |
| | | }, |
| | | methods: { |
| | | //éé |
| | | rechoose() { |
| | | const that = this |
| | | uni.chooseImage({ |
| | | count: 1, |
| | | sizeType: ['original', 'compressed'], |
| | | sourceType: ["album"], |
| | | success: (res) => { |
| | | that.sT1 = that.sT |
| | | that.csH1 = that.csH |
| | | that.fSelect(res.tempFilePaths[0]) |
| | | } |
| | | }); |
| | | }, |
| | | //åå§ååç§æ°æ® |
| | | fWindowResize() { |
| | | let sysInfo = uni.getSystemInfoSync(); |
| | | this.platform = sysInfo.platform; |
| | | this.wW = sysInfo.windowWidth; |
| | | // #ifndef H5 |
| | | let phone = uni.getSystemInfoSync().platform |
| | | console.log(uni.getSystemInfoSync().platform) |
| | | if (phone == 'ios') { |
| | | let h = uni.upx2px(60); //å°rpxåä½å¼è½¬æ¢æpx è£åªæ¡èªå·± |
| | | let b = uni.upx2px(100); //åºé¨æé® |
| | | this.sT1 = (sysInfo.windowHeight - h - b) / 2 + 'px' //è£åªæ¡è·ç¦»é¡¶é¨+px |
| | | this.sT1num = (sysInfo.windowHeight - h - b) / 2 //è£åªæ¡è·ç¦»é¡¶é¨ä¸+px |
| | | } else { |
| | | this.drawTop = 0; |
| | | } |
| | | // #endif |
| | | // #ifndef MP-ALIPAY |
| | | let phone = uni.getSystemInfoSync().platform |
| | | this.wH = sysInfo.windowHeight; //设å¤é« |
| | | if (!this.noBar) this.wH += tH; //th=50 |
| | | this.csH = this.wH - tH + 'px'; //é«=设å¤é«-50(导èª) |
| | | if (phone == 'ios') { //éé
ios |
| | | this.csH1 = (this.wH - 50) / 2 + 'px' |
| | | } else { |
| | | this.csH1 = this.wH - tH + 'px'; |
| | | } |
| | | // #endif |
| | | this.tp = this.csH; |
| | | this.pxRatio = this.wW / 750; //设å¤å®½/750 æ¯å |
| | | this.expWidth && (this.eW = this.expWidth.toString().indexOf('upx') >= 0 ? parseInt(this.expWidth) * this |
| | | .pxRatio : parseInt(this.expWidth)); |
| | | this.expHeight && (this.eH = this.expHeight.toString().indexOf('upx') >= 0 ? parseInt(this.expHeight) * |
| | | this.pxRatio : parseInt(this.expHeight)); |
| | | this.fHideImg(); |
| | | }, |
| | | fSelect(r) { |
| | | if (this.fSelecting) return; |
| | | this.fSelecting = true; |
| | | setTimeout(() => { |
| | | this.fSelecting = false; |
| | | }, 500); //鲿 |
| | | let path = this.imgPath = r; //éè¦åªè£çå¾çè·¯å¾ |
| | | // è·åå¾çä¿¡æ¯ |
| | | uni.getImageInfo({ |
| | | src: path, |
| | | success: r => { |
| | | this.imgWidth = r.width; |
| | | this.imgHeight = r.height; |
| | | this.path = path; |
| | | if (!this.hasSel) { |
| | | let style = this.sS || {}; |
| | | if (this.selWidth && this.selHeight) { //设置çåªè£åºåå®½é« |
| | | let sW = this.selWidth.toString().indexOf('upx') >= 0 ? |
| | | parseInt(this.selWidth) * this.pxRatio : parseInt( |
| | | this.selWidth), |
| | | sH = this.selHeight.toString().indexOf('upx') >= 0 ? |
| | | parseInt(this.selHeight) * this.pxRatio : parseInt( |
| | | this.selHeight); |
| | | style.width = sW + 'px'; |
| | | style.height = sH + 'px'; |
| | | style.top = ((this.wH - sH - tH) | 0) / 2 + 'px'; |
| | | style.left = ((this.wW - sW) | 0) / 2 + 'px'; |
| | | // } |
| | | } else { |
| | | uni.showModal({ |
| | | title: 'è£åªæ¡ç宽æé«æ²¡æè®¾ç½®', |
| | | showCancel: false |
| | | }) |
| | | return; |
| | | } |
| | | this.sS = style; |
| | | } |
| | | if (this.noBar) { |
| | | setTimeout(() => { |
| | | this.fDrawInit(true); |
| | | }, 200) |
| | | } else { |
| | | uni.hideTabBar({ |
| | | complete: () => { |
| | | setTimeout(() => { |
| | | this.fDrawInit(true); |
| | | }, 200) |
| | | } |
| | | }); |
| | | } |
| | | }, |
| | | fail: () => { |
| | | uni.showToast({ |
| | | title: "è¯·éæ©æ£ç¡®å¾ç", |
| | | duration: 2000, |
| | | }) |
| | | }, |
| | | complete() { |
| | | uni.hideLoading(); |
| | | } |
| | | }); |
| | | }, |
| | | //åªè£ç¡®å® |
| | | fUpload() { |
| | | uni.showLoading({ |
| | | title: 'å¾çä¸ä¼ ä¸...', |
| | | mask: true |
| | | }); |
| | | if (this.fUploading) return; |
| | | this.fUploading = true; |
| | | setTimeout(() => { |
| | | this.fUploading = false; |
| | | }, 1000) |
| | | let style = this.sS, |
| | | x = parseInt(style.left), |
| | | y = parseInt(style.top), |
| | | width = parseInt(style.width), |
| | | height = parseInt(style.height), |
| | | expWidth = this.eW || (width * this.pixelRatio), |
| | | expHeight = this.eH || (height * this.pixelRatio); |
| | | this.fHideImg(); |
| | | // #ifndef MP-ALIPAY |
| | | let phone = uni.getSystemInfoSync().platform |
| | | if (phone == 'ios') { |
| | | y = this.sT1num |
| | | } |
| | | uni.canvasToTempFilePath({ |
| | | x: x, |
| | | y: y, |
| | | width: width, |
| | | height: height, |
| | | destWidth: expWidth, |
| | | destHeight: expHeight, |
| | | canvasId: 'avatar-canvas', |
| | | fileType: this.fType, |
| | | quality: this.qlty, |
| | | success: (r) => { |
| | | r = r.tempFilePath; |
| | | // #ifndef H5 |
| | | this.$emit("upload", { |
| | | avatar: this.imgSrc, |
| | | path: r, |
| | | index: this.indx, |
| | | data: this.rtn, |
| | | base64: this.base64 || null |
| | | }); |
| | | // #endif |
| | | }, |
| | | fail: (res) => { |
| | | uni.showToast({ |
| | | title: "error1", |
| | | duration: 2000, |
| | | }) |
| | | }, |
| | | complete: () => { |
| | | uni.hideLoading(); |
| | | this.noBar || uni.showTabBar(); |
| | | this.$emit("end"); |
| | | } |
| | | }, this); |
| | | // #endif |
| | | }, |
| | | fDrawInit(ini = false) { |
| | | let allWidth = this.wW, //设å¤å®½ |
| | | allHeight = this.wH, //设å¤é« |
| | | imgWidth = this.imgWidth, //å¾å®½ |
| | | imgHeight = this.imgHeight, //å¾é« |
| | | imgRadio = imgWidth / imgHeight, //徿¯ |
| | | useWidth = allWidth - 40, //设å¤å®½-40 |
| | | useHeight = allHeight - tH - 80, //设å¤é«-80 |
| | | useRadio = useWidth / useHeight, |
| | | sW = parseInt(this.sS.width), //å¾çä¿¡æ¯ |
| | | sH = parseInt(this.sS.height); |
| | | this.fixWidth = 0; |
| | | this.fixHeight = 0; |
| | | this.lckWidth = 0; |
| | | this.lckHeight = 0; |
| | | switch (this.stc) { //以䏿¯èªå¨éºæ»¡çç®æ³ |
| | | case 'x': |
| | | this.fixWidth = 1; |
| | | break; |
| | | case 'y': |
| | | this.fixHeight = 1; |
| | | break; |
| | | case 'long': |
| | | if (imgRadio > 1) this.fixWidth = 1; |
| | | else this.fixHeight = 1; |
| | | break; |
| | | case 'short': |
| | | if (imgRadio > 1) this.fixHeight = 1; |
| | | else this.fixWidth = 1; |
| | | break; |
| | | case 'longSel': |
| | | if (sW > sH) this.fixWidth = 1; |
| | | else this.fixHeight = 1; |
| | | break; |
| | | case 'shortSel': |
| | | if (sW > sH) this.fixHeight = 1; |
| | | else this.fixWidth = 1; |
| | | break; |
| | | } |
| | | switch (this.lck) { //以ä¸éå®å±å¹çç§»å¨æ¹å |
| | | case 'x': |
| | | this.lckWidth = 1; |
| | | break; |
| | | case 'y': |
| | | this.lckHeight = 1; |
| | | break; |
| | | case 'long': |
| | | if (imgRadio > 1) this.lckWidth = 1; |
| | | else this.lckHeight = 1; |
| | | break; |
| | | case 'short': |
| | | if (imgRadio > 1) this.lckHeight = 1; |
| | | else this.lckWidth = 1; |
| | | break; |
| | | case 'longSel': |
| | | if (sW > sH) this.lckWidth = 1; |
| | | else this.lckHeight = 1; |
| | | break; |
| | | case 'shortSel': |
| | | if (sW > sH) this.lckHeight = 1; |
| | | else this.lckWidth = 1; |
| | | break; |
| | | } |
| | | if (this.fixWidth) { |
| | | useWidth = sW; |
| | | useHeight = useWidth / imgRadio; |
| | | } else if (this.fixHeight) { |
| | | useHeight = sH; |
| | | useWidth = useHeight * imgRadio; |
| | | } else if (imgRadio < useRadio) { |
| | | if (imgHeight < useHeight) { |
| | | useWidth = imgWidth; |
| | | useHeight = imgHeight; |
| | | } else { |
| | | useWidth = useHeight * imgRadio; |
| | | } |
| | | } else { |
| | | if (imgWidth < useWidth) { |
| | | useWidth = imgWidth; |
| | | useHeight = imgHeight; |
| | | } else { |
| | | useHeight = useWidth / imgRadio; |
| | | } |
| | | } |
| | | if (this.isin) { |
| | | if (useWidth < sW) { |
| | | useWidth = sW; |
| | | useHeight = useWidth / imgRadio; |
| | | this.lckHeight = 0; |
| | | } |
| | | if (useHeight < sH) { |
| | | useHeight = sH; |
| | | useWidth = useHeight * imgRadio; |
| | | this.lckWidth = 0; |
| | | } |
| | | } |
| | | this.scaleSize = 1; |
| | | this.rotateDeg = 0; |
| | | this.posWidth = (allWidth - useWidth) / 2 | 0; |
| | | this.posHeight = (allHeight - useHeight - tH) / 2 | 0; |
| | | this.useWidth = useWidth | 0; |
| | | this.useHeight = useHeight | 0; |
| | | this.centerX = this.posWidth + useWidth / 2; |
| | | this.centerY = this.posHeight + useHeight / 2; |
| | | this.focusX = 0; |
| | | this.focusY = 0; |
| | | let style = this.sS, |
| | | left = parseInt(style.left), |
| | | top = parseInt(style.top), |
| | | width = parseInt(style.width), |
| | | height = parseInt(style.height), |
| | | canvas = this.canvas, |
| | | canvasOper = this.canvasOper, |
| | | cc = this.cc, //avatar-canvas |
| | | cco = this.cco; //oper-canvas è£åª |
| | | cco.beginPath(); //å¼å§å建ä¸ä¸ªè·¯å¾ |
| | | cco.setLineWidth(3); //设置线æ¡ç宽度 px |
| | | cco.setGlobalAlpha(1); //设置å
¨å±ç»ç¬éæåº¦ã |
| | | cco.setStrokeStyle('white'); //设置边æ¡é¢è²ãå¦ææ²¡æè®¾ç½® fillStyleï¼é»è®¤é¢è²ä¸º blackã |
| | | cco.strokeRect(left, top, width, height); //ç»ä¸ä¸ªç©å½¢(éå¡«å
)ãç¨ setFillStroke() 设置边æ¡é¢è²ï¼å¦ææ²¡è®¾ç½®é»è®¤æ¯é»è²ã |
| | | cco.setFillStyle('black'); |
| | | cco.setGlobalAlpha(0.5); |
| | | cco.fillRect(0, 0, this.wW, top); //å¡«å
ä¸ä¸ªç©å½¢ |
| | | cco.fillRect(0, top, left, height); |
| | | cco.fillRect(0, top + height, this.wW, this.wH - height - top - tH); |
| | | cco.fillRect(left + width, top, this.wW - width - left, height); |
| | | cco.setGlobalAlpha(1); |
| | | cco.setStrokeStyle('red'); |
| | | cco.moveTo(left + 15, top); //æè·¯å¾ç§»å¨å°ç»å¸ä¸çæå®ç¹ï¼ä¸å建线æ¡ãç¨ stroke() æ¹æ³æ¥ç»çº¿æ¡ã |
| | | cco.lineTo(left, top); //å¢å ä¸ä¸ªæ°ç¹ï¼ç¶ååå»ºä¸æ¡ä»ä¸æ¬¡æå®ç¹å°ç®æ ç¹ç线ã |
| | | cco.lineTo(left, top + 15); |
| | | cco.moveTo(left + width - 15, top); |
| | | cco.lineTo(left + width, top); |
| | | cco.lineTo(left + width, top + 15); |
| | | cco.moveTo(left + 15, top + height); |
| | | cco.lineTo(left, top + height); |
| | | cco.lineTo(left, top + height - 15); |
| | | cco.moveTo(left + width - 15, top + height); |
| | | cco.lineTo(left + width, top + height); |
| | | cco.lineTo(left + width, top + height - 15); |
| | | cco.stroke(); //ç»çº¿æ¡ |
| | | cco.draw(false, () => { //å°ä¹åå¨ç»å¾ä¸ä¸æä¸çæè¿°ï¼è·¯å¾ãåå½¢ãæ ·å¼ï¼ç»å° canvas ä¸ã |
| | | if (ini) { |
| | | this.sT = this.drawTop + 'px'; |
| | | this.fDrawImage(true); //ç»å¶èæ¯è² |
| | | } |
| | | }); |
| | | this.$emit("init"); |
| | | }, |
| | | //ç»å¶èæ¯è² |
| | | fDrawImage(ini = false) { |
| | | let tm_now = Date.now(); //å½åæ¶é´ |
| | | if (tm_now - this.drawTm < 20) return; |
| | | this.drawTm = tm_now; |
| | | let cc = this.cc, |
| | | imgWidth = this.useWidth * this.scaleSize, |
| | | imgHeight = this.useHeight * this.scaleSize; |
| | | if (this.bgImage) { //å¦æèæ¯å¾ |
| | | // #ifndef MP-ALIPAY |
| | | cc.drawImage(this.bgImage, 0, 0, this.wW, this.wH - tH); //ç»å¶å¾åå°ç»å¸ã |
| | | // #endif |
| | | } else { |
| | | cc.fillRect(0, 0, this.wW, this.wH - tH); //å¡«å
ä¸ä¸ªç©å½¢ |
| | | } |
| | | if (this.isin) { //ç¦æ¢æè½¬å¹¶å¨å¾çèå´å
ç§»å¨ |
| | | let cx = this.focusX * (this.scaleSize - 1), |
| | | cy = this.focusY * (this.scaleSize - 1); |
| | | cc.translate(this.centerX, this.centerY); |
| | | cc.rotate(this.rotateDeg * Math.PI / 180); |
| | | cc.drawImage(this.imgPath, this.posWidth - this.centerX - cx, this.posHeight - this.centerY - cy, |
| | | imgWidth, imgHeight); |
| | | } else { |
| | | cc.translate(this.posWidth + imgWidth / 2, this.posHeight + imgHeight / 2); |
| | | cc.rotate(this.rotateDeg * Math.PI / 180); |
| | | cc.drawImage(this.imgPath, -imgWidth / 2, -imgHeight / 2, imgWidth, imgHeight); |
| | | } |
| | | cc.draw(false); |
| | | }, |
| | | //æè½¬ |
| | | fRotate() { |
| | | this.rotateDeg += 90 - this.rotateDeg % 90; |
| | | this.fDrawImage(); |
| | | }, |
| | | //ææè§¦æ¸å¼å§ |
| | | fStart(e) { |
| | | let touches = e.touches, |
| | | touch0 = touches[0], |
| | | touch1 = touches[1]; |
| | | this.touch0 = touch0; |
| | | this.touch1 = touch1; |
| | | if (touch1) { |
| | | let x = touch1.x - touch0.x, |
| | | y = touch1.y - touch0.y; |
| | | this.fgDistance = Math.sqrt(x * x + y * y); |
| | | } |
| | | }, |
| | | //ææè§¦æ¸åç§»å¨ |
| | | fMove(e) { |
| | | let touches = e.touches, |
| | | touch0 = touches[0], |
| | | touch1 = touches[1]; |
| | | if (touch1) { |
| | | let x = touch1.x - touch0.x, |
| | | y = touch1.y - touch0.y, |
| | | fgDistance = Math.sqrt(x * x + y * y), |
| | | scaleSize = 0.005 * (fgDistance - this.fgDistance), |
| | | beScaleSize = this.scaleSize + scaleSize; |
| | | do { |
| | | if (!this.letScale) break; |
| | | if (beScaleSize < this.mnScale) break; |
| | | if (beScaleSize > this.mxScale) break; |
| | | let growX = this.useWidth * scaleSize / 2, |
| | | growY = this.useHeight * scaleSize / 2; |
| | | if (this.isin) { |
| | | let imgWidth = this.useWidth * beScaleSize, |
| | | imgHeight = this.useHeight * beScaleSize, |
| | | l = this.posWidth - growX, |
| | | t = this.posHeight - growY, |
| | | r = l + imgWidth, |
| | | b = t + imgHeight, |
| | | left = parseInt(this.sS.left), |
| | | top = parseInt(this.sS.top), |
| | | width = parseInt(this.sS.width), |
| | | height = parseInt(this.sS.height), |
| | | right = left + width, |
| | | bottom = top + height, |
| | | cx, cy; |
| | | if (imgWidth <= width || imgHeight <= height) break; |
| | | this.cx = cx = this.focusX * beScaleSize - this.focusX, |
| | | this.cy = cy = this.focusY * beScaleSize - this.focusY; |
| | | this.posWidth -= growX; |
| | | this.posHeight -= growY; |
| | | if (this.posWidth - cx > left) { |
| | | this.posWidth = left + cx; |
| | | } |
| | | if (this.posWidth + imgWidth - cx < right) { |
| | | this.posWidth = right - imgWidth + cx; |
| | | } |
| | | if (this.posHeight - cy > top) { |
| | | this.posHeight = top + cy; |
| | | } |
| | | if (this.posHeight + imgHeight - cy < bottom) { |
| | | this.posHeight = bottom - imgHeight + cy; |
| | | } |
| | | } else { |
| | | this.posWidth -= growX; |
| | | this.posHeight -= growY; |
| | | } |
| | | this.scaleSize = beScaleSize; |
| | | } while (0); |
| | | this.fgDistance = fgDistance; |
| | | if (touch1.x !== touch0.x && this.letRotate) { |
| | | x = (this.touch1.y - this.touch0.y) / (this.touch1.x - this.touch0.x); |
| | | y = (touch1.y - touch0.y) / (touch1.x - touch0.x); |
| | | this.rotateDeg += Math.atan((y - x) / (1 + x * y)) * 180 / Math.PI; |
| | | this.touch0 = touch0; |
| | | this.touch1 = touch1; |
| | | } |
| | | this.fDrawImage(); |
| | | } else if (this.touch0) { |
| | | let x = touch0.x - this.touch0.x, |
| | | y = touch0.y - this.touch0.y, |
| | | beX = this.posWidth + x, |
| | | beY = this.posHeight + y; |
| | | if (this.isin) { |
| | | let imgWidth = this.useWidth * this.scaleSize, |
| | | imgHeight = this.useHeight * this.scaleSize, |
| | | l = beX, |
| | | t = beY, |
| | | r = l + imgWidth, |
| | | b = t + imgHeight, |
| | | left = parseInt(this.sS.left), |
| | | top = parseInt(this.sS.top), |
| | | right = left + parseInt(this.sS.width), |
| | | bottom = top + parseInt(this.sS.height), |
| | | cx, cy; |
| | | this.cx = cx = this.focusX * this.scaleSize - this.focusX; |
| | | this.cy = cy = this.focusY * this.scaleSize - this.focusY; |
| | | if (!this.lckWidth && Math.abs(x) < 100) { |
| | | if (left < l - cx) { |
| | | this.posWidth = left + cx; |
| | | } else if (right > r - cx) { |
| | | this.posWidth = right - imgWidth + cx; |
| | | } else { |
| | | this.posWidth = beX; |
| | | this.focusX -= x; |
| | | } |
| | | } |
| | | if (!this.lckHeight && Math.abs(y) < 100) { |
| | | if (top < t - cy) { |
| | | this.focusY -= (top + cy - this.posHeight); |
| | | this.posHeight = top + cy; |
| | | } else if (bottom > b - cy) { |
| | | this.focusY -= (bottom + cy - (this.posHeight + imgHeight)); |
| | | this.posHeight = bottom - imgHeight + cy; |
| | | } else { |
| | | this.posHeight = beY; |
| | | this.focusY -= y; |
| | | } |
| | | } |
| | | } else { |
| | | if (Math.abs(x) < 100 && !this.lckWidth) this.posWidth = beX; |
| | | if (Math.abs(y) < 100 && !this.lckHeight) this.posHeight = beY; |
| | | this.focusX -= x; |
| | | this.focusY -= y; |
| | | } |
| | | this.touch0 = touch0; |
| | | this.fDrawImage(); |
| | | } |
| | | }, |
| | | //ææè§¦æ¸å¨ä½ç»æ |
| | | fEnd(e) { |
| | | let touches = e.touches, |
| | | touch0 = touches && touches[0], |
| | | touch1 = touches && touches[1]; |
| | | if (touch0) { |
| | | this.touch0 = touch0; |
| | | } else { |
| | | this.touch0 = null; |
| | | this.touch1 = null; |
| | | } |
| | | }, |
| | | fHideImg() { |
| | | this.prvImg = ''; |
| | | this.pT = '-10000px'; |
| | | this.prvImgData = null; |
| | | this.target = null; |
| | | }, |
| | | } |
| | | } |
| | | </script> |
| | | <style> |
| | | .croppage { |
| | | width: 100%; |
| | | height: 100%; |
| | | box-sizing: border-box; |
| | | background-color: #000000; |
| | | position: relative; |
| | | } |
| | | .my-canvas { |
| | | /* display: flex; */ |
| | | position: absolute !important; |
| | | left: 0; |
| | | z-index: 100000; |
| | | width: 100%; |
| | | } |
| | | .my-avatar { |
| | | width: 150upx; |
| | | height: 150upx; |
| | | border-radius: 100%; |
| | | } |
| | | .oper-canvas { |
| | | /* display: flex; */ |
| | | position: absolute !important; |
| | | left: 0; |
| | | z-index: 100000; |
| | | width: 100%; |
| | | } |
| | | .prv-canvas { |
| | | display: flex; |
| | | position: fixed !important; |
| | | background: #000000; |
| | | left: 0; |
| | | z-index: 200000; |
| | | width: 100%; |
| | | } |
| | | .oper-wrapper { |
| | | height: 100rpx; |
| | | position: fixed !important; |
| | | box-sizing: border-box; |
| | | border: 1px solid #F1F1F1; |
| | | background: #ffffff; |
| | | width: 100%; |
| | | left: 0; |
| | | bottom: 0; |
| | | z-index: 99999999; |
| | | flex-direction: row; |
| | | } |
| | | .oper { |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | padding: 10upx 20upx; |
| | | width: 100%; |
| | | height: 100%; |
| | | box-sizing: border-box; |
| | | align-self: center; |
| | | } |
| | | .btn-wrapper { |
| | | display: flex; |
| | | flex-direction: row; |
| | | flex-grow: 1; |
| | | height: 50px; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .btn-wrapper view { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 16px; |
| | | color: #3b7ffb; |
| | | border-radius: 6%; |
| | | } |
| | | .hover { |
| | | background: #f1f1f1; |
| | | border-radius: 6%; |
| | | } |
| | | .clr-wrapper { |
| | | display: flex; |
| | | flex-direction: row; |
| | | flex-grow: 1; |
| | | } |
| | | .clr-wrapper view { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 16px; |
| | | color: #333; |
| | | border: 1px solid #f1f1f1; |
| | | border-radius: 6%; |
| | | } |
| | | .my-slider { |
| | | flex-grow: 1; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="so-mask" v-if="show"> |
| | | <view style="height: 100%" @tap="$emit('close')" /> |
| | | <view class="so-plate animation-scale-up"> |
| | | <view class="so-plate-head"> |
| | | <view class="so-plate-type"> |
| | | <radio-group @change="typeChange"> |
| | | <label> |
| | | <radio value="1" :checked="type===1" /> |
| | | æ®é车ç |
| | | </label> |
| | | <label> |
| | | <radio value="2" :checked="type===2" /> |
| | | æ°è½æºè½¦ç |
| | | </label> |
| | | </radio-group> |
| | | </view> |
| | | </view> |
| | | <view class="so-plate-body"> |
| | | <view class="so-plate-word" :class="{ active: currentInputIndex == 0 }" @tap="inputSwitch" |
| | | data-index="0"> |
| | | <text>{{ currentInputValue[0] }}</text> |
| | | </view> |
| | | <view class="so-plate-word" :class="{ active: currentInputIndex == 1 }" @tap="inputSwitch" |
| | | data-index="1"> |
| | | <text>{{ currentInputValue[1] }}</text> |
| | | </view> |
| | | <view class="so-plate-dot"></view> |
| | | <view class="so-plate-word" :class="{ active: currentInputIndex == 2 }" @tap="inputSwitch" |
| | | data-index="2"> |
| | | <text>{{ currentInputValue[2] }}</text> |
| | | </view> |
| | | <view class="so-plate-word" :class="{ active: currentInputIndex == 3 }" @tap="inputSwitch" |
| | | data-index="3"> |
| | | <text>{{ currentInputValue[3] }}</text> |
| | | </view> |
| | | <view class="so-plate-word" :class="{ active: currentInputIndex == 4 }" @tap="inputSwitch" |
| | | data-index="4"> |
| | | <text>{{ currentInputValue[4] }}</text> |
| | | </view> |
| | | <view class="so-plate-word" :class="{ active: currentInputIndex == 5 }" @tap="inputSwitch" |
| | | data-index="5"> |
| | | <text>{{ currentInputValue[5] }}</text> |
| | | </view> |
| | | <view class="so-plate-word" :class="{ active: currentInputIndex == 6 }" @tap="inputSwitch" |
| | | data-index="6"> |
| | | <text>{{ currentInputValue[6] }}</text> |
| | | </view> |
| | | <view class="so-plate-word" :class="{ active: currentInputIndex == 7 }" @tap="inputSwitch" |
| | | v-if="type == 2" data-index="7"> |
| | | <text>{{ currentInputValue[7] }}</text> |
| | | </view> |
| | | </view> |
| | | <view class="so-plate-foot"> |
| | | <view class="so-plate-keyboard" :style="{height:keyboardHeight}"> |
| | | <view id="keyboard"> |
| | | <block v-if="inputType == 1"> |
| | | <view hover-class="hover" class="so-plate-key" v-for="el of provinceText" :key="el" |
| | | :data-value="el" @tap="chooseKey">{{ el }}</view> |
| | | </block> |
| | | <block v-if="inputType == 1"> |
| | | <text class="so-plate-key fill-block"></text> |
| | | </block> |
| | | <block v-if="inputType >= 3"> |
| | | <view hover-class="hover" class="so-plate-key" v-for="el of numberText" :key="el" |
| | | :data-value="el" @tap="chooseKey">{{ el }}</view> |
| | | </block> |
| | | <block v-if="inputType >= 2"> |
| | | <view hover-class="hover" class="so-plate-key" v-for="el of wordText" :key="el" |
| | | :data-value="el" @tap="chooseKey">{{ el }}</view> |
| | | </block> |
| | | <block v-if="inputType == 3"> |
| | | <text v-for="el of fillBlock" :key="el.num" class="so-plate-key fill-block"></text> |
| | | </block> |
| | | <block v-if="inputType == 4"> |
| | | <view hover-class="hover" class="so-plate-key" v-for="el of lastWordText" :key="el" |
| | | :data-value="el" @tap="chooseKey">{{ el }}</view> |
| | | </block> |
| | | <text v-if="inputType == 4" class="so-plate-key fill-block"></text> |
| | | </view> |
| | | </view> |
| | | <view class="so-plate-btn-group"> |
| | | <view> |
| | | <button class="so-plate-btn so-plate-btn--cancel" @tap="$emit('close')">åæ¶</button> |
| | | </view> |
| | | <view> |
| | | <button class="so-plate-btn so-plate-btn--delete" @tap="deleteKey">å é¤</button> |
| | | <button class="so-plate-btn so-plate-btn--submit" @tap="exportPlate">宿</button> |
| | | |
| | | </view> |
| | | |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view v-else></view> |
| | | </template> |
| | | <script> |
| | | export default { |
| | | name: 'uni-plate-input', |
| | | data() { |
| | | return { |
| | | show: false, |
| | | type: 1, //车çç±»å |
| | | currentInputIndex: 0, //å½åç¼è¾çè¾å
¥æ¡ |
| | | currentInputValue: ['', '', '', '', '', '', ''], |
| | | fillBlock: [{ |
| | | num: 11 |
| | | }, { |
| | | num: 12 |
| | | }, { |
| | | num: 13 |
| | | }, { |
| | | num: 14 |
| | | }, { |
| | | num: 15 |
| | | }, { |
| | | num: 16 |
| | | }], //é¿å
:keyæ¥é |
| | | keyboardHeightInit: false, |
| | | keyboardHeight: 'auto', |
| | | provinceText: [ |
| | | '粤', |
| | | '京', |
| | | 'å', |
| | | '沪', |
| | | 'æ´¥', |
| | | 'æ', |
| | | 'è', |
| | | 'è¾½', |
| | | 'å', |
| | | 'é»', |
| | | 'è', |
| | | 'æµ', |
| | | 'ç', |
| | | 'é½', |
| | | 'èµ£', |
| | | 'é²', |
| | | '豫', |
| | | 'é', |
| | | 'æ¹', |
| | | 'æ¡', |
| | | 'ç¼', |
| | | 'æ¸', |
| | | 'å·', |
| | | 'è´µ', |
| | | 'äº', |
| | | 'è', |
| | | 'é', |
| | | 'ç', |
| | | 'é', |
| | | 'å®', |
| | | 'æ°' |
| | | ], |
| | | numberText: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'], |
| | | wordText: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', |
| | | 'V', 'W', 'X', 'Y', 'Z' |
| | | ], |
| | | lastWordText: ['æ', '港', 'å¦', 'é¢', 'è¦'] |
| | | }; |
| | | }, |
| | | props: { |
| | | plate: { |
| | | type: String |
| | | } |
| | | }, |
| | | computed: { |
| | | //è¾å
¥æ¡ç±»å |
| | | inputType() { |
| | | switch (this.currentInputIndex) { |
| | | case 0: |
| | | return 1; |
| | | break; |
| | | case 1: |
| | | return 2; |
| | | break; |
| | | case 2: |
| | | return 3; |
| | | break; |
| | | case 3: |
| | | return 3; |
| | | break; |
| | | case 4: |
| | | return 3; |
| | | break; |
| | | case 5: |
| | | return 3; |
| | | break; |
| | | case 6: |
| | | return this.type == 2 ? 3 : 4; |
| | | break; |
| | | case 7: |
| | | return 4; |
| | | break; |
| | | default: |
| | | return 1; |
| | | break; |
| | | } |
| | | } |
| | | }, |
| | | watch: { |
| | | currentInputIndex: function(n, o) { |
| | | if (!this.keyboardHeightInit) return |
| | | this.$nextTick(() => { |
| | | this.changeKeyboardHeight() |
| | | }) |
| | | } |
| | | }, |
| | | methods: { |
| | | open() { |
| | | this.type = 1 |
| | | this.currentInputIndex = 0 |
| | | this.currentInputValue = ['', '', '', '', '', '', ''] |
| | | this.show = true |
| | | setTimeout(() => { //å¨å¨ç»ç»æä¹åæå¼å§è·å |
| | | this.$nextTick(() => { |
| | | this.changeKeyboardHeight() |
| | | }) |
| | | }, 500); |
| | | }, |
| | | close() { |
| | | this.show = false |
| | | }, |
| | | //车çç±»å忢 |
| | | typeChange(e) { |
| | | this.$emit("typeChange", e.detail.value); |
| | | const { |
| | | value |
| | | } = e.detail; |
| | | this.type = parseInt(value) |
| | | this.currentInputIndex = 0 |
| | | if (value == 1) { |
| | | this.currentInputValue = ['', '', '', '', '', '', ''] |
| | | } else { |
| | | this.currentInputValue = ['', '', '', '', '', '', '', ''] |
| | | } |
| | | }, |
| | | inputSwitch(e) { |
| | | const { |
| | | index |
| | | } = e.currentTarget.dataset; |
| | | this.currentInputIndex = parseInt(index); |
| | | }, |
| | | chooseKey(e) { |
| | | const { |
| | | value |
| | | } = e.currentTarget.dataset; |
| | | this.$set(this.currentInputValue, this.currentInputIndex, value); |
| | | if (this.type == 1 && this.currentInputIndex < 6) { |
| | | this.currentInputIndex++ |
| | | } |
| | | if (this.type == 2 && this.currentInputIndex < 7) { |
| | | this.currentInputIndex++ |
| | | } |
| | | }, |
| | | deleteKey() { |
| | | this.$set(this.currentInputValue, this.currentInputIndex, '') |
| | | if (this.currentInputIndex != 0) this.currentInputIndex-- |
| | | }, |
| | | exportPlate() { |
| | | const plate = this.currentInputValue.join('') |
| | | let err = false |
| | | if (this.type === 1 && plate.length != 7) { |
| | | err = true |
| | | } else if (this.type === 2 && plate.length != 8) { |
| | | err = true |
| | | } |
| | | if (err) return uni.showToast({ |
| | | title: '请è¾å
¥å®æ´ç车çå·ç ', |
| | | icon: 'none' |
| | | }) |
| | | |
| | | this.$emit('export', plate) |
| | | }, |
| | | changeKeyboardHeight() { |
| | | const that = this |
| | | const query = uni.createSelectorQuery().in(this); |
| | | query.select('#keyboard').boundingClientRect(); |
| | | query.exec(function(res) { |
| | | if (res && res[0]) { |
| | | that.keyboardHeight = res[0].height + uni.upx2px(30) + 'px' |
| | | that.keyboardHeightInit = true |
| | | } |
| | | }); |
| | | } |
| | | }, |
| | | mounted() { |
| | | // console.log(this.plate); |
| | | // const plateKey = this.plate.split('') |
| | | // if (plateKey.length === 7) { |
| | | // this.type = 1 |
| | | // } else if (plateKey.length === 8) { |
| | | // this.type = 2 |
| | | // } |
| | | // if (plateKey.length === 7 || plateKey.length === 8) { |
| | | // this.currentInputValue = plateKey |
| | | // this.currentInputIndex = plateKey.length - 1 |
| | | // } |
| | | |
| | | // setTimeout(() => { //å¨å¨ç»ç»æä¹åæå¼å§è·å |
| | | // this.$nextTick(() => { |
| | | // this.changeKeyboardHeight() |
| | | // }) |
| | | // }, 500); |
| | | } |
| | | }; |
| | | </script> |
| | | <style scoped lang="less"> |
| | | .so-mask { |
| | | position: fixed; |
| | | top: 0; |
| | | bottom: 0; |
| | | right: 0; |
| | | left: 0; |
| | | background: rgba(0, 0, 0, 0.5); |
| | | z-index: 99999; |
| | | } |
| | | .so-plate { |
| | | box-sizing: border-box; |
| | | position: absolute; |
| | | bottom: 0; |
| | | width: 100%; |
| | | left: 0; |
| | | background: #fff; |
| | | padding: 25upx 25upx 0 25upx; |
| | | &-head { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | &-type { |
| | | flex:1; |
| | | display:block; |
| | | label { |
| | | display: inline-block; |
| | | min-height: 32upx; |
| | | font-size: 26upx; |
| | | margin-right: 10upx; |
| | | } |
| | | } |
| | | &-body { |
| | | box-sizing: border-box; |
| | | padding: 30upx 0; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | &-word { |
| | | border: 1upx solid #ccc; |
| | | border-radius: 10upx; |
| | | height: 0; |
| | | margin: 0 5upx; |
| | | box-sizing: border-box; |
| | | padding-bottom: calc((100% - 70upx) / 7); |
| | | width: calc((100% - 70upx) / 7); |
| | | position: relative; |
| | | &.active { |
| | | border-color: #007aff; |
| | | box-shadow: 0 0 15upx 0 #007aff; |
| | | } |
| | | text { |
| | | position: absolute; |
| | | top: 50%; |
| | | left: 50%; |
| | | transform: translateX(-50%) translateY(-50%); |
| | | font-weight: 700; |
| | | font-size: 32upx; |
| | | } |
| | | } |
| | | &-dot { |
| | | width: 15upx; |
| | | height: 15upx; |
| | | background: #ccc; |
| | | border-radius: 50%; |
| | | margin: 0 5upx; |
| | | } |
| | | &-keyboard { |
| | | background: #eee; |
| | | margin-left: -25upx; |
| | | margin-right: -25upx; |
| | | padding: 20upx 25upx 10upx 25upx; |
| | | box-sizing: border-box; |
| | | transition: all .3s; |
| | | &>view{ |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | justify-content: space-between; |
| | | } |
| | | } |
| | | &-key { |
| | | display: block; |
| | | background: #fff; |
| | | border-radius: 10upx; |
| | | box-shadow: 0 0 8upx 0 #bbb; |
| | | width: 80upx; |
| | | height: 80upx; |
| | | margin: 5upx 0; |
| | | font-size: 32upx; |
| | | text-align: center; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | position: relative; |
| | | &.hover { |
| | | background: #efefef; |
| | | } |
| | | &.fill-block { |
| | | width: 80upx; |
| | | height: 80upx; |
| | | background: none; |
| | | box-shadow: none; |
| | | } |
| | | } |
| | | &-btn { |
| | | display: inline-block; |
| | | background: #fff; |
| | | border-radius: 10upx; |
| | | box-shadow: 0 0 10upx 0 #bbb; |
| | | font-size: 28upx; |
| | | text-align: center; |
| | | margin:0 0 0 10upx; |
| | | padding:0 25upx; |
| | | &-group{ |
| | | display: flex; |
| | | justify-content: space-between; |
| | | background: #eee; |
| | | margin-left: -25upx; |
| | | margin-right: -25upx; |
| | | box-sizing: border-box; |
| | | padding: 0 25upx 10upx 25upx; |
| | | } |
| | | &--cancel{ |
| | | margin:0; |
| | | } |
| | | &--submit{ |
| | | background:#5773f9; |
| | | color:#fff; |
| | | } |
| | | &--delete{ |
| | | color:#fd6b6d; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | .animation-scale-up { |
| | | animation-duration: .2s; |
| | | animation-timing-function: ease-out; |
| | | animation-fill-mode: both; |
| | | animation-name: scale-up |
| | | } |
| | | @keyframes scale-up { |
| | | 0% { |
| | | opacity: .8; |
| | | transform: scale(.8) |
| | | } |
| | | |
| | | 100% { |
| | | opacity: 1; |
| | | transform: scale(1) |
| | | } |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="picture-cut" :class="{'picture-cut-show':isShow}"> |
| | | |
| | | <!-- :style="{width:choosePictureWidth+'px',height:choosePictureHeight+'px',top:choosePictureTop+'px',left:choosePictureLeft+'px'}" --> |
| | | <view class="select-box" :style="{width: '70%', height: '250px', top:choosePictureTop+'px',left: '15%'}"> |
| | | <view class="horn"> |
| | | <!-- <view class="lt" data-drag="leftTop" @touchstart.stop="dragStart" @touchmove.stop.prevent="dragMove" ></view> |
| | | <view class="rt" data-drag="topTight" @touchstart.stop="dragStart" @touchmove.stop.prevent="dragMove" ></view> |
| | | <view class="rb" data-drag="rightBottom" @touchstart.stop="dragStart" @touchmove.stop.prevent="dragMove"></view> |
| | | <view class="lb" data-drag="bottomLeft" @touchstart.stop="dragStart" @touchmove.stop.prevent="dragMove"></view> --> |
| | | </view> |
| | | </view> |
| | | |
| | | |
| | | <movable-area class="picture-area" :style="{width:areaWidth+'px',height:areaHeight+'px',top:areaHeightTop+'px',left:areaWidthLeft+'px'}"> |
| | | <movable-view class="picture-view" :style="{width:img_width/img_scaling+'px',height:img_height/img_scaling+'px'}" |
| | | direction="all" :x="offsetX" :y="offsetY" scale="true" :scale-min="scaleMin" @change="movableChange" @scale="movableScale"> |
| | | <image :style="{width:img_width/img_scaling+'px',height:img_height/img_scaling+'px'}" :src="pictureSrc"></image> |
| | | </movable-view> |
| | | </movable-area> |
| | | <view class="area-bottom"> |
| | | <view class="area-bottom-box"> |
| | | <view @click="cancelArea">åæ¶</view> |
| | | <!-- <view @click="changeImg">æ¢ä¸ªå¾ç</view> --> |
| | | <view @click="createImg">宿</view> |
| | | </view> |
| | | |
| | | </view> |
| | | <canvas canvas-id="picture-canvas" :style="'position:absolute;border: 1px solid red; width:'+canvasWidth+'px;height:'+canvasHeight+'px;top:-9999px;left:-9999px;'" class="canvas-view"></canvas> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | |
| | | let tailorSize = 240; // éè¦æªåç尺寸240x240pxï¼æ¤åéè¦åæ ·å¼ä¸ç240pxå120pxç¸å¯¹åºï¼120px为æ¤åéçä¸åï¼è¥è¦ä¿®æ¹æå
¶ä»å¼ä¸å®è¦ä¸ä¸å¯¹åº |
| | | let tailorWidth = 0; |
| | | let tailorHeight = 0; |
| | | let newOffsetX = 0; // æå¨ç¼©æ¾å®æåçXè½´åç§»é |
| | | let newOffsetY = 0; // æå¨ç¼©æ¾å®æåçYè½´åç§»é |
| | | let T_PAGE_X, // æç§»å¨çæ¶åxçä½ç½® |
| | | T_PAGE_Y, // æç§»å¨çæ¶åYçä½ç½® |
| | | area_x, |
| | | area_y |
| | | let [choosePictureMinWidth,choosePictureMinHeight] = [50,50]; |
| | | export default { |
| | | name: "tly-picture-cut", |
| | | props: { |
| | | // å¾çè·¯å¾ |
| | | pictureSrc: { |
| | | type: String, |
| | | required: true |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | offsetX: 0, // å¾ååå§åçXè½´åç§»é |
| | | offsetY: 0, // å¾ååå§åçYè½´åç§»é |
| | | img_width: 0, // å¾ççå®å®½åº¦ |
| | | img_height: 0, // å¾ççå®é«åº¦ |
| | | img_scaling: 1, //å¾çåå§åç¼©æ¾æ¯ä¾ |
| | | scale: 1, // æå¨ç¼©æ¾å®æåçå¾çç¼©æ¾æ¯ä¾ |
| | | scaleMin: 0.5, // æå°ç¼©æ¾å¼ |
| | | isShow: false, |
| | | choosePictureWidth:0, |
| | | choosePictureHeight:0, |
| | | choosePictureTop:0, |
| | | choosePictureLeft:0, |
| | | chooseVisible:0.5, |
| | | areaWidth:0, |
| | | areaHeight:0, |
| | | movableViewTop:0, |
| | | movableViewLeft:0, |
| | | areaWidthLeft:0, |
| | | areaHeightTop:0, |
| | | canvasWidth:0, |
| | | canvasHeight:0, |
| | | |
| | | }; |
| | | }, |
| | | watch: { |
| | | pictureSrc() { |
| | | this.getImgInfo(); |
| | | } |
| | | }, |
| | | methods: { |
| | | changeImg(){ |
| | | this.$emit('changeImg') |
| | | }, |
| | | cancelArea(){ |
| | | this.hidePop(); |
| | | }, |
| | | // 设置大å°çæ¶å触åçtouchStartäºä»¶ |
| | | dragStart(e) { |
| | | T_PAGE_X = e.touches[0].pageX |
| | | T_PAGE_Y = e.touches[0].pageY |
| | | }, |
| | | |
| | | // 设置大å°çæ¶å触åçtouchMoveäºä»¶ |
| | | dragMove(e) { |
| | | var _this = this |
| | | var dragType = e.target.dataset.drag |
| | | var dragLengthX = (T_PAGE_X - e.touches[0].pageX); |
| | | var dragLengthY = (T_PAGE_Y - e.touches[0].pageY); |
| | | switch (dragType) { |
| | | case 'leftTop': |
| | | this.choosePictureWidth += dragLengthX; |
| | | this.choosePictureLeft -= dragLengthX; |
| | | this.choosePictureTop -= dragLengthY; |
| | | this.choosePictureHeight += dragLengthY; |
| | | this.canvasY -= dragLengthY |
| | | this.canvasX -= dragLengthX |
| | | break; |
| | | case 'topTight': |
| | | this.choosePictureWidth -= dragLengthX; |
| | | this.choosePictureHeight += dragLengthY; |
| | | this.choosePictureTop -= dragLengthY; |
| | | this.canvasY -= dragLengthY |
| | | break; |
| | | case 'bottomLeft': |
| | | this.choosePictureWidth += dragLengthX; |
| | | this.choosePictureLeft -= dragLengthX; |
| | | this.choosePictureHeight -= dragLengthY; |
| | | this.canvasX -= dragLengthX |
| | | |
| | | break; |
| | | case 'rightBottom': |
| | | this.choosePictureWidth -= dragLengthX; |
| | | this.choosePictureHeight -= dragLengthY; |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | T_PAGE_Y -= dragLengthY; |
| | | T_PAGE_X -= dragLengthX; |
| | | }, |
| | | // æ¾ç¤ºç»ä»¶ |
| | | showPop() { |
| | | this.isShow = true; |
| | | }, |
| | | // éèç»ä»¶ |
| | | hidePop() { |
| | | this.isShow = false; |
| | | }, |
| | | // åå§åå¾ç |
| | | getImgInfo() { |
| | | uni.getImageInfo({ |
| | | src: this.pictureSrc, |
| | | success: (res) => { |
| | | |
| | | // å±å¹å¯ç¨å®½é« |
| | | let sysInfo = uni.getSystemInfoSync(); |
| | | let windowWidth = sysInfo.windowWidth; |
| | | let windowHeight = sysInfo.windowHeight; |
| | | // å¾çå®½é« |
| | | // çæ¯ç¼©æ¾ |
| | | this.img_width = windowWidth*0.8; |
| | | this.img_height = res.height*(this.img_width/res.width); |
| | | this.canvasWidth = this.img_width; |
| | | this.canvasHeight = this.img_height; |
| | | //æªå¾å®½ |
| | | this.choosePictureWidth = this.img_width*this.chooseVisible; |
| | | //æªå¾é« |
| | | this.choosePictureHeight = this.img_height*this.chooseVisible; |
| | | |
| | | this.canvasX = (this.img_width - this.choosePictureWidth) /2; |
| | | this.canvasY = (this.img_height - this.choosePictureHeight) /2; |
| | | area_x = this.canvasX ; |
| | | area_y = this.canvasY ; |
| | | this.choosePictureTop = windowHeight/2-this.choosePictureHeight/2; |
| | | this.choosePictureLeft = windowWidth/2-this.choosePictureWidth/2; |
| | | // 计ç®åå§ç¼©æ¾æ¯åæå°ç¼©æ¾å¼ |
| | | if (this.img_width < this.choosePictureWidth || this.img_height < this.choosePictureHeight) { // å½å¾ç宽æé«å°äº240pxæ¶ |
| | | let count = this.img_width <= this.img_height ? this.img_width : this.img_height; |
| | | let check = this.choosePictureWidth <= this.choosePictureHeight ? this.choosePictureWidth : this.choosePictureHeight; |
| | | this.img_scaling = count / check; |
| | | this.scaleMin = 1; |
| | | } else if (this.img_width > windowWidth && this.img_width <= this.img_height) { // å½å¾ç宽度大äºå±å¹å®½åº¦å¹¶ä¸å¾ç宽度å°äºå¾çé«åº¦æ¶ |
| | | this.img_scaling = this.img_width / windowWidth; |
| | | this.scaleMin = tailorSize / windowWidth; |
| | | } else { |
| | | this.img_scaling = 1; |
| | | //this.img_scaling = count / check; |
| | | let count = this.img_width <= this.img_height ? this.img_width : this.img_height; |
| | | let check = this.choosePictureWidth <= this.choosePictureHeight ? this.choosePictureWidth : this.choosePictureHeight; |
| | | this.scaleMin = check / count; |
| | | } |
| | | //å¤åå®½é« |
| | | this.areaWidth = this.choosePictureWidth*3; |
| | | this.areaHeight = this.choosePictureHeight*3; |
| | | //å¤ååç§»é |
| | | this.areaHeightTop = -((this.areaHeight - windowHeight)/2); |
| | | this.areaWidthLeft = -((this.areaWidth - windowWidth)/2); |
| | | |
| | | this.offsetX = this.areaWidth/2-(this.img_width/this.img_scaling)/2; |
| | | this.offsetY = this.areaHeight/2-(this.img_height/this.img_scaling)/2; |
| | | |
| | | // è·åæ°çåç§»é |
| | | newOffsetX = this.offsetX; |
| | | newOffsetY = this.offsetY; |
| | | } |
| | | }) |
| | | }, |
| | | // è®¡ç®æå¨åç§»é |
| | | movableChange(e) { |
| | | |
| | | this.canvasX = this.canvasX-(e.detail.x-area_x); |
| | | area_x = e.detail.x; |
| | | this.canvasY = this.canvasY-(e.detail.y-area_y) |
| | | if(this.canvasY<0){ |
| | | this.canvasY = 0; |
| | | } |
| | | area_y = e.detail.y; |
| | | |
| | | }, |
| | | // 计ç®ç¼©æ¾æ¯ä¾ååç§»é |
| | | movableScale(e) { |
| | | newOffsetX = e.detail.x |
| | | newOffsetY = e.detail.y |
| | | this.canvasWidth = this.canvasWidth*e.detail.scale; |
| | | this.canvasHeight = this.canvasHeight*e.detail.scale; |
| | | this.scale = e.detail.scale; |
| | | }, |
| | | // æªåå¾ç |
| | | createImg() { |
| | | var that = this; |
| | | let ctx = uni.createCanvasContext("picture-canvas",this); |
| | | ctx.drawImage(this.pictureSrc, 0, 0, this.img_width*this.scale,this.img_height*this.scale ); |
| | | // ctx.draw(); |
| | | ctx.draw(false, () => { |
| | | |
| | | uni.canvasToTempFilePath({ |
| | | x: this.canvasX, |
| | | y: this.canvasY, |
| | | width: this.choosePictureWidth, |
| | | height: this.choosePictureHeight, |
| | | destWidth: this.choosePictureWidth, |
| | | destHeight: this.choosePictureHeight, |
| | | quality: 0.9, |
| | | canvasId: 'picture-canvas', |
| | | success: function (res) { |
| | | |
| | | //#ifdef H5 |
| | | that.hidePop(); |
| | | that.$emit("createImg",res.tempFilePath) |
| | | //#endif |
| | | //#ifdef MP-WEIXIN || APP |
| | | uni.getFileSystemManager().readFile({ |
| | | filePath: res.tempFilePath, |
| | | encoding: 'base64', |
| | | success: res => { |
| | | let base64 = 'data:image/png;base64,' + res.data; |
| | | |
| | | that.hidePop(); |
| | | that.$emit("createImg",base64) |
| | | } |
| | | }) |
| | | //#endif |
| | | |
| | | |
| | | } |
| | | },this); |
| | | |
| | | |
| | | |
| | | }); |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style> |
| | | .picture-cut { |
| | | position: fixed; |
| | | top: 0; |
| | | left: 0; |
| | | bottom: 0; |
| | | right: 0; |
| | | width: 100%; |
| | | height: 100%; |
| | | |
| | | z-index: 999999; |
| | | |
| | | transform: translateX(100%); |
| | | transition: all 200ms ease; |
| | | visibility: hidden; |
| | | } |
| | | |
| | | .picture-cut-show { |
| | | transform: translateY(0) !important; |
| | | visibility: visible; |
| | | |
| | | |
| | | } |
| | | |
| | | /* æå¨åçä½ç½®åå¤§å° */ |
| | | .picture-cut .picture-area { |
| | | |
| | | position: absolute; |
| | | /* 使å
¶å±
ä¸å®ä½ */ |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | /* æå¨æ§ä»¶çå¤§å° */ |
| | | .picture-area { |
| | | |
| | | pointer-events: none; |
| | | z-index: 998; |
| | | |
| | | } |
| | | |
| | | .picture-view { |
| | | |
| | | pointer-events: auto; |
| | | |
| | | } |
| | | |
| | | /* ä¸é´éæ©æ¡ç大å°ï¼æ¬ææ¯è§è§ä¸æ¨¡ææå¨å */ |
| | | .select-box { |
| | | |
| | | position: absolute; |
| | | /* top: calc(50% - 120px); |
| | | left: calc(50% - 120px); */ |
| | | /* width: 240px; |
| | | height: 240px; */ |
| | | box-sizing: border-box; |
| | | /* border-radius: 50%; */ |
| | | |
| | | |
| | | box-shadow: 0px 0px 0px 2005px rgba(0, 0, 0, 0.7) ; |
| | | z-index: 999; |
| | | pointer-events: none; |
| | | /* min-width: 50px; |
| | | min-height: 50px; */ |
| | | } |
| | | .horn{ |
| | | position: absolute; |
| | | width: 100%; |
| | | height: 100%; |
| | | /* border:1rpx solid #ff0000; */ |
| | | |
| | | } |
| | | .horn>view{ |
| | | width: 15px; |
| | | height: 15px; |
| | | position:absolute; |
| | | } |
| | | .horn .lt{ |
| | | pointer-events: auto; |
| | | /* border-top: 3px solid #ff0000; |
| | | border-left: 3px solid #ff0000; */ |
| | | left: -4px; |
| | | top: -4px; |
| | | } |
| | | .horn .rt{ |
| | | pointer-events: auto; |
| | | /* border-top: 3px solid #ff0000; |
| | | border-right: 3px solid #ff0000; */ |
| | | right: -2px; |
| | | top: -2px; |
| | | } |
| | | .horn .rb{ |
| | | pointer-events: auto; |
| | | /* border-bottom:3px solid #ff0000; |
| | | border-right: 3px solid #ff0000; */ |
| | | right: -2px; |
| | | bottom: -2px; |
| | | } |
| | | .horn .lb{ |
| | | pointer-events: auto; |
| | | /* border-bottom:3px solid #ff0000; |
| | | border-left: 3px solid #ff0000; */ |
| | | left: -2px; |
| | | bottom: -2px; |
| | | } |
| | | .area-bottom{ |
| | | position: absolute; |
| | | width:100%; |
| | | height:75px; |
| | | |
| | | bottom: 0; |
| | | z-index:999; |
| | | box-shadow: 0 -8px 12px -5px #ffffff; |
| | | background-color: rgba(66, 66, 66, 0.4); |
| | | } |
| | | .area-bottom-box{ |
| | | |
| | | display: flex; |
| | | justify-content: space-between; |
| | | width:86%; |
| | | height:50px; |
| | | line-height: 60px; |
| | | color:#FFFFFF; |
| | | margin:0 auto; |
| | | } |
| | | .button-view { |
| | | position: absolute; |
| | | bottom: 20px; |
| | | right: 20px; |
| | | width: 60px; |
| | | background-color: #007AFF; |
| | | font-size: 14px; |
| | | color: #FFFFFF; |
| | | z-index:101; |
| | | } |
| | | |
| | | /* ç»å¸å¤§å°ï¼ç»å¸å¤§å°å°±æ¯æªåçåå§å¤§å° */ |
| | | .canvas-view { |
| | | position: absolute; |
| | | /* visibility: hidden; */ |
| | | } |
| | | </style> |
| | |
| | | |
| | | // Vue.prototype.$baseUrl = 'http://192.168.0.186:10027/'; |
| | | // Vue.prototype.$baseUrl = 'https://dmtest.ahapp.net/h5_api/'; |
| | | Vue.prototype.$baseUrl = 'http://218.23.218.228:8018/web_interface/'; |
| | | Vue.prototype.$baseUrl = 'http://facepay.huasunsolar.com/web_interface/'; |
| | | Vue.prototype.$store = store; |
| | | |
| | | App.mpType = 'app' |
| | |
| | | { |
| | | "id": "stephenzhou-picker", |
| | | "name": "æ¯æå页Picker", |
| | | "displayName": "æ¯æå页Picker", |
| | | "version": "1.0", |
| | | "description": "Popupå¼¹åºæ¡ï¼å¯æ»å¨åé¡µï¼æ¯æåéãå¤éåè½çpickerçéç»ä»¶", |
| | | "id": "tly-picture-cut", |
| | | "name": "å¾çè£åª åè§æå¨ å¾ç缩æ¾ç§»å¨", |
| | | "displayName": "å¾çè£åª åè§æå¨ å¾ç缩æ¾ç§»å¨", |
| | | "version": "1.0.0", |
| | | "description": "å¾çè£åªç»ä»¶ æ¯ææå¨åè§ å·²ä½¿ç¨å¾®ä¿¡å°ç¨åºãH5 å¹³å°", |
| | | "keywords": [ |
| | | "çé", |
| | | "å页", |
| | | "æç´¢", |
| | | "å¤é", |
| | | "åé" |
| | | "å¾çè£åª" |
| | | ], |
| | | "dcloudext": { |
| | | "category": [ |
| | | "å端ç»ä»¶", |
| | | "éç¨ç»ä»¶" |
| | | ] |
| | | }, |
| | | "dependencies": { |
| | | "qrcodejs2": "0.0.2", |
| | | "uniapp-qrcode": "^1.0.2" |
| | | } |
| | | } |
| | | } |
| | |
| | | <view class="footer-box"> |
| | | <view class="submit-button" @click="submit">ä¸ä¸æ¥</view> |
| | | </view> |
| | | <u-picker keyName="name" :show="show" :columns="columns" @confirm="confirm" @cancel="show = false"></u-picker> |
| | | <!-- <tly-picture-cut ref="tlyPictureCut" :pictureSrc="photoSrc" @createImg="uploadImg"></tly-picture-cut> --> |
| | | <u-picker :show="show" :columns="columns" keyName="name" @cancel="show = false" @confirm="confirm"></u-picker> |
| | | <qf-image-cropper ref="cropper" :width="280" :height="280" :radius="30" @crop="uploadImg"></qf-image-cropper> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | import tlyPictureCut from "@/components/tly-picture-cut/tlyPictureCut.vue"; |
| | | import QfImageCropper from '@/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.vue'; |
| | | import { mapState } from 'vuex' |
| | | export default { |
| | | data() { |
| | | return { |
| | | photoSrc: "", |
| | | show: false, |
| | | visit: '', |
| | | type: '', |
| | |
| | | faceImg: '', |
| | | faceImgUrl: '', |
| | | imgurl: '', |
| | | imgurlUrl: '' |
| | | imgurlUrl: '', |
| | | companyName: '' |
| | | } |
| | | } |
| | | }, |
| | | |
| | | computed: { |
| | | ...mapState(['member']) |
| | | }, |
| | | |
| | | components: { tlyPictureCut, QfImageCropper }, |
| | | |
| | | onLoad(option) { |
| | | if (this.member) { |
| | | this.visitorData.name = this.member.name |
| | | this.visitorData.phone = this.member.phone |
| | | this.visitorData.idcardNo = this.member.idcardDecode |
| | | this.visitorData.companyName = this.member.visitCompanyName |
| | | this.visitorData.faceImg = this.member.faceImg |
| | | if (this.member.faceImg) { |
| | | this.visitorData.faceImgUrl = this.member.prefixUrl + this.member.faceImg |
| | | } |
| | | this.visitorData.imgurl = this.member.imgurl |
| | | if (this.member.imgurl) { |
| | | this.visitorData.imgurlUrl = this.member.prefixUrl + this.member.imgurl |
| | | } |
| | | this.visitorData.idcardType = this.member.idcardType |
| | | if (this.member.idcardType === 0) { |
| | | this.visitorData.idcardTypeName = '身份è¯' |
| | | } else if (this.member.idcardType === 1) { |
| | | this.visitorData.idcardTypeName = '港澳è¯ä»¶' |
| | | } else if (this.member.idcardType === 2) { |
| | | this.visitorData.idcardTypeName = 'æ¤ç
§' |
| | | } |
| | | } |
| | | this.visitorData.userAnswerId = option.userAnswerId |
| | | this.getVisit() |
| | | uni.$on('update', (data) => { |
| | | this.uploadImg(data.tempFilePath) |
| | | }) |
| | | // uni.$on('update', (data) => { |
| | | // this.uploadImg(data.tempFilePath) |
| | | // }) |
| | | }, |
| | | |
| | | methods: { |
| | |
| | | }) |
| | | }, |
| | | uploadImg(file) { |
| | | var that = this |
| | | that.$refs.cropper.close() |
| | | uni.showLoading({ title: 'ä¸ä¼ ä¸', mask: true }); |
| | | uni.uploadFile({ |
| | | url: `${this.$baseUrl}public/api/uploadFtp.do`, |
| | | filePath: file, |
| | | filePath: file.tempFilePath, |
| | | name: 'file', |
| | | formData: { |
| | | folderCode: 'MEMBER_IMG' |
| | | }, |
| | | success: (uploadFileRes) => { |
| | | let res = JSON.parse(uploadFileRes.data) |
| | | if (this.type === 'faceImg') { |
| | | this.visitorData.faceImg = res.data.halfPath |
| | | this.visitorData.faceImgUrl = res.data.prefixPath + res.data.folder + res.data.halfPath |
| | | } else { |
| | | this.visitorData.imgurl = res.data.halfPath |
| | | this.visitorData.imgurlUrl = res.data.prefixPath + res.data.folder + res.data.halfPath |
| | | } |
| | | this.visitorData.faceImg = res.data.halfPath |
| | | this.visitorData.faceImgUrl = res.data.prefixPath + res.data.folder + res.data.halfPath |
| | | }, |
| | | fail(err) { |
| | | alert('失败') |
| | | }, |
| | | complete() { |
| | | uni.hideLoading(); |
| | |
| | | }); |
| | | }, |
| | | upload(type) { |
| | | this.type = type |
| | | var that = this |
| | | that.type = type |
| | | if (type === 'faceImg') { |
| | | that.$refs.cropper.open() |
| | | return |
| | | } |
| | | uni.chooseImage({ |
| | | count: 1, |
| | | success: (chooseImageRes) => { |
| | | if (type === 'faceImg') { |
| | | uni.navigateTo({ |
| | | url: `/pages/cropping/cropping?item=${JSON.stringify({ tempFilePath: chooseImageRes.tempFilePaths[0] })}` |
| | | }) |
| | | return |
| | | } |
| | | uni.showLoading({ title: 'ä¸ä¼ ä¸', mask: true }); |
| | | for (let i = 0; i < chooseImageRes.tempFilePaths.length; i++) { |
| | | // if (type === 'faceImg') { |
| | | // that.photoSrc = chooseImageRes.tempFilePaths[0]; |
| | | // that.$refs.tlyPictureCut.showPop(); |
| | | // } |
| | | if (type === 'imgurl') { |
| | | uni.showLoading({ title: 'ä¸ä¼ ä¸', mask: true }); |
| | | uni.uploadFile({ |
| | | url: `${this.$baseUrl}public/api/uploadFtp.do`, |
| | | filePath: chooseImageRes.tempFilePaths[i], |
| | | url: `${that.$baseUrl}public/api/uploadFtp.do`, |
| | | filePath: chooseImageRes.tempFilePaths[0], |
| | | name: 'file', |
| | | formData: { |
| | | folderCode: 'MEMBER_IMG' |
| | | }, |
| | | success: (uploadFileRes) => { |
| | | timeout: 60000, |
| | | success: (uploadFileRes) => { |
| | | let res = JSON.parse(uploadFileRes.data) |
| | | if (type === 'faceImg') { |
| | | this.visitorData.faceImg = res.data.halfPath |
| | | this.visitorData.faceImgUrl = res.data.prefixPath + res.data.folder + res.data.halfPath |
| | | } else { |
| | | this.visitorData.imgurl = res.data.halfPath |
| | | this.visitorData.imgurlUrl = res.data.prefixPath + res.data.folder + res.data.halfPath |
| | | } |
| | | that.visitorData.imgurl = res.data.halfPath |
| | | that.visitorData.imgurlUrl = res.data.prefixPath + res.data.folder + res.data.halfPath |
| | | }, |
| | | complete() { |
| | | if (i === chooseImageRes.tempFilePaths.length - 1) { |
| | | uni.hideLoading(); |
| | | } |
| | | uni.hideLoading(); |
| | | } |
| | | }); |
| | | } |
| | | }, |
| | | fail(err) { |
| | | alert('apiæ¥é') |
| | | } |
| | | }); |
| | | }, |
| | |
| | | } |
| | | </script> |
| | | |
| | | <style> |
| | | <style lang="scss"> |
| | | page { |
| | | background-color: #F7F7F7 !important; |
| | | } |
| | |
| | | display: flex; |
| | | flex-direction: column; |
| | | .title1_a { |
| | | font-size: 30rpx; |
| | | font-size: 30rpx !important; |
| | | font-weight: 400; |
| | | color: #222222; |
| | | display: flex; |
| | |
| | | } |
| | | } |
| | | .title1_b { |
| | | font-size: 24rpx; |
| | | font-size: 24rpx !important; |
| | | font-weight: 400; |
| | | color: #999999; |
| | | } |
| | |
| | | <text>访é®é¨ç¦</text> |
| | | <text>*</text> |
| | | </view> |
| | | <!-- @click="show6 = true" --> |
| | | <view class="list_item_content"> |
| | | <text :style="{color: form1.doorSelectName ? '#000000' : ''}">{{form1.doorSelectName ? form1.doorSelectName : 'è¯·éæ©'}}</text> |
| | | <u-icon name="arrow-right" color="#CCCCCC" size="20"></u-icon> |
| | |
| | | <text>éè¡è½¦è¾</text> |
| | | <text></text> |
| | | </view> |
| | | <view class="list_item_content"> |
| | | <input type="text" placeholder="请è¾å
¥è½¦çå·" v-model="form1.carNos" maxlength="8" placeholder-style="color: #999999;" /> |
| | | <view class="list_item_content" @click="openInput(1)"> |
| | | <text :style="{color: form1.carNos ? '#000000' : ''}">{{form1.carNos ? form1.carNos : '请è¾å
¥è½¦çå·ç '}}</text> |
| | | <!-- <input type="text" placeholder="请è¾å
¥è½¦çå·" v-model="form1.carNos" maxlength="8" placeholder-style="color: #999999;" /> --> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | <view class="adduser_list_item"> |
| | | <view class="adduser_list_item_label"> |
| | | <text>å
¬å¸</text> |
| | | <text></text> |
| | | <text>*</text> |
| | | </view> |
| | | <view class="adduser_list_item_ipt"> |
| | | <input type="text" v-model="withUserList.companyName" placeholder-style="color: #999999;font-size: 28rpx;" placeholder="请è¾å
¥å
¬å¸åç§°" /> |
| | |
| | | <text>éè¡è½¦è¾</text> |
| | | <text></text> |
| | | </view> |
| | | <view class="adduser_list_item_ipt"> |
| | | <input type="text" v-model="withUserList.carNos" placeholder-style="color: #999999;font-size: 28rpx;" placeholder="请è¾å
¥è½¦çå·" /> |
| | | <view class="adduser_list_item_ipt" @click="openInput(2)"> |
| | | <text :style="{color: withUserList.carNos ? '#000000' : ''}">{{withUserList.carNos ? withUserList.carNos : '请è¾å
¥è½¦çå·ç '}}</text> |
| | | <!-- <input type="text" v-model="withUserList.carNos" disabled placeholder-style="color: #999999;font-size: 28rpx;" placeholder="请è¾å
¥è½¦çå·" /> --> |
| | | </view> |
| | | </view> |
| | | <view class="adduser_list_item"> |
| | |
| | | </view> |
| | | </u-popup> |
| | | <u-picker keyName="name" :show="show6" :columns="columns1" @confirm="seleIdcard" @cancel="show6 = false"></u-picker> |
| | | <!-- <tly-picture-cut ref="tlyPictureCut" :pictureSrc="photoSrc" @createImg="uploadImg"></tly-picture-cut> --> |
| | | <keyboardInput ref="keyboard" @export="setPlate" @close="closeInput" /> |
| | | <qf-image-cropper ref="cropper" :width="280" :height="280" :radius="30" @crop="uploadImg"></qf-image-cropper> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | import tlyPictureCut from "@/components/tly-picture-cut/tlyPictureCut.vue"; |
| | | import keyboardInput from "@/components/keyboard-input/keyboard-input.vue"; |
| | | import QfImageCropper from '@/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.vue'; |
| | | export default { |
| | | data() { |
| | | return { |
| | | photoSrc: '', |
| | | type: '', |
| | | inputType: '', |
| | | show: false, |
| | | show1: false, |
| | | show2: false, |
| | |
| | | show4: false, |
| | | show5: false, |
| | | show6: false, |
| | | show7: false, |
| | | fileList: [], |
| | | columns1: [[{name: '身份è¯', id: 0}, {name: '港澳è¯ä»¶', id: 1},{name: 'æ¤ç
§', id: 2}]], |
| | | columns: [], |
| | |
| | | verify: '' |
| | | }; |
| | | }, |
| | | components: { tlyPictureCut, keyboardInput, QfImageCropper }, |
| | | onLoad(options) { |
| | | this.form = JSON.parse(options.data) |
| | | if (options.data) { |
| | | this.form = JSON.parse(options.data) |
| | | } |
| | | this.getvisit() |
| | | this.getVisit1() |
| | | this.getUserValid() |
| | | }, |
| | | methods: { |
| | | openInput(type) { |
| | | this.inputType = type |
| | | this.$refs.keyboard.open() |
| | | }, |
| | | setPlate(e) { |
| | | if (this.inputType === 1) { |
| | | this.form1.carNos = e |
| | | } else if (this.inputType === 2) { |
| | | this.withUserList.carNos = e |
| | | } |
| | | this.$forceUpdate() |
| | | this.closeInput() |
| | | }, |
| | | closeInput() { |
| | | this.$refs.keyboard.close() |
| | | }, |
| | | uploadImg(file) { |
| | | this.$refs.cropper.close() |
| | | uni.showLoading({ title: 'ä¸ä¼ ä¸', mask: true }); |
| | | uni.uploadFile({ |
| | | url: `${this.$baseUrl}public/api/uploadFtp.do`, |
| | | filePath: file.tempFilePath, |
| | | name: 'file', |
| | | formData: { |
| | | folderCode: 'MEMBER_IMG' |
| | | }, |
| | | success: (uploadFileRes) => { |
| | | let res = JSON.parse(uploadFileRes.data) |
| | | this.withUserList.faceImg = res.data.halfPath |
| | | this.withUserList.faceImgUrl = res.data.prefixPath + res.data.folder + res.data.halfPath |
| | | }, |
| | | complete() { |
| | | uni.hideLoading(); |
| | | } |
| | | }); |
| | | }, |
| | | closeMJ() { |
| | | this.show = false |
| | | this.columns.forEach(item => { |
| | |
| | | title: 'ç¦»åºæ¶é´ä¸è½ä¸ºç©º', |
| | | icon: 'none' |
| | | }) |
| | | if (!this.form1.doorSelectName) return uni.showToast({ |
| | | if (!this.form1.doorSelectName && this.accessControl == 1) return uni.showToast({ |
| | | title: '访é®é¨ç¦ä¸è½ä¸ºç©º', |
| | | icon: 'none' |
| | | }) |
| | |
| | | withUserList: this.personnel |
| | | }).then(res => { |
| | | if (res.code === 200) { |
| | | console.log(res) |
| | | uni.reLaunch({ |
| | | url: `/pages/appointmentDetails/appointmentDetails?id=${res.data}` |
| | | }) |
| | |
| | | icon: 'none' |
| | | }) |
| | | } |
| | | if (!this.withUserList.companyName) return uni.showToast({ |
| | | title: 'å
¬å¸ä¸è½ä¸ºç©º', |
| | | icon: 'none' |
| | | }) |
| | | if (!this.withUserList.faceImg) return uni.showToast({ |
| | | title: '人è¸ç
§çä¸è½ä¸ºç©º', |
| | | icon: 'none' |
| | |
| | | this.withUserList.imgurlUrl = '' |
| | | }, |
| | | upload(type) { |
| | | this.type = type |
| | | if (type === 'faceImg') { |
| | | this.$refs.cropper.open() |
| | | return |
| | | } |
| | | uni.chooseImage({ |
| | | success: (chooseImageRes) => { |
| | | // if (type === 'faceImg') { |
| | | // this.photoSrc = chooseImageRes.tempFilePaths[0]; |
| | | // this.$refs.tlyPictureCut.showPop(); |
| | | // return |
| | | // } |
| | | uni.showLoading({ title: 'ä¸ä¼ ä¸', mask: true }); |
| | | for (let i = 0; i < chooseImageRes.tempFilePaths.length; i++) { |
| | | uni.uploadFile({ |
| | |
| | | }, |
| | | // æ¥è¯¢ç¨æ· |
| | | getUser() { |
| | | console.log(this.verify) |
| | | console.log(this.form1.phone1) |
| | | console.log(this.form1.receptMemberName) |
| | | if (this.verify === '0') { |
| | | if (this.form1.phone1) { |
| | | this.$u.api.getVisitedMember({ |
| | |
| | | label: 'BEVISITED_USER_VALID' |
| | | }).then(res => { |
| | | if (res.code === 200) { |
| | | console.log(res) |
| | | this.verify = res.data.code |
| | | } |
| | | }) |
| | |
| | | <script> |
| | | var p = location.href.split("?") |
| | | // window.location.href = 'https://dmtest.ahapp.net/hsvisit_h5/#/pages/notice/notice?' + p[1] |
| | | window.location.href = 'http://218.23.218.228:8018/h5/#/pages/notice/notice?' + p[1] |
| | | window.location.href = 'http://facepay.huasunsolar.com/h5/#/pages/notice/notice?' + p[1] |
| | | </script> |
| | | </head> |
| | | <body> |
| | |
| | | Vue.use(Vuex) |
| | | |
| | | const openId = uni.getStorageSync('openId'); |
| | | const member = uni.getStorageSync('member'); |
| | | |
| | | const store = new Vuex.Store({ |
| | | |
| | | state: { |
| | | openId: openId || '' |
| | | openId: openId || '', |
| | | member: member || null |
| | | }, |
| | | |
| | | mutations: { |
| | | // 设置åå¸ |
| | | // 设置openId |
| | | setOpenId(state, val) { |
| | | state.openId = val |
| | | uni.setStorageSync('openId', val); |
| | | }, |
| | | // è®¾ç½®ç¨æ·ä¿¡æ¯ |
| | | setMember(state, val) { |
| | | state.member = val |
| | | uni.setStorageSync('member', val); |
| | | } |
| | | } |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | ## 3.0.2ï¼2023-06-06ï¼ |
| | | æ´æ°äºææ¡£ |
| | | |
| | | ## 3.0.1ï¼2022-11-03ï¼ |
| | | ä¿®å¤ æ¤éåéåä¸çæçé®é¢ |
| | | ## 3.0.0ï¼2022-11-03ï¼ |
| | | 使ç¨wxséæä»£ç ï¼æ§è½å¤§æå |
| | | æ°å¢ æ¯æèçè£åªï¼å¯ä»¥è£åªä»»ä½å½¢ç¶çå¾å½¢ï¼è¯¦æ
è§demo示ä¾ï¼ |
| | | æ°å¢ æ¯æå¨å¼¹çªä¸ä½¿ç¨ï¼è¯¦æ
è§demo示ä¾ï¼ |
| | | ç§»é¤ ç±äºææ§½ä¼å¯¼è´è®¸å¤é®é¢ï¼å®é
ä¸å¼åè
èªå·±å°è£
ç»ä»¶åèæ´ç®åï¼æä»¥3.0çæ¬ä»¥åç§»é¤ææ§½ï¼2.0è¿ç§»æç¨è§ demo:å
¨å±è£åª |
| | | ## 2.0.3ï¼2022-08-21ï¼ |
| | | ä¿®å¤ å¨vue3 ç¨åºä¸æ¥éçé®é¢ |
| | | æ°å¢ æ°å¢äºå¾çåå§å宿åå 载失败çäºä»¶ |
| | | ## 2.0.2ï¼2022-08-18ï¼ |
| | | æ°å¢ å¢å äºååç´ è£åªåè½ï¼å³ä½¿ç¨ç¨æ·å¨è£åªæ¡åæ¯ç大å°ä½ä¸ºè¾åºåç´ ï¼æ¢å¥è¯è¯´ï¼è¾åºçå¾çå辨çä¸è¾å
¥å¾çå辨ç䏿 · |
| | | æ°å¢ å¢å äºchangeäºä»¶ï¼ä¼å¨å¾ååè£åªæ¡ä½ç½®ååå触å |
| | | æ°å¢ å¢å äºcompressåæ° å缩å¾çï¼å缩å¾çæ¯ä¸ºäºæåæµç
åº¦ï¼æä»¥åªä¼éå¯¹ç¨æ·æå¨çé£å¼ å¾çè¿è¡åç¼©ï¼æç»è¾åºçå¾åå质并ä¸ä¼åå°å½±å |
| | | ä¿®å¤ ç¨æ·å¨æ²¡æä¼ å
¥å¾åæ¶æ¥éçé®é¢ |
| | | ä¿®å¤ ioså¨æäºæºå䏿å¨åºç°æ®ççé®é¢ |
| | | ## 2.0.1ï¼2022-07-20ï¼ |
| | | ä¿®å¤ï¼iosæå
æappçæ¶åæå çè£åªä¸æåçé®é¢ |
| | | ## 2.0.0ï¼2022-07-13ï¼ |
| | | æ´æ°äº2.0çæ¬ï¼å¢å äºå¾çæ¾å¤§åè½ |
| | | ## bt-cropper å¾çè£å |
| | | ======== |
| | | ### 2022å¹´7æ13æ¥ åå¸2.0çæ¬ |
| | | * 1.å®å
¨éæäºä»£ç ï¼å¹¶ä¸ä¼åäºæ§è½ |
| | | * 2.æ¯æapp |
| | | * 3.ä¿®å¤demoå¨H5çæ
åµä¸é«åº¦é误çé®é¢ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="bt-container" :style="[containerStyle]"> |
| | | <!-- #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 --> |
| | | <view class="mainContent" data-type="image" @touchstart="wxsModule.touchStart" @touchmove="wxsModule.touchMove" @touchend="wxsModule.touchEnd"> |
| | | <!-- #endif --> |
| | | <!-- #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 --> |
| | | <view class="mainContent" data-type="image" @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd"> |
| | | <!-- #endif --> |
| | | <template v-if="imageRect && cropperRect"> |
| | | <!-- #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 --> |
| | | <image mode="aspectFit" :src="imageSrc" class="image" :rotateAngle="rotateAngle" :change:rotateAngle="wxsModule.changeRotateAngle" :change:imageRect="wxsModule.changeImageRect" :imageRect="imageRect" :class="{ anim }"> |
| | | <!-- #endif --> |
| | | <!-- #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 --> |
| | | <image mode="aspectFit" :src="imageSrc" class="image" :style="[imageStyle]" :class="{ anim }"> |
| | | <!-- #endif --> |
| | | </image> |
| | | <!-- #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 --> |
| | | <view class="cropper" :class="{ anim }" :change:cropperRect="wxsModule.changeCropper" :cropperRect="cropperRect" :change:ratio="wxsModule.changeRatio" :ratio="ratio" > |
| | | <!-- #endif --> |
| | | <!-- #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 --> |
| | | <view class="cropper" :class="{ anim }" :style="[cropperStyle]"> |
| | | <!-- #endif --> |
| | | <image class="mask" :src="mask"></image> |
| | | <template v-if="showGrid"> |
| | | <view class="line row row1"></view> |
| | | <view class="line row row2"></view> |
| | | <view class="line col col1"></view> |
| | | <view class="line col col2"></view> |
| | | </template> |
| | | <!-- #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 --> |
| | | <view class="controller vertical left" @touchstart="wxsModule.touchStart" data-type="controller" /> |
| | | <view class="controller vertical right" @touchstart="wxsModule.touchStart" data-type="controller" /> |
| | | <view class="controller horizon top" @touchstart="wxsModule.touchStart" data-type="controller" /> |
| | | <view class="controller horizon bottom" @touchstart="wxsModule.touchStart" data-type="controller" /> |
| | | <view class="controller left top" @touchstart="wxsModule.touchStart" data-type="controller" /> |
| | | <view class="controller left bottom" @touchstart="wxsModule.touchStart" data-type="controller" /> |
| | | <view class="controller right top" @touchstart="wxsModule.touchStart" data-type="controller" /> |
| | | <view class="controller right bottom" @touchstart="wxsModule.touchStart" data-type="controller" /> |
| | | <!-- #endif --> |
| | | <!-- #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 --> |
| | | <view class="controller vertical left" @touchstart.stop="touchStart(-1, 0, $event)" /> |
| | | <view class="controller vertical right" @touchstart.stop="touchStart(1, 0, $event)" /> |
| | | <view class="controller horizon top" @touchstart.stop="touchStart(0, -1, $event)" /> |
| | | <view class="controller horizon bottom" @touchstart.stop="touchStart(0, 1, $event)" /> |
| | | <view class="controller left top" @touchstart.stop="touchStart(-1, -1, $event)" /> |
| | | <view class="controller left bottom" @touchstart.stop="touchStart(-1, 1, $event)" /> |
| | | <view class="controller right top" @touchstart.stop="touchStart(1, -1, $event)" /> |
| | | <view class="controller right bottom" @touchstart.stop="touchStart(1, 1, $event)" /> |
| | | <!-- #endif --> |
| | | </view> |
| | | </template> |
| | | </view> |
| | | <canvas v-if="type2d" type="2d" class="bt-canvas" :width="target.width" :height="target.height"></canvas> |
| | | <canvas |
| | | v-else |
| | | :canvas-id="canvasId" |
| | | class="bt-canvas" |
| | | :style="{ |
| | | width: target.width + 'px', |
| | | height: target.height + 'px' |
| | | }" |
| | | :width="target.width * pixel" |
| | | :height="target.height * pixel" |
| | | ></canvas> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | // #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 |
| | | import touches from './js/touchs.js'; |
| | | // #endif |
| | | import { parseUnit,sleep } from './utils/tools.js'; |
| | | /** |
| | | * better-cropper å¾çè£åæä»¶ |
| | | */ |
| | | export default { |
| | | name: 'bt-cropper', |
| | | props: { |
| | | // å¾çè·¯å¾ï¼æ¯æç½ç»è·¯å¾åæ¬å°è·¯å¾ |
| | | imageSrc: { |
| | | type: String, |
| | | default: '', |
| | | required: true |
| | | }, |
| | | mask: { |
| | | type: String, |
| | | default: '' |
| | | }, |
| | | // æå¨æå®å®¹å¨çå¤§å° |
| | | containerSize: { |
| | | type: Object, |
| | | default: null |
| | | }, |
| | | // è¾åºå¾ççæ ¼å¼ï¼é»è®¤jpg |
| | | fileType: { |
| | | type: String, |
| | | default: 'png' |
| | | }, |
| | | // çæçå¾çç宽度,ä¸ä¼ æè
ä¼ 0表示æç
§åå§å辨çè£å |
| | | dWidth: Number, |
| | | maxWidth: { |
| | | type: Number, |
| | | default: 2000 |
| | | }, |
| | | // è£åæ¯ä¾ï¼0表示èªç± |
| | | ratio: { |
| | | type: Number, |
| | | default: 0, |
| | | validator(value) { |
| | | if (typeof value === 'number') { |
| | | if (value < 0) { |
| | | return false; |
| | | } |
| | | } else { |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
| | | }, |
| | | // æè½¬è§åº¦ |
| | | rotate: Number, |
| | | // æ¯å¦å±ç¤ºç½æ ¼ |
| | | showGrid: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | // å¾çè´¨éï¼0-1 è¶å¤§è´¨éè¶å¥½ |
| | | quality: { |
| | | type: Number, |
| | | default: 1 |
| | | }, |
| | | canvas2d: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | // åå§çå¾çä½ç½® |
| | | initPosition: { |
| | | type: Object, |
| | | default() { |
| | | return null; |
| | | } |
| | | }, |
| | | // æ¯å¦å¼å¯æä½ç»æåèªå¨æ¾å¤§ |
| | | autoZoom: { |
| | | type: Boolean, |
| | | default: true |
| | | } |
| | | }, |
| | | // #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 |
| | | mixins: [touches], |
| | | // #endif |
| | | data() { |
| | | return { |
| | | canvasId: 'bt-cropper', |
| | | containerRect: null, |
| | | imageInfo: null, |
| | | operationHistory: [], |
| | | operationIndex: 0, |
| | | anim: false, |
| | | timer: null, |
| | | // æ¯å¦ä½¿ç¨2D canvas |
| | | type2d: false, |
| | | pixel: 1, |
| | | imageRect: null, |
| | | cropperRect: null, |
| | | target:{ |
| | | width:0, |
| | | height:0 |
| | | } |
| | | }; |
| | | }, |
| | | watch: { |
| | | imageSrc: { |
| | | handler(src) { |
| | | if (typeof src === 'string' && src !== '') { |
| | | this.imageInit(src); |
| | | } else { |
| | | this.imageInfo = null; |
| | | } |
| | | }, |
| | | immediate: true |
| | | }, |
| | | ratio() { |
| | | if (this.ratio != 0) { |
| | | this.startAnim(); |
| | | this.init(); |
| | | } |
| | | } |
| | | }, |
| | | computed: { |
| | | containerStyle() { |
| | | if (this.containerSize && this.containerRect) { |
| | | return { |
| | | width: this.containerRect.width + 'px', |
| | | height: this.containerRect.height + 'px' |
| | | }; |
| | | } |
| | | return {}; |
| | | }, |
| | | rotateAngle(){ |
| | | const angel = Number(this.rotate) |
| | | if(isNaN(angel)){ |
| | | return 0 |
| | | }else{ |
| | | return angel % 360 |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | startAnim() { |
| | | this.stopAnim(); |
| | | this.anim = true; |
| | | this.timer = setTimeout(() => { |
| | | this.anim = false; |
| | | }, 200); |
| | | }, |
| | | stopAnim() { |
| | | this.anim = false; |
| | | clearTimeout(this.timer); |
| | | }, |
| | | imageInit(src) { |
| | | uni.showLoading({ |
| | | title: 'è½½å
¥ä¸...' |
| | | }); |
| | | uni.getImageInfo({ |
| | | src, |
| | | success: res => { |
| | | this.imageInfo = res; |
| | | this.$nextTick(() => { |
| | | this.getContainer().then(rect => { |
| | | this.containerRect = rect; |
| | | this.init(); |
| | | }); |
| | | }); |
| | | }, |
| | | fail: (err) => { |
| | | this.$emit('loadFail',err); |
| | | uni.showToast({ |
| | | title: 'å¾çä¸è½½å¤±è´¥!', |
| | | icon: 'none' |
| | | }); |
| | | }, |
| | | complete(res) { |
| | | uni.hideLoading(); |
| | | } |
| | | }); |
| | | }, |
| | | initCropper() { |
| | | const imageRate = this.imageInfo.width / this.imageInfo.height; |
| | | const containerRate = this.containerRect.width / this.containerRect.height; |
| | | const imageRect = {}; |
| | | let cropperRate = this.ratio; |
| | | if (cropperRate == 0) { |
| | | if (this.cropperRect) { |
| | | cropperRate = this.cropperRect.width / this.cropperRect.height; |
| | | } else { |
| | | cropperRate = 1; |
| | | } |
| | | } |
| | | const cropperRect = {}; |
| | | if (containerRate > cropperRate) { |
| | | cropperRect.height = this.containerRect.height * 0.85; |
| | | cropperRect.width = cropperRect.height * cropperRate; |
| | | } else { |
| | | cropperRect.width = this.containerRect.width * 0.85; |
| | | cropperRect.height = cropperRect.width / cropperRate; |
| | | } |
| | | if (cropperRate > imageRate) { |
| | | imageRect.width = cropperRect.width; |
| | | imageRect.height = imageRect.width / imageRate; |
| | | } else { |
| | | imageRect.height = cropperRect.height; |
| | | imageRect.width = imageRect.height * imageRate; |
| | | } |
| | | imageRect.left = (this.containerRect.width - imageRect.width) / 2; |
| | | imageRect.top = (this.containerRect.height - imageRect.height) / 2; |
| | | cropperRect.left = imageRect.left + (imageRect.width - cropperRect.width) / 2; |
| | | cropperRect.top = imageRect.top + (imageRect.height - cropperRect.height) / 2; |
| | | return { |
| | | imageRect, |
| | | cropperRect |
| | | }; |
| | | }, |
| | | init() { |
| | | const {imageRect,cropperRect} = this.initCropper() |
| | | if(this.initPosition){ |
| | | const scale = this.imageInfo.width/imageRect.width; |
| | | const {left,top,width,height} = this.initPosition; |
| | | if(left!==undefined&&top!==undefined&&width!==undefined&&height!==undefined){ |
| | | cropperRect.width = width/scale; |
| | | cropperRect.height = height/scale; |
| | | cropperRect.left = left/scale; |
| | | cropperRect.top = top/scale; |
| | | this.$nextTick(this.zoomToFill); |
| | | } |
| | | } |
| | | this.imageRect = imageRect |
| | | this.cropperRect = cropperRect |
| | | this.operationHistory = [{imageRect,cropperRect}]; |
| | | this.operationIndex = 0; |
| | | this.setTarget(); |
| | | // #ifdef MP-WEIXIN |
| | | const systemInfo = uni.getSystemInfoSync(); |
| | | if (this.canvas2d === false || systemInfo.platform === 'windows' || systemInfo.platform === 'mac') { |
| | | this.type2d = false; |
| | | } else { |
| | | this.type2d = true; |
| | | this.pixel = systemInfo.pixelRatio; |
| | | } |
| | | // #endif |
| | | //é微信å°ç¨åºç«¯å¼ºå¶å
³écanvas2dæ¨¡å¼ |
| | | // #ifndef MP-WEIXIN |
| | | this.type2d = false; |
| | | // #endif |
| | | // #ifdef MP-TOUTIAO || MP-LARK || MP-ALIPAY |
| | | this.type2d = this.canvas2d; |
| | | // #endif |
| | | }, |
| | | // è®¾ç½®ç®æ å¾åçå¤§å° |
| | | setTarget(){ |
| | | const ratio = this.cropperRect.width / this.cropperRect.height; |
| | | if (!!this.dWidth) { |
| | | this.target = { |
| | | width: this.dWidth, |
| | | height: this.dWidth / (ratio || 1) |
| | | } |
| | | } else { |
| | | const width = Math.min(this.maxWidth, this.cropperRect.width * (this.imageInfo.width / this.imageRect.width)); |
| | | this.target = { |
| | | width, |
| | | height: width / (ratio || 1) |
| | | } |
| | | } |
| | | }, |
| | | addHistory({imageRect,cropperRect}){ |
| | | if(this.operationIndex!==this.operationHistory.length-1){ |
| | | this.operationHistory = this.operationHistory.slice(0,this.operationIndex) |
| | | } |
| | | this.operationHistory.push({ |
| | | imageRect, |
| | | cropperRect |
| | | }); |
| | | if (this.operationHistory.length > 10) { |
| | | this.operationHistory.shift(); |
| | | } |
| | | this.operationIndex = this.operationHistory.length - 1; |
| | | }, |
| | | updateData(data) { |
| | | this.imageRect = data.imageRect |
| | | this.cropperRect = data.cropperRect |
| | | this.addHistory(data); |
| | | this.setTarget(); |
| | | if (this.autoZoom) { |
| | | this.timer = setTimeout(() => { |
| | | this.zoomToFill(); |
| | | }, 600); |
| | | } |
| | | const {imageRect,cropperRect} = data |
| | | const scale = imageRect.width/this.imageInfo.width |
| | | this.$emit('change', { |
| | | left: (cropperRect.left - imageRect.left) /scale, |
| | | top: (cropperRect.top - imageRect.top) / scale, |
| | | width: cropperRect.width / scale, |
| | | height: cropperRect.height / scale |
| | | }); |
| | | }, |
| | | getContainer() { |
| | | if (this.containerSize !== null && typeof this.containerSize == 'object') { |
| | | const { width, height } = this.containerSize; |
| | | return Promise.resolve({ |
| | | width: parseUnit(width), |
| | | height: parseUnit(height) |
| | | }); |
| | | } else { |
| | | return new Promise(resolve => { |
| | | const query = uni.createSelectorQuery().in(this); |
| | | query |
| | | .select('.mainContent') |
| | | .boundingClientRect(rect => { |
| | | resolve(rect); |
| | | }) |
| | | .exec(); |
| | | }); |
| | | } |
| | | }, |
| | | zoomToFill() { |
| | | this.startAnim(); |
| | | const beforeCropper = { |
| | | ...this.cropperRect |
| | | }; |
| | | const operation = { |
| | | imageRect:this.imageRect, |
| | | cropperRect:this.cropperRect |
| | | }; |
| | | this.cropperRect = this.initCropper().cropperRect; |
| | | const scale = this.cropperRect.width / beforeCropper.width; |
| | | const ox = beforeCropper.left - this.imageRect.left; |
| | | const oy = beforeCropper.top - this.imageRect.top; |
| | | this.imageRect = { |
| | | width: this.imageRect.width * scale, |
| | | height: this.imageRect.height * scale, |
| | | left: this.imageRect.left + (this.cropperRect.left - beforeCropper.left) - (scale - 1) * ox, |
| | | top: this.imageRect.top + (this.cropperRect.top - beforeCropper.top) - (scale - 1) * oy |
| | | }; |
| | | }, |
| | | onTouchStart() { |
| | | this.stopAnim(); |
| | | }, |
| | | // æ¤é |
| | | undo() { |
| | | if (this.operationIndex > 0) { |
| | | this.operationIndex--; |
| | | this.imageRect = this.operationHistory[this.operationIndex].imageRect; |
| | | this.cropperRect = this.operationHistory[this.operationIndex].cropperRect; |
| | | return true; |
| | | } |
| | | return false; |
| | | }, |
| | | // éå |
| | | resume() { |
| | | if (this.operationIndex < this.operationHistory.length - 1) { |
| | | this.operationIndex++; |
| | | this.imageRect = this.operationHistory[this.operationIndex].imageRect; |
| | | this.cropperRect = this.operationHistory[this.operationIndex].cropperRect; |
| | | return true; |
| | | } |
| | | return false; |
| | | }, |
| | | async drawImage(ctx,image,x,y,w,h){ |
| | | if (this.type2d) { |
| | | await new Promise(resolve => (image.onload = resolve)); |
| | | ctx.drawImage(image, x * this.pixel, y * this.pixel, w * this.pixel, h * this.pixel); |
| | | } else { |
| | | const path = await new Promise((resolve)=>{ |
| | | uni.getImageInfo({ |
| | | src:image, |
| | | success({path}){ |
| | | resolve(path) |
| | | } |
| | | }) |
| | | }) |
| | | ctx.drawImage(path, x * this.pixel, y * this.pixel, w * this.pixel, h * this.pixel); |
| | | await new Promise((resolve) => ctx.draw(false,resolve)); |
| | | } |
| | | }, |
| | | async crop() { |
| | | let ctx; |
| | | let canvas; |
| | | this.$emit('cropStart') |
| | | this.setTarget() |
| | | if (this.type2d) { |
| | | const query = uni.createSelectorQuery().in(this); |
| | | canvas = await new Promise(resolve => |
| | | query |
| | | .select('.bt-canvas') |
| | | .node(({ node }) => resolve(node)) |
| | | .exec() |
| | | ); |
| | | canvas.width = this.target.width * this.pixel; |
| | | canvas.height = this.target.height * this.pixel; |
| | | ctx = canvas.getContext('2d'); |
| | | // #ifdef MP-TOUTIAO |
| | | if(this.type2d){ |
| | | console.warn("请注æï¼ç®å头æ¡ç³»å°ç¨åºææ¶æ æ³ä½¿ç¨2d canvasä¿åå¾çï¼å»ºè®®æ¢æV1çæ¬") |
| | | } |
| | | // #endif |
| | | } else { |
| | | ctx = uni.createCanvasContext(this.canvasId,this); |
| | | } |
| | | const scale = this.cropperRect.width / this.target.width; |
| | | const dx = (this.cropperRect.left - this.imageRect.left) / scale; |
| | | const dy = (this.cropperRect.top - this.imageRect.top) / scale; |
| | | let image; |
| | | if(this.type2d){ |
| | | image = canvas.createImage() |
| | | image.src = this.imageSrc; |
| | | }else{ |
| | | image = this.imageSrc; |
| | | } |
| | | const x = -dx, |
| | | y = -dy, |
| | | w = this.imageRect.width / scale, |
| | | h = this.imageRect.height / scale; |
| | | ctx.save(); |
| | | ctx.translate(x + w / 2, y + h / 2); |
| | | ctx.rotate((this.rotateAngle * Math.PI) / 180); |
| | | ctx.translate(-(x + w / 2), -(y + h / 2)); |
| | | await this.drawImage(ctx,image, x, y, w, h); |
| | | ctx.restore(); |
| | | if (this.mask !== '') { |
| | | let imageData; |
| | | if (this.type2d) { |
| | | imageData = ctx.getImageData(0, 0, this.target.width, this.target.height); |
| | | } else { |
| | | imageData = await new Promise(resolve => { |
| | | uni.canvasGetImageData({ |
| | | canvasId: this.canvasId, |
| | | x: 0, |
| | | y: 0, |
| | | width: this.target.width, |
| | | height: this.target.height, |
| | | success(res) { |
| | | resolve(res); |
| | | } |
| | | },this); |
| | | }); |
| | | } |
| | | ctx.clearRect(0, 0, this.target.width, this.target.height); |
| | | if(this.type2d){ |
| | | image.src = this.mask; |
| | | }else{ |
| | | image = this.mask; |
| | | } |
| | | await this.drawImage(ctx,image, 0, 0, this.target.width, this.target.height); |
| | | let maskData; |
| | | if (this.type2d) { |
| | | maskData = ctx.getImageData(0, 0, this.target.width, this.target.height); |
| | | } else { |
| | | maskData = await new Promise((resolve,reject) => { |
| | | uni.canvasGetImageData({ |
| | | canvasId: this.canvasId, |
| | | x: 0, |
| | | y: 0, |
| | | width: this.target.width, |
| | | height: this.target.height, |
| | | success(res) { |
| | | resolve(res); |
| | | } |
| | | },this); |
| | | }); |
| | | } |
| | | ctx.clearRect(0, 0, this.target.width, this.target.height); |
| | | for (let index = 3; index < maskData.data.length; index += 4) { |
| | | const alpha = maskData.data[index]; |
| | | if (alpha !== 0) { |
| | | imageData.data[index] = 0; |
| | | } |
| | | } |
| | | if (this.type2d) { |
| | | ctx.putImageData(imageData, 0, 0); |
| | | } else { |
| | | await new Promise(resolve => { |
| | | uni.canvasPutImageData({ |
| | | canvasId: this.canvasId, |
| | | x: 0, |
| | | y: 0, |
| | | width: imageData.width, |
| | | height: imageData.height, |
| | | data: imageData.data, |
| | | complete: res => { |
| | | resolve(res); |
| | | } |
| | | },this); |
| | | }); |
| | | } |
| | | } |
| | | return new Promise((resolve,reject) => { |
| | | const params = {}; |
| | | if (this.type2d) { |
| | | params.canvas = canvas; |
| | | } else { |
| | | params.canvasId = this.canvasId; |
| | | } |
| | | |
| | | uni.canvasToTempFilePath({ |
| | | ...params, |
| | | destWidth: this.target.width, |
| | | destHeight: this.target.height, |
| | | quality: Number(this.quality) || 1, |
| | | fileType: this.fileType, |
| | | success: ({ tempFilePath }) => { |
| | | // #ifdef H5 |
| | | var arr = tempFilePath.split(','); |
| | | var mime = arr[0].match(/:(.*?);/)[1]; |
| | | var bstr = atob(arr[1]); |
| | | var n = bstr.length; |
| | | var u8arr = new Uint8Array(n); |
| | | for (var i = 0; i < n; i++) { |
| | | u8arr[i] = bstr.charCodeAt(i); |
| | | } |
| | | var url = URL || webkitURL; |
| | | resolve( |
| | | url.createObjectURL( |
| | | new Blob([u8arr], { |
| | | type: mime |
| | | }) |
| | | ) |
| | | ); |
| | | // #endif |
| | | resolve(tempFilePath); |
| | | }, |
| | | fail(err) { |
| | | console.log('ä¿å失败ï¼é误信æ¯ï¼',err); |
| | | reject(err); |
| | | } |
| | | },this); |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | | </script> |
| | | <!-- #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 --> |
| | | <script module="wxsModule" lang="wxs"> |
| | | var startTouchs = []; |
| | | var startDistance = 0; |
| | | var touchCenter = []; |
| | | var ratio = 0; |
| | | var imageInstance = null; |
| | | var cropperInstance = null; |
| | | var touchType = ""; |
| | | var touchInstance = null; |
| | | var cropperRect = null; |
| | | var imageRect = null; |
| | | // æè½¬è§åº¦ |
| | | var rotateAngle = 0; |
| | | // æä½æ¶æ¹åç对象 |
| | | var changes = { |
| | | imageRect: null, |
| | | cropperRect: null |
| | | } |
| | | |
| | | function updateImageStyle() { |
| | | var imageRect = changes.imageRect |
| | | imageInstance.setStyle({ |
| | | left: imageRect.left + 'px', |
| | | top: imageRect.top + 'px', |
| | | width: imageRect.width + 'px', |
| | | height: imageRect.height + 'px', |
| | | transform: 'rotate(' + rotateAngle + 'deg)' |
| | | }) |
| | | } |
| | | |
| | | function updateCopperStyle() { |
| | | var cropperRect = changes.cropperRect |
| | | cropperInstance.setStyle({ |
| | | left: cropperRect.left + "px", |
| | | top: cropperRect.top + "px", |
| | | width: cropperRect.width + "px", |
| | | height: cropperRect.height + "px" |
| | | }) |
| | | } |
| | | |
| | | function imageScale(scaleRate) { |
| | | var cw = imageRect.width * (scaleRate - 1) |
| | | var ch = imageRect.height * (scaleRate - 1) |
| | | changes.imageRect = { |
| | | width: imageRect.width + cw, |
| | | height: imageRect.height + ch, |
| | | left: imageRect.left - cw * (touchCenter[0]), |
| | | top: imageRect.top - ch * (touchCenter[1]) |
| | | } |
| | | } |
| | | function getImageRotateSizeChange(w,h){ |
| | | var cw = h*Math.sin(rotateAngle/180 * Math.PI) |
| | | var ch = w*Math.sin(rotateAngle/180 * Math.PI) |
| | | return {cw,ch} |
| | | } |
| | | // è§åº¦è½¬å¼§åº¦ |
| | | function ang2deg(ang){ |
| | | return ang/180*Math.PI |
| | | } |
| | | // è®¡ç®æè½¬åçå®çå¾çå¤§å° |
| | | function getRealSize(){ |
| | | var w = changes.imageRect.width |
| | | var h = changes.imageRect.height |
| | | var l = changes.imageRect.left |
| | | var t = changes.imageRect.top |
| | | // å
æè¾¹ |
| | | var R = Math.sqrt(w*w+h*h) |
| | | var angle = Math.atan(h/w) / Math.PI * 180 |
| | | var rorate = rotateAngle%90 |
| | | var direct = Math.floor(rotateAngle/90) |
| | | var width = R*Math.cos(ang2deg(angle-rorate)) |
| | | var height = R*Math.sin(ang2deg(angle+rorate)) |
| | | if(direct % 2 === 1){ |
| | | var temp = width |
| | | width = height |
| | | height = temp |
| | | } |
| | | return { |
| | | width: width, |
| | | height: height, |
| | | left: l - (width - w)/2, |
| | | top: t - (height - h)/2, |
| | | dw: width - w, |
| | | dh: height - h |
| | | } |
| | | } |
| | | module.exports = { |
| | | touchStart: function (ev, oi) { |
| | | // #ifdef APP-PLUS || H5 |
| | | ev.preventDefault(); |
| | | ev.stopPropagation(); |
| | | // #endif |
| | | touchInstance = ev.instance; |
| | | var dataSet = ev.instance.getDataset() |
| | | touchType = dataSet.type; |
| | | startTouchs = ev.touches; |
| | | oi.callMethod('onTouchStart') |
| | | if (startTouchs.length == 2) { |
| | | touchType = "image" |
| | | var x1 = startTouchs[0].clientX |
| | | var y1 = startTouchs[0].clientY |
| | | var x2 = startTouchs[1].clientX |
| | | var y2 = startTouchs[1].clientY |
| | | var distance = Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) |
| | | startDistance = Math.sqrt(distance) |
| | | var leftPercent = ((x1 + x2) / 2 - imageRect.left) / imageRect.width |
| | | var topPercent = ((y1 + y2) / 2 - imageRect.top) / imageRect.height |
| | | touchCenter = [leftPercent, topPercent] |
| | | } |
| | | return false; |
| | | }, |
| | | touchMove: function (ev, io) { |
| | | if (touchType == "") return false |
| | | // #ifdef H5 |
| | | ev.preventDefault(); |
| | | ev.stopPropagation(); |
| | | // #endif |
| | | var touches = ev.touches; |
| | | var changeX1 = touches[0].clientX - startTouchs[0].clientX; |
| | | var changeY1 = touches[0].clientY - startTouchs[0].clientY; |
| | | if (startTouchs.length == 1) { |
| | | if (touchType === 'image') { |
| | | changes.imageRect.left = imageRect.left + changeX1; |
| | | changes.imageRect.top = imageRect.top + changeY1; |
| | | updateImageStyle() |
| | | } else if (touchType === 'controller') { |
| | | var directionX = 0; |
| | | if (touchInstance.hasClass('left')) { |
| | | directionX = -1; |
| | | } |
| | | if (touchInstance.hasClass('right')) { |
| | | directionX = 1; |
| | | } |
| | | var directionY = 0; |
| | | if (touchInstance.hasClass('top')) { |
| | | directionY = -1 |
| | | } |
| | | if (touchInstance.hasClass('bottom')) { |
| | | directionY = 1 |
| | | } |
| | | var changeX = changeX1 * directionX; |
| | | var changeY = changeY1 * directionY; |
| | | // æ¯ä¾ç¼©æ¾æ§å¶ |
| | | if (ratio !== 0) { |
| | | if (directionX * directionY !== 0) { |
| | | if (changeX / ratio > changeY) { |
| | | changeY = changeX / ratio |
| | | changeX = changeY * ratio |
| | | } else { |
| | | changeX = changeY * ratio |
| | | changeY = changeX / ratio |
| | | } |
| | | } else { |
| | | if (directionX == 0) { |
| | | changeX = changeY * ratio |
| | | } else { |
| | | changeY = changeX / ratio |
| | | } |
| | | } |
| | | } |
| | | var realSize = getRealSize() |
| | | var width = cropperRect.width + changeX |
| | | var height = cropperRect.height + changeY |
| | | // var imageRight = imageRect.left + imageRect.width |
| | | // var imageBottom = imageRect.top + imageRect.height |
| | | var imageRight = realSize.left+realSize.width |
| | | var imageBottom = realSize.top+realSize.height |
| | | if (directionX != -1) { |
| | | if (cropperRect.left + width > imageRight) { |
| | | width = imageRight - cropperRect.left |
| | | if (ratio !== 0) { |
| | | height = width / ratio |
| | | } |
| | | } |
| | | } else { |
| | | var cLeft = cropperRect.left - changeX |
| | | if (cLeft < realSize.left) { |
| | | width = cropperRect.left + cropperRect.width - realSize.left |
| | | if (ratio !== 0) { |
| | | height = width / ratio |
| | | } |
| | | } |
| | | } |
| | | // 夿æ¯å¦è§¦åº |
| | | if (directionY != -1) { |
| | | if (cropperRect.top + height > imageBottom) { |
| | | height = imageBottom - cropperRect.top |
| | | if (ratio !== 0) { |
| | | width = height * ratio |
| | | } |
| | | } |
| | | } else { |
| | | var cTop = cropperRect.top - changeY |
| | | if (cTop < realSize.top) { |
| | | height = cropperRect.top + cropperRect.height - realSize.top |
| | | if (ratio !== 0) { |
| | | width = height * ratio |
| | | } |
| | | } |
| | | } |
| | | if (directionX == -1) { |
| | | changes.cropperRect.left = cropperRect.left + cropperRect.width - width |
| | | } |
| | | if (directionY == -1) { |
| | | changes.cropperRect.top = cropperRect.top + cropperRect.height - height |
| | | } |
| | | // è¾¹çæ§å¶ |
| | | changes.cropperRect.width = width |
| | | changes.cropperRect.height = height |
| | | updateCopperStyle() |
| | | } |
| | | } else if (touches.length == 2 && startTouchs.length == 2) { |
| | | var changeX2 = touches[0].clientX - touches[1].clientX; |
| | | var changeY2 = touches[0].clientY - touches[1].clientY; |
| | | var distance = Math.pow(changeX2, 2) + Math.pow(changeY2, 2) |
| | | distance = Math.sqrt(distance) |
| | | // æ¾å¤§æ¯ä¾ |
| | | var scaleRate = distance / startDistance |
| | | imageScale(scaleRate) |
| | | updateImageStyle() |
| | | } |
| | | return false; |
| | | }, |
| | | touchEnd: function (ev, oi) { |
| | | if (touchType === "image") { |
| | | var cropperLeft = cropperRect.left |
| | | var cropperRight = cropperRect.left + cropperRect.width |
| | | var cropperTop = cropperRect.top |
| | | var cropperBottom = cropperTop + cropperRect.height |
| | | var cropperRate = cropperRect.width / cropperRect.height |
| | | var realSize = getRealSize() |
| | | var rate = realSize.width / realSize.height |
| | | if (realSize.width < cropperRect.width || realSize.height < cropperRect.height) { |
| | | var scale = 1 |
| | | if (rate < cropperRate) { |
| | | scale = cropperRect.width / realSize.width |
| | | } else { |
| | | scale = cropperRect.height / realSize.height |
| | | } |
| | | imageRect.width = changes.imageRect.width |
| | | imageRect.height = changes.imageRect.height |
| | | imageScale(scale) |
| | | } |
| | | // è¾¹çæ§å¶start |
| | | if (cropperLeft < realSize.left) { |
| | | changes.imageRect.left = cropperLeft + realSize.dw/2 |
| | | } |
| | | if (cropperRight > realSize.left + realSize.width) { |
| | | changes.imageRect.left = cropperRight - realSize.width + realSize.dw/2 |
| | | } |
| | | if (cropperTop < realSize.top) { |
| | | changes.imageRect.top = cropperTop + realSize.dh/2 |
| | | } |
| | | if (cropperBottom > realSize.top + realSize.height) { |
| | | changes.imageRect.top = cropperBottom - realSize.height + realSize.dh/2 |
| | | } |
| | | // è¾¹çæ§å¶end |
| | | updateImageStyle() |
| | | } |
| | | oi.callMethod('updateData', { |
| | | cropperRect: changes.cropperRect, |
| | | imageRect: changes.imageRect, |
| | | }) |
| | | touchType = "" |
| | | startTouchs = [] |
| | | return false; |
| | | }, |
| | | // å°é»è¾å±çå¾ååæ¢åæ¥è¿æ¥ |
| | | // è£åªæ¯ä¾åå |
| | | changeRatio: function (value) { |
| | | ratio = value |
| | | }, |
| | | changeRotateAngle:function (value){ |
| | | rotateAngle = value; |
| | | if(imageInstance){ |
| | | updateImageStyle() |
| | | } |
| | | var realSize = getRealSize() |
| | | }, |
| | | changeImageRect: function (value, oldValue, oi) { |
| | | if (value) { |
| | | imageRect = value; |
| | | changes.imageRect = { |
| | | left: value.left, |
| | | top: value.top, |
| | | width: value.width, |
| | | height: value.height |
| | | }; |
| | | // #ifndef MP-WEIXIN || MP-QQ |
| | | setTimeout(function() { |
| | | imageInstance = oi.selectComponent('.mainContent > .image') |
| | | updateImageStyle(); |
| | | }); |
| | | // #endif |
| | | // #ifdef MP-WEIXIN || MP-QQ |
| | | imageInstance = oi.selectComponent('.mainContent > .image') |
| | | updateImageStyle(); |
| | | // #endif |
| | | } |
| | | }, |
| | | changeCropper: function (value, oldValue, oi) { |
| | | if (value) { |
| | | cropperRect = value |
| | | changes.cropperRect = { |
| | | left: value.left, |
| | | top: value.top, |
| | | width: value.width, |
| | | height: value.height |
| | | } |
| | | // #ifdef H5 || APP-VUE |
| | | setTimeout(function() { |
| | | // #endif |
| | | cropperInstance = oi.selectComponent('.mainContent > .cropper') |
| | | updateCopperStyle() |
| | | // #ifdef H5 || APP-VUE |
| | | }); |
| | | // #endif |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | <!-- #endif --> |
| | | <style lang="scss" scoped> |
| | | .bt-container { |
| | | // display: flex; |
| | | // flex-direction: column; |
| | | // justify-content: space-between; |
| | | height: 100%; |
| | | box-sizing: border-box; |
| | | // background-color: #0e1319; |
| | | position: relative; |
| | | overflow: hidden; |
| | | |
| | | .bt-canvas { |
| | | position: fixed; |
| | | left: 100%; |
| | | top: 0; |
| | | } |
| | | |
| | | .mainContent { |
| | | // flex: 1; |
| | | // flex-shrink:0; |
| | | // margin: 60rpx; |
| | | width: 100%; |
| | | height: 100%; |
| | | position: relative; |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | // touch-action: none; |
| | | |
| | | .image { |
| | | position: absolute; |
| | | // will-change: transform; |
| | | // transform-origin: center center; |
| | | width: 85%; |
| | | height: 85%; |
| | | will-change: left, top, width, height; |
| | | } |
| | | |
| | | .controller { |
| | | position: absolute; |
| | | z-index: 99; |
| | | padding: 10rpx; |
| | | $offset: -20rpx; |
| | | |
| | | &::after { |
| | | display: block; |
| | | content: ''; |
| | | filter: drop-shadow(0 0px 10rpx rgba(0, 0, 0, 0.3)); |
| | | } |
| | | |
| | | &.vertical { |
| | | top: calc(50% - 30rpx); |
| | | } |
| | | |
| | | &.horizon { |
| | | left: calc(50% - 30rpx); |
| | | } |
| | | |
| | | &.left { |
| | | &::after { |
| | | height: 40rpx; |
| | | border-left: 10rpx solid #fff; |
| | | } |
| | | |
| | | left: $offset; |
| | | } |
| | | |
| | | &.right { |
| | | &::after { |
| | | height: 40rpx; |
| | | border-right: 10rpx solid #fff; |
| | | } |
| | | |
| | | right: $offset; |
| | | } |
| | | |
| | | &.top { |
| | | top: $offset; |
| | | |
| | | &::after { |
| | | width: 40rpx; |
| | | border-top: 10rpx solid #fff; |
| | | } |
| | | } |
| | | |
| | | &.bottom { |
| | | bottom: $offset; |
| | | |
| | | &::after { |
| | | width: 40rpx; |
| | | border-bottom: 10rpx solid #fff; |
| | | } |
| | | } |
| | | |
| | | &.left.bottom, |
| | | &.right.bottom, |
| | | &.left.top, |
| | | &.left.bottom { |
| | | &::after { |
| | | width: 30rpx; |
| | | height: 30rpx; |
| | | background-color: transparent; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .cropper { |
| | | position: absolute; |
| | | border: 1px solid #eee; |
| | | box-sizing: content-box; |
| | | // transform-origin: center center; |
| | | outline: 999px solid rgba(0, 0, 0, 0.5); |
| | | will-change: left, top, width, height; |
| | | |
| | | // display: contain; |
| | | // pointer-events: none; |
| | | .mask { |
| | | position: absolute; |
| | | left: 0; |
| | | top: 0; |
| | | width: 100%; |
| | | height: 100%; |
| | | opacity: 0.5; |
| | | } |
| | | |
| | | .line { |
| | | position: absolute; |
| | | // background-color: #eee; |
| | | } |
| | | |
| | | .row { |
| | | width: 100%; |
| | | height: 0px; |
| | | left: 0; |
| | | border-top: 1px dashed #007aff; |
| | | } |
| | | |
| | | .col { |
| | | height: 100%; |
| | | width: 0px; |
| | | border-left: 1px dashed #007aff; |
| | | } |
| | | |
| | | .row1 { |
| | | top: 33%; |
| | | } |
| | | |
| | | .row2 { |
| | | top: 66%; |
| | | } |
| | | |
| | | .col1 { |
| | | left: 33%; |
| | | } |
| | | |
| | | .col2 { |
| | | left: 66%; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // .slot { |
| | | // position: relative; |
| | | // padding-top: 20rpx; |
| | | // } |
| | | } |
| | | |
| | | .anim { |
| | | transition: 0.2s; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | @font-face { |
| | | font-family: "iconfont"; /* Project id 3311610 */ |
| | | src: url('//at.alicdn.com/t/font_3311610_7wh8injedpd.woff2?t=1649382821379') format('woff2'), |
| | | url('//at.alicdn.com/t/font_3311610_7wh8injedpd.woff?t=1649382821379') format('woff'), |
| | | url('//at.alicdn.com/t/font_3311610_7wh8injedpd.ttf?t=1649382821379') format('truetype'); |
| | | } |
| | | |
| | | .iconfont { |
| | | font-family: "iconfont" !important; |
| | | font-size: 16px; |
| | | font-style: normal; |
| | | -webkit-font-smoothing: antialiased; |
| | | -moz-osx-font-smoothing: grayscale; |
| | | } |
| | | |
| | | .icon-reset:before { |
| | | content: "\e611"; |
| | | } |
| | | |
| | | .icon-move:before { |
| | | content: "\e67b"; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | var startTouchs = []; |
| | | var touchType = '' |
| | | var startDistance = 0; |
| | | var touchCenter = []; |
| | | var cropperRect = null; |
| | | var imageRect = null; |
| | | var directionX = 0; |
| | | var directionY = 0; |
| | | var ratio = 0; |
| | | // æä½æ¶æ¹åç对象 |
| | | var changes = { |
| | | imageRect: null, |
| | | cropperRect: null |
| | | } |
| | | // è®¡ç®æè½¬åçå®çå¾çå¤§å° |
| | | function getRealSize(){ |
| | | var w = changes.imageRect.width |
| | | var h = changes.imageRect.height |
| | | var l = changes.imageRect.left |
| | | var t = changes.imageRect.top |
| | | // å
æè¾¹ |
| | | var R = Math.sqrt(w*w+h*h) |
| | | var angle = Math.atan(h/w) / Math.PI * 180 |
| | | var rorate = rotateAngle%90 |
| | | var direct = Math.floor(rotateAngle/90) |
| | | var width = R*Math.cos(ang2deg(angle-rorate)) |
| | | var height = R*Math.sin(ang2deg(angle+rorate)) |
| | | if(direct % 2 === 1){ |
| | | var temp = width |
| | | width = height |
| | | height = temp |
| | | } |
| | | return { |
| | | width: width, |
| | | height: height, |
| | | left: l - (width - w)/2, |
| | | top: t - (height - h)/2, |
| | | dw: width - w, |
| | | dh: height - h |
| | | } |
| | | } |
| | | export default { |
| | | computed: { |
| | | imageStyle() { |
| | | const imageRect = this.imageRect |
| | | if (imageRect) { |
| | | return { |
| | | left: imageRect.left + 'px', |
| | | top: imageRect.top + 'px', |
| | | width: imageRect.width + 'px', |
| | | height: imageRect.height + 'px' |
| | | } |
| | | } else { |
| | | return {} |
| | | } |
| | | }, |
| | | cropperStyle() { |
| | | const cropperRect = this.cropperRect |
| | | if (cropperRect) { |
| | | return { |
| | | left: cropperRect.left + 'px', |
| | | top: cropperRect.top + 'px', |
| | | width: cropperRect.width + 'px', |
| | | height: cropperRect.height + 'px' |
| | | } |
| | | } else { |
| | | return {} |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | touchStart() { |
| | | let ev; |
| | | if (arguments.length == 3) { |
| | | directionX = arguments[0]; |
| | | directionY = arguments[1]; |
| | | ev = arguments[2]; |
| | | touchType = "controller"; |
| | | } else { |
| | | touchType = "image"; |
| | | ev = arguments[0]; |
| | | } |
| | | startTouchs = ev.touches; |
| | | changes = { |
| | | imageRect: this.imageRect, |
| | | cropperRect: this.cropperRect |
| | | }; |
| | | ratio = this.ratio; |
| | | cropperRect = { |
| | | ...changes.cropperRect |
| | | } |
| | | imageRect = { |
| | | ...changes.imageRect |
| | | } |
| | | if (startTouchs.length == 2) { |
| | | const imageRect = this.imageRect |
| | | var x1 = startTouchs[0].clientX |
| | | var y1 = startTouchs[0].clientY |
| | | var x2 = startTouchs[1].clientX |
| | | var y2 = startTouchs[1].clientY |
| | | var distance = Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) |
| | | startDistance = Math.sqrt(distance) |
| | | var leftPercent = ((x1 + x2) / 2 - imageRect.left) / imageRect.width |
| | | var topPercent = ((y1 + y2) / 2 - imageRect.top) / imageRect.height |
| | | touchCenter = [leftPercent, topPercent] |
| | | } |
| | | }, |
| | | touchMove(ev) { |
| | | if(startTouchs.length!==ev.touches.length) return |
| | | var touches = ev.touches; |
| | | var changeX1 = touches[0].clientX - startTouchs[0].clientX; |
| | | var changeY1 = touches[0].clientY - startTouchs[0].clientY; |
| | | if (startTouchs.length == 1) { |
| | | if (touchType === 'image') { |
| | | changes.imageRect.left = imageRect.left + changeX1; |
| | | changes.imageRect.top = imageRect.top + changeY1; |
| | | // console.log(startTouchs.length,ev.touches.length) |
| | | } else if (touchType === 'controller') { |
| | | var changeX = changeX1 * directionX; |
| | | var changeY = changeY1 * directionY; |
| | | // æ¯ä¾ç¼©æ¾æ§å¶ |
| | | if (ratio !== 0) { |
| | | if (directionX * directionY !== 0) { |
| | | if (changeX / ratio > changeY) { |
| | | changeY = changeX / ratio |
| | | changeX = changeY * ratio |
| | | } else { |
| | | changeX = changeY * ratio |
| | | changeY = changeX / ratio |
| | | } |
| | | } else { |
| | | if (directionX == 0) { |
| | | changeX = changeY * ratio |
| | | } else { |
| | | changeY = changeX / ratio |
| | | } |
| | | } |
| | | } |
| | | var realSize = getRealSize() |
| | | var width = cropperRect.width + changeX |
| | | var height = cropperRect.height + changeY |
| | | var imageRight = realSize.left+realSize.width |
| | | var imageBottom = realSize.top+realSize.height |
| | | if (directionX != -1) { |
| | | if (cropperRect.left + width > imageRight) { |
| | | width = imageRight - cropperRect.left |
| | | if (ratio !== 0) { |
| | | height = width / ratio |
| | | } |
| | | } |
| | | } else { |
| | | var cLeft = cropperRect.left - changeX |
| | | if (cLeft < realSize.left) { |
| | | width = cropperRect.left + cropperRect.width - realSize.left |
| | | if (ratio !== 0) { |
| | | height = width / ratio |
| | | } |
| | | } |
| | | } |
| | | // 夿æ¯å¦è§¦åº |
| | | if (directionY != -1) { |
| | | if (cropperRect.top + height > imageBottom) { |
| | | height = imageBottom - cropperRect.top |
| | | if (ratio !== 0) { |
| | | width = height * ratio |
| | | } |
| | | } |
| | | } else { |
| | | var cTop = cropperRect.top - changeY |
| | | if (cTop < realSize.top) { |
| | | height = cropperRect.top + cropperRect.height - realSize.top |
| | | if (ratio !== 0) { |
| | | width = height * ratio |
| | | } |
| | | } |
| | | } |
| | | if (directionX == -1) { |
| | | changes.cropperRect.left = cropperRect.left + cropperRect.width - width |
| | | } |
| | | if (directionY == -1) { |
| | | changes.cropperRect.top = cropperRect.top + cropperRect.height - height |
| | | } |
| | | // è¾¹çæ§å¶ |
| | | changes.cropperRect.width = width |
| | | changes.cropperRect.height = height |
| | | } |
| | | } else if (touches.length == 2 && startTouchs.length == 2) { |
| | | var changeX2 = touches[0].clientX - touches[1].clientX; |
| | | var changeY2 = touches[0].clientY - touches[1].clientY; |
| | | var distance = Math.pow(changeX2, 2) + Math.pow(changeY2, 2) |
| | | distance = Math.sqrt(distance) |
| | | // æ¾å¤§æ¯ä¾ |
| | | var scaleRate = distance / startDistance |
| | | this.imageScale(scaleRate) |
| | | } |
| | | }, |
| | | touchEnd(ev) { |
| | | // console.log('end',ev) |
| | | if(ev.touches.length!==0) return |
| | | if (touchType === "image") { |
| | | var cropperLeft = cropperRect.left |
| | | var cropperRight = cropperRect.left + cropperRect.width |
| | | var cropperTop = cropperRect.top |
| | | var cropperBottom = cropperTop + cropperRect.height |
| | | var cropperRate = cropperRect.width / cropperRect.height |
| | | var realSize = getRealSize() |
| | | var rate = realSize.width / realSize.height |
| | | if (realSize.width < cropperRect.width || realSize.height < cropperRect.height) { |
| | | var scale = 1 |
| | | if (rate < cropperRate) { |
| | | scale = cropperRect.width / realSize.width |
| | | } else { |
| | | scale = cropperRect.height / realSize.height |
| | | } |
| | | imageRect.width = changes.imageRect.width |
| | | imageRect.height = changes.imageRect.height |
| | | this.imageScale(scale) |
| | | } |
| | | // è¾¹çæ§å¶start |
| | | if (cropperLeft < realSize.left) { |
| | | changes.imageRect.left = cropperLeft + realSize.dw/2 |
| | | } |
| | | if (cropperRight > realSize.left + realSize.width) { |
| | | changes.imageRect.left = cropperRight - realSize.width + realSize.dw/2 |
| | | } |
| | | if (cropperTop < realSize.top) { |
| | | changes.imageRect.top = cropperTop + realSize.dh/2 |
| | | } |
| | | if (cropperBottom > realSize.top + realSize.height) { |
| | | changes.imageRect.top = cropperBottom - realSize.height + realSize.dh/2 |
| | | } |
| | | // è¾¹çæ§å¶end |
| | | } |
| | | this.updateData({ |
| | | cropperRect: changes.cropperRect, |
| | | imageRect: changes.imageRect, |
| | | }) |
| | | touchType = "" |
| | | startTouchs = [] |
| | | return false; |
| | | }, |
| | | imageScale(scaleRate) { |
| | | var cw = imageRect.width * (scaleRate - 1) |
| | | var ch = imageRect.height * (scaleRate - 1) |
| | | changes.imageRect = { |
| | | width: imageRect.width + cw, |
| | | height: imageRect.height + ch, |
| | | left: imageRect.left - cw * (touchCenter[0]), |
| | | top: imageRect.top - ch * (touchCenter[1]) |
| | | } |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | export function getTouchPoints(touchs) { |
| | | return Array.from(touchs).map(ev => { |
| | | return [ev.clientX, ev.clientY] |
| | | }) |
| | | } |
| | | // 彿°é²æ |
| | | export function debounce(fn, wait = 200) { |
| | | var timer = null; |
| | | return function (){ |
| | | if (timer !== null) { |
| | | clearTimeout(timer); |
| | | } |
| | | timer = setTimeout(fn.bind(this), wait); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * @description ç¡ç |
| | | * @param {number} time çå¾
æ¶é´æ¯«ç§æ° |
| | | */ |
| | | export function sleep(time = 200) { |
| | | return new Promise(resolve => { |
| | | setTimeout(resolve, time) |
| | | }) |
| | | } |
| | | const systemInfo = uni.getSystemInfoSync(); |
| | | |
| | | export function parseUnit(size){ |
| | | if(typeof size == 'number' || !isNaN(Number(size))){ |
| | | return uni.upx2px(size) |
| | | }else if(typeof size === 'string') { |
| | | if(size.endsWith('rpx')){ |
| | | return parseUnit(size.replace('rpx','')) |
| | | }else if(size.endsWith('px')){ |
| | | return Number(size.replace('px','')) |
| | | }else if(size.endsWith('vw')){ |
| | | return Number(size.replace('vw',''))*systemInfo.screenWidth/100 |
| | | }else if(size.endsWith('vh')){ |
| | | return Number(size.replace('vh',''))*systemInfo.screenHeight/100 |
| | | } |
| | | } |
| | | return 0 |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | { |
| | | "id": "bt-cropper", |
| | | "displayName": "bt-cropperå¾çè£åªæä»¶", |
| | | "version": "3.0.2", |
| | | "description": "䏿¬¾å¥½ç¨çå¾çè£åªæä»¶", |
| | | "keywords": [ |
| | | "å¾ç", |
| | | "å¾çè£åª", |
| | | "å¾çè£åª", |
| | | "头åè£åª", |
| | | "cropper" |
| | | ], |
| | | "repository": "", |
| | | "engines": { |
| | | "HBuilderX": "^3.4.9" |
| | | }, |
| | | "dcloudext": { |
| | | "sale": { |
| | | "regular": { |
| | | "price": "0.00" |
| | | }, |
| | | "sourcecode": { |
| | | "price": "0.00" |
| | | } |
| | | }, |
| | | "contact": { |
| | | "qq": "1097122362" |
| | | }, |
| | | "declaration": { |
| | | "ads": "æ ", |
| | | "data": "æä»¶ä¸éé任使°æ®", |
| | | "permissions": "æ " |
| | | }, |
| | | "npmurl": "", |
| | | "type": "component-vue" |
| | | }, |
| | | "uni_modules": { |
| | | "dependencies": [], |
| | | "encrypt": [], |
| | | "platforms": { |
| | | "cloud": { |
| | | "tcb": "y", |
| | | "aliyun": "y" |
| | | }, |
| | | "client": { |
| | | "Vue": { |
| | | "vue2": "y", |
| | | "vue3": "y" |
| | | }, |
| | | "App": { |
| | | "app-vue": "y", |
| | | "app-nvue": "n" |
| | | }, |
| | | "H5-mobile": { |
| | | "Safari": "y", |
| | | "Android Browser": "y", |
| | | "微信æµè§å¨(Android)": "y", |
| | | "QQæµè§å¨(Android)": "y" |
| | | }, |
| | | "H5-pc": { |
| | | "Chrome": "n", |
| | | "IE": "n", |
| | | "Edge": "n", |
| | | "Firefox": "n", |
| | | "Safari": "n" |
| | | }, |
| | | "å°ç¨åº": { |
| | | "微信": "y", |
| | | "é¿é": "u", |
| | | "ç¾åº¦": "u", |
| | | "åèè·³å¨": "y", |
| | | "QQ": "y" |
| | | }, |
| | | "å¿«åºç¨": { |
| | | "å为": "n", |
| | | "èç": "n" |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | |
| | | |
| | | ## bt-cropper å¾çè£å |
| | | > **ç»ä»¶åï¼bt-cropper** |
| | | |
| | | å¾çè£åç»ä»¶ï¼å¨é¡µé¢ä¸è£åå¾çï¼è¾åºè£ååçå¾çï¼æ¯æappï¼å°ç¨åºï¼H5 |
| | | ### [å¨çº¿ä½éª](https://static-mp-8cc5bb7c-7831-45bf-a4e1-a71b10d3319c.next.bspapp.com/h5) |
| | | |
| | | ## å°demoç¼è¯ä¸ºå¾®ä¿¡å°ç¨åºçæ¶åï¼ä¸å®è¦å¡«åappidï¼ï¼ï¼ä¸ç¶æ æ³ä½¿ç¨ï¼ï¼ |
| | | |
| | | |
| | | > **注æäºé¡¹** |
| | | > 为äºé¿å
é误使ç¨ï¼ç»å¤§å®¶å¸¦æ¥ä¸å¥½çå¼åä½éªï¼è¯·å¨ä½¿ç¨ç»ä»¶åä»ç»é
读ä¸é¢ç注æäºé¡¹ï¼å¯ä»¥å¸®ä½ é¿å
ä¸äºé误ã |
| | | > - ç»ä»¶éè¦ä¾èµ `sass` æä»¶ ï¼è¯·èªè¡æå¨å®è£
|
| | | > - åªæµè¯äºå¤´æ¡å°ç¨åºï¼app-vue å®åï¼å¾®ä¿¡å°ç¨åºåH5 大é¨åå¹³å°åºè¯¥é½æ²¡é®é¢äº |
| | | > - å
è£¹å±æè£åªå¨éè¦æå¨æå®é«åº¦åå®½åº¦ï¼æ¨èæå¨æå®è£åªå¨ç大å°ï¼å°¤å
¶æ¯å¤´æ¡å°ç¨åºï¼jsææ¶åè·åä¸å°å®¹å¨çå¤§å° |
| | | > - å¦ä½¿ç¨è¿ç¨ä¸æä»»ä½é®é¢ï¼æè
æ¨æä¸äºå¥½çå»ºè®®ï¼æ¬¢è¿èç³»ä½è
微信:1097122362 |
| | | |
| | | |
| | | |
| | | ### å®è£
æ¹å¼ |
| | | |
| | | æ¬ç»ä»¶ç¬¦å[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)è§èï¼`HBuilderX 2.5.5`èµ·ï¼åªéå°æ¬ç»ä»¶å¯¼å
¥é¡¹ç®ï¼å¨é¡µé¢`template`ä¸å³å¯ç´æ¥ä½¿ç¨ï¼æ éå¨é¡µé¢ä¸`import`åæ³¨å`components`ã |
| | | |
| | | ### åºæ¬ç¨æ³ |
| | | |
| | | **示ä¾** |
| | | |
| | | ```html |
| | | <template> |
| | | <view class="container"> |
| | | <bt-cropper ref="cropper" :imageSrc="imageSrc"></bt-cropper> |
| | | <button @click="crop">è£å</button> |
| | | </view> |
| | | </template> |
| | | <style> |
| | | .container{ |
| | | /** å¤å±ä¸å®è¦æå®å¤§å° */ |
| | | height:100vh; |
| | | } |
| | | </style> |
| | | ``` |
| | | |
| | | |
| | | ```javascript |
| | | export default { |
| | | methods:{ |
| | | crop(){ |
| | | // éè¿ç»ä»¶å®ä¹çrefè°ç¨cropperæ¹æ³ï¼è¿åä¸ä¸ªpromise对象 |
| | | this.$refs.cropper.crop().then((res)=>{ |
| | | console.log(res) |
| | | }) |
| | | } |
| | | } |
| | | } |
| | | |
| | | ``` |
| | | |
| | | ### éå®è£åæ¯ä¾ |
| | | |
| | | bt-cropperï¼æå®ratioå³å¯è®¾ç½®è£åæ¡ç宽髿¯ï¼å¦æä½ æ³è®©ç¨æ·èªç±ç¼©æ¾ï¼å°ratio设置为0å³å¯ |
| | | |
| | | **示ä¾** |
| | | |
| | | ```html |
| | | <bt-cropper ref="cropper" :ratio="16/9":imageSrc="imageSrc"></bt-cropper> |
| | | ``` |
| | | |
| | | ## API |
| | | |
| | | ### cropper Props |
| | | |
| | | |屿§å|ç±»å|é»è®¤å¼|说æ| |
| | | |:-:|:-:|:-:|:-:| |
| | | |ratio|number|0|è£åå¾åç宽髿¯ï¼0表示èªç±æ¯ä¾| |
| | | |dWidth|number|0|çæçå¾çç宽度,åä½ï¼px,å¦æä¼ å
¥0çè¯å°±æ¯æååç´ çæ¯ä¾è£åªï¼ä¹å°±æ¯è¯´ï¼è¾åºå¾ççæ¸
æ°åº¦åè¾å
¥å¾ççæ¸
æ°åº¦ä¸æ ·| |
| | | |imageSrc|String|''|åå¾çè·¯å¾ï¼æ¯ææ¬å°è·¯å¾åç½ç»è·¯å¾ï¼å¦ææ¯ç½ç»è·¯å¾ï¼å°ç¨åºè¦æ³¨æé
ç½®ä¸è½½ååï¼H5è¦æ³¨æè·¨åé®é¢| |
| | | |mask|String|''| è£åªçèçurlï¼é
åèçå¯ä»¥è£åªåºä»»ä½å½¢ç¶çå¾å½¢ (示ä¾è§å
¨å±è£åªdemo) | |
| | | |fileType|String|'jpg'|ç®æ æä»¶çç±»åï¼åªæ¯æ 'jpg' æ 'png'ãé»è®¤ä¸º 'jpg'| |
| | | |quality|Number|1|å¾ççè´¨éï¼åå¼èå´ä¸º (0, 1]ï¼ä¸å¨èå´å
æ¶å½ä½1.0å¤ç| |
| | | |showGrid|Boolean|false|æ¯å¦æ¾ç¤ºä¸å¿ç½æ ¼çº¿ï¼é»è®¤ä¸æ¾ç¤º| |
| | | |initPosition|object|null|å¾çèªå®ä¹çåå§çä½ç½®ï¼å
å®¹æ ¼å¼è§changeäºä»¶| |
| | | |autoZoom|Boolean|true|æ¯å¦å¼å¯æä½ç»æåèªå¨æ¾å¤§å°çªå£å¤§å°| |
| | | |containerSize|object|null|æå¨æå®å®¹å¨å¤§å°ï¼å¦æè£åªå¨æ¾å¨å¤§å°ä¼ç§»å¨æç¼©æ¾çdomä¸ï¼åå¿
é¡»æå¨æå®å¤§å°ï¼å¯ä»¥å¸¦ä¸åä½ï¼å¦æä¸å¸¦åä½é»è®¤pxï¼æ¯æçå使ï¼rpxï¼pxï¼vwï¼vm,示ä¾ï¼{width:100,height:1100}æè
ï¼{width:'100rpx',height:'100rpx'}| |
| | | |canvas2d|Boolean|false| æ¯å¼å¯ 2d canvas | |
| | | |
| | | |
| | | |
| | | ### cropper Methods |
| | | |
| | | |æ¹æ³åç§°|说æ|åæ°| |
| | | |:-:|:-:|:-:| |
| | | |crop|è£åªå¾ç|å¼å§ç»å¶å¹¶å¼å§è£åªå¾çï¼è¿åPromise对象| |
| | | |init|åå§å,å¾çè·¯å¾ååçæ¶åèªå¨è°ç¨æ¤æ¹æ³ï¼å¦æå
裹çdom大å°ååäºï¼ä½ éè¦æå¨è°ç¨æ¤æ¹æ³|-| |
| | | |initCropper|éç½®è£åªæ¡åå¾ççä½ç½®å大å°å°åå§çä½ç½®å大å°|-| |
| | | |undo|æ¤éï¼æå¤å¯ä»¥åé10æ¥|-| |
| | | |resume|éå|-| |
| | | |
| | | |
| | | ### cropper Events |
| | | |
| | | |æ¹æ³åç§°|说æ|è¿åå¼| |
| | | |:-:|:-:|:-:| |
| | | |change|å½è£åªæ¡åå¾ççç¸å¯¹ä½ç½®åçååçæ¶å触åï¼è¿åè£åªæ¡ä¸å¾ççç¸å¯¹ä½ç½®|ev={left:number,top:number,width:number,height:number}| |
| | | |loadFail|å½å¾çå 载失败æ¶è§¦å| - | |
| | | |cropStart|å½è£å¼å§æ¶è§¦å| - | |
| | | ## å¸®å© |
| | | å¨ä½¿ç¨ä¸å¦éå°æ æ³è§£å³çé®é¢ï¼è¯·æ [Issues](https://gitee.com/xiaojiang1996/better-uni-cropper/issues) æè
å æ 微信:1097122362ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | ## 2.1.6ï¼2023-04-16ï¼ |
| | | * ä¿®å¤ ç»ä»¶ä½¿ç¨ v-show æä»¤ä¼å¯¼è´éæ©å¾çååå§ä½ç½®ä¸¥éåä½çé®é¢ |
| | | ## 2.1.5ï¼2023-04-16ï¼ |
| | | * æ°å¢ å
¼å®¹APPå¹³å° |
| | | |
| | | ## 2.1.4ï¼2023-03-13ï¼ |
| | | * æ°å¢ fileType 屿§ï¼ç¨äºæå®çææä»¶çç±»åï¼åªæ¯æ 'jpg' æ 'png'ï¼é»è®¤ä¸º 'png' |
| | | * æ°å¢ delay 屿§ï¼å¾®ä¿¡å°ç¨åºå¹³å°ä½¿ç¨ `Canvas 2D` ç»å¶æ¶æ§å¶å¾çä»ç»å¶å°çææéæ¶é´ |
| | | * ä¼å å½çæå¾çç尺寸宽/é«è¶
è¿ Canvas 2D æå¤§éå¶ï¼1365*1365ï¼åå°ç»å¸å°ºå¯¸ç¼©æ¾å¨éå¶èå´å
ç»å¶å®æåè¾åºç®æ 尺寸 |
| | | * ä¼å æè½¬å¾æ æç¤ºæ¹åä¸å®é
æè½¬æ¹åä¸ç¬¦ |
| | | |
| | | ## 2.1.3ï¼2023-02-06ï¼ |
| | | * ä¼å vue3æ¯æ |
| | | |
| | | ## 2.1.2ï¼2023-02-03ï¼ |
| | | * æ°å¢ navigation 屿§ï¼H5å¹³å°å½ showAngle 为 true æ¶ï¼ä½¿ç¨æä»¶ç页é¢å¨ `page.json` ä¸é
ç½®äº "navigationStyle": "custom" æ¶ï¼å¿
须尿¤å¼è®¾ä¸º false ï¼å¦ååä¸ªå¯æä¼¸è§ç触åä½ç½®ä¼æåå·® |
| | | * ä¿®å¤ H5å¹³å°é¨å设å¤ï¼å·²ç¥iPhone11以䏿ºåï¼æç
§çå¾çç¼©æ¾æ¶ä¼éªå¨çé®é¢ |
| | | |
| | | ## 2.1.1ï¼2022-12-06ï¼ |
| | | * ä¿®å¤ æ¨ªå±éé
é®é¢ |
| | | |
| | | ## 2.1.0ï¼2022-12-06ï¼ |
| | | * æ°å¢ å
¼å®¹H5å¹³å°ï¼ä½¿ç¨ renderjs ååºæå¿äºä»¶ |
| | | |
| | | ## 2.0.0ï¼2022-12-05ï¼ |
| | | * éæ æä»¶ï¼ä½¿ç¨ WXS ååºæå¿äºä»¶ |
| | | * æ°å¢ å¾ç翻转 |
| | | * æ°å¢ æä¼¸è£åªæ¡æ¾å¤§å¾ç |
| | | * æ°å¢ çå¬PCé¼ æ æ»è½®è§¦åç¼©æ¾ |
| | | * æ°å¢ åå½¢ãåè§ç©å½¢çå¾çè£åª |
| | | * ä¼å å¾ç缩æ¾ï¼ç§»å¨ç«¯ä»¥åæè§¦æ¸ä¸å¿ç¹ä¸ºç¼©æ¾ä¸å¿ç¹ï¼PCç«¯ä»¥é¼ æ æå¨ç¹ä¸ºç¼©æ¾ä¸å¿ç¹ |
| | | * ä¼å è£åªæ¡æ ·å¼ |
| | | * ä¼å å¾çä½ç½®æå¨ æ¯æè¾¹çåå¼¹ææï¼æ»å¨æ¶å¯æ»åºè¾¹çï¼éæ¾æ¶åå¼¹å°è¾¹çï¼ |
| | | * ä¼å çæå¾çä½¿ç¨æ°ç Canvas 2D æ¥å£ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | /** |
| | | * å¾çç¼è¾å¨-æå¿çå¬ |
| | | * 1. æ¯æç¼è¯å°app-vueï¼uni-app 2.5.5å以ä¸çæ¬ï¼ãH5ä¸ |
| | | */ |
| | | /** å¾çåç§»é */ |
| | | var offset = { x: 0, y: 0 }; |
| | | /** å¾çç¼©æ¾æ¯ä¾ */ |
| | | var scale = 1; |
| | | /** å¾çæå°ç¼©æ¾æ¯ä¾ */ |
| | | var minScale = 1; |
| | | /** å¾çæè½¬è§åº¦ */ |
| | | var rotate = 0; |
| | | /** 触æ¸ç¹ */ |
| | | var touches = []; |
| | | /** å¾çå¸å±ä¿¡æ¯ */ |
| | | var img = {}; |
| | | /** ç³»ç»ä¿¡æ¯ */ |
| | | var sys = {}; |
| | | /** è£åªåºåå¸å±ä¿¡æ¯ */ |
| | | var area = {}; |
| | | /** 触æ¸è¡ä¸ºç±»å */ |
| | | var touchType = ''; |
| | | /** æä½è§çä½ç½® */ |
| | | var activeAngle = 0; |
| | | /** è£åªåºåå¸å±ä¿¡æ¯åç§»é */ |
| | | var areaOffset = { left: 0, right: 0, top: 0, bottom: 0 }; |
| | | /** å
ç´ ID */ |
| | | var elIds = { |
| | | 'imageStyles': 'crop-image', |
| | | 'maskStylesList': 'crop-mask-block', |
| | | 'borderStyles': 'crop-border', |
| | | 'circleBoxStyles': 'crop-circle-box', |
| | | 'circleStyles': 'crop-circle', |
| | | 'gridStylesList': 'crop-grid', |
| | | 'angleStylesList': 'crop-angle', |
| | | } |
| | | /** è®°å½ä¸æ¬¡åå§åæ¶é´æ³ï¼æé¤APPé夿´æ° */ |
| | | var timestamp = 0; |
| | | /** |
| | | * æ ·å¼å¯¹è±¡è½¬å符串 |
| | | * @param {Object} style æ ·å¼å¯¹è±¡ |
| | | */ |
| | | function styleToString(style) { |
| | | if(typeof style === 'string') return style; |
| | | var str = ''; |
| | | for (let k in style) { |
| | | str += k + ':' + style[k] + ';'; |
| | | } |
| | | return str; |
| | | } |
| | | /** |
| | | * |
| | | * @param {Object} instance 页é¢å®ä¾å¯¹è±¡ |
| | | * @param {Object} key è¦ä¿®æ¹æ ·å¼çkey |
| | | * @param {Object|Array} style æ ·å¼ |
| | | */ |
| | | function setStyle(instance, key, style) { |
| | | // console.log('setStyle', instance, key, JSON.stringify(style)) |
| | | // #ifdef APP-PLUS |
| | | if(Object.prototype.toString.call(style) === '[object Array]') { |
| | | for (var i = 0, len = style.length; i < len; i++) { |
| | | var el = window.document.getElementById(elIds[key] + '-' + (i + 1)); |
| | | el && (el.style = styleToString(style[i])); |
| | | } |
| | | } else { |
| | | var el = window.document.getElementById(elIds[key]); |
| | | el && (el.style = styleToString(style)); |
| | | } |
| | | // #endif |
| | | // #ifdef H5 |
| | | instance[key] = style; |
| | | // #endif |
| | | } |
| | | /** |
| | | * 触å页é¢å®ä¾æå®æ¹æ³ |
| | | * @param {Object} instance 页é¢å®ä¾å¯¹è±¡ |
| | | * @param {Object} name æ¹æ³åç§° |
| | | * @param {Object} obj ä¼ éåæ° |
| | | */ |
| | | function callMethod(instance, name, obj) { |
| | | // #ifdef APP-PLUS |
| | | instance.callMethod(name, obj); |
| | | // #endif |
| | | // #ifdef H5 |
| | | instance[name](obj); |
| | | // #endif |
| | | } |
| | | /** |
| | | * 计ç®ä¸¤ç¹é´è· |
| | | * @param {Object} touches 触æ¸ç¹ä¿¡æ¯ |
| | | */ |
| | | function getDistanceByTouches(touches) { |
| | | // æ ¹æ®å¾è¡å®çæ±ä¸¤ç¹é´è·ç¦» |
| | | var a = touches[1].pageX - touches[0].pageX; |
| | | var b = touches[1].pageY - touches[0].pageY; |
| | | var c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2)); |
| | | // æ±ä¸¤ç¹é´çä¸ç¹åæ |
| | | // 1. aãbå¯è½ä¸ºè´å¼ |
| | | // 2. 卿±aãbæ¶ï¼å¦ç¨touches[1]åtouches[0]ï¼åæ±ä¸ç¹åæ ä¹å¾ç¨touches[1]åa/2ãb/2 |
| | | // 3. åçï¼å¨æ±aãbæ¶ï¼ä¹å¯ç¨touches[0]åtouches[1]ï¼åæ±ä¸ç¹åæ ä¹å¾ç¨touches[0]åa/2ãb/2 |
| | | var x = touches[1].pageX - a / 2; |
| | | var y = touches[1].pageY - b / 2; |
| | | return { c, x, y }; |
| | | }; |
| | | /** |
| | | * æ£æ¥è¾¹çï¼éå¶ xãy æå¨èå´ï¼ç¦æ¢æ»åºè¾¹ç |
| | | * @param {Object} e ç¹åæ |
| | | */ |
| | | function checkRange(e) { |
| | | var r = rotate / 90 % 2; |
| | | if(r === 1) { // å å¾ç宽é«å¯è½ä¸çï¼ç¿»è½¬ 90° æ 270° åå¾ç宽é«éåç计ç®ï¼ä¸å·¦å³åä¸ä¸è¾¹çè¦æ ¹æ®å·®å¼ååç§» |
| | | var o = (img.height - img.width) / 2; // 宽é«å·®å¼ä¸å |
| | | return { |
| | | x: Math.min(Math.max(e.x, -img.height + o + area.width + area.left), area.left + o), |
| | | y: Math.min(Math.max(e.y, -img.width - o + area.height + area.top), area.top - o) |
| | | } |
| | | } |
| | | return { |
| | | x: Math.min(Math.max(e.x, -img.width + area.width + area.left), area.left), |
| | | y: Math.min(Math.max(e.y, -img.height + area.height + area.top), area.top) |
| | | } |
| | | }; |
| | | /** |
| | | * åæ´å¾çå¸å±ä¿¡æ¯ |
| | | * @param {Object} e å¸å±ä¿¡æ¯ |
| | | */ |
| | | function changeImageRect(e) { |
| | | // console.log('changeImageRect', e) |
| | | offset.x += e.x || 0; |
| | | offset.y += e.y || 0; |
| | | if(e.check) { // æ£æ¥è¾¹ç |
| | | var point = checkRange(offset); |
| | | if(offset.x !== point.x || offset.y !== point.y) { |
| | | offset = point; |
| | | } |
| | | } |
| | | |
| | | // å é¢ç¹ä¿®æ¹ width/height ä¼é æå¤§éçå
åæ¶èï¼æ¹ä¸ºscale |
| | | // e.instance.imageStyles = { |
| | | // width: img.width + 'px', |
| | | // height: img.height + 'px', |
| | | // transform: 'translate(' + (offset.x + ox) + 'px, ' + (offset.y + ox) + 'px) rotate(' + rotate +'deg)' |
| | | // }; |
| | | var ox = (img.width - img.oldWidth) / 2; |
| | | var oy = (img.height - img.oldHeight) / 2; |
| | | // e.instance.imageStyles = { |
| | | // width: img.oldWidth + 'px', |
| | | // height: img.oldHeight + 'px', |
| | | // transform: 'translate(' + (offset.x + ox) + 'px, ' + (offset.y + oy) + 'px) rotate(' + rotate +'deg) scale(' + scale + ')' |
| | | // }; |
| | | setStyle(e.instance, 'imageStyles', { |
| | | width: img.oldWidth + 'px', |
| | | height: img.oldHeight + 'px', |
| | | transform: 'translate(' + (offset.x + ox) + 'px, ' + (offset.y + oy) + 'px) rotate(' + rotate +'deg) scale(' + scale + ')' |
| | | }); |
| | | callMethod(e.instance, 'dataChange', { |
| | | width: img.width, |
| | | height: img.height, |
| | | x: offset.x, |
| | | y: offset.y, |
| | | rotate: rotate |
| | | }); |
| | | }; |
| | | /** |
| | | * åæ´è£åªåºåå¸å±ä¿¡æ¯ |
| | | * @param {Object} e å¸å±ä¿¡æ¯ |
| | | */ |
| | | function changeAreaRect(e) { |
| | | // console.log('changeAreaRect', e) |
| | | // åæ´èçæ ·å¼ |
| | | setStyle(e.instance, 'maskStylesList', [ |
| | | { |
| | | left: 0, |
| | | width: (area.left + areaOffset.left) + 'px', |
| | | top: 0, |
| | | bottom: 0, |
| | | }, |
| | | { |
| | | left: (area.right + areaOffset.right) + 'px', |
| | | right: 0, |
| | | top: 0, |
| | | bottom: 0, |
| | | }, |
| | | { |
| | | left: (area.left + areaOffset.left) + 'px', |
| | | width: (area.width + areaOffset.right - areaOffset.left) + 'px', |
| | | top: 0, |
| | | height: (area.top + areaOffset.top) + 'px', |
| | | }, |
| | | { |
| | | left: (area.left + areaOffset.left) + 'px', |
| | | width: (area.width + areaOffset.right - areaOffset.left) + 'px', |
| | | top: (area.bottom + areaOffset.bottom) + 'px', |
| | | // height: (area.top - areaOffset.bottom + sys.offsetBottom) + 'px', |
| | | bottom: 0, |
| | | } |
| | | ]); |
| | | // åæ´è¾¹æ¡æ ·å¼ |
| | | if(area.showBorder) { |
| | | setStyle(e.instance, 'borderStyles', { |
| | | left: (area.left + areaOffset.left) + 'px', |
| | | top: (area.top + areaOffset.top) + 'px', |
| | | width: (area.width + areaOffset.right - areaOffset.left) + 'px', |
| | | height: (area.height + areaOffset.bottom - areaOffset.top) + 'px', |
| | | }); |
| | | } |
| | | |
| | | // åæ´åèçº¿æ ·å¼ |
| | | if(area.showGrid) { |
| | | setStyle(e.instance, 'gridStylesList', [ |
| | | { |
| | | 'border-width': '1px 0 0 0', |
| | | left: (area.left + areaOffset.left) + 'px', |
| | | right: (area.right + areaOffset.right) + 'px', |
| | | top: (area.top + areaOffset.top + (area.height + areaOffset.bottom - areaOffset.top) / 3 - 0.5) + 'px', |
| | | width: (area.width + areaOffset.right - areaOffset.left) + 'px' |
| | | }, |
| | | { |
| | | 'border-width': '1px 0 0 0', |
| | | left: (area.left + areaOffset.left) + 'px', |
| | | right: (area.right + areaOffset.right) + 'px', |
| | | top: (area.top + areaOffset.top + (area.height + areaOffset.bottom - areaOffset.top) * 2 / 3 - 0.5) + 'px', |
| | | width: (area.width + areaOffset.right - areaOffset.left) + 'px' |
| | | }, |
| | | { |
| | | 'border-width': '0 1px 0 0', |
| | | top: (area.top + areaOffset.top) + 'px', |
| | | bottom: (area.bottom + areaOffset.bottom) + 'px', |
| | | left: (area.left + areaOffset.left + (area.width + areaOffset.right - areaOffset.left) / 3 - 0.5) + 'px', |
| | | height: (area.height + areaOffset.bottom - areaOffset.top) + 'px' |
| | | }, |
| | | { |
| | | 'border-width': '0 1px 0 0', |
| | | top: (area.top + areaOffset.top) + 'px', |
| | | bottom: (area.bottom + areaOffset.bottom) + 'px', |
| | | left: (area.left + areaOffset.left + (area.width + areaOffset.right - areaOffset.left) * 2 / 3 - 0.5) + 'px', |
| | | height: (area.height + areaOffset.bottom - areaOffset.top) + 'px' |
| | | } |
| | | ]); |
| | | } |
| | | |
| | | // åæ´åä¸ªä¼¸ç¼©è§æ ·å¼ |
| | | if(area.showAngle) { |
| | | setStyle(e.instance, 'angleStylesList', [ |
| | | { |
| | | 'border-width': area.angleBorderWidth + 'px 0 0 ' + area.angleBorderWidth + 'px', |
| | | left: (area.left + areaOffset.left - area.angleBorderWidth) + 'px', |
| | | top: (area.top + areaOffset.top - area.angleBorderWidth) + 'px', |
| | | }, |
| | | { |
| | | 'border-width': area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px 0 0', |
| | | left: (area.right + areaOffset.right - area.angleSize) + 'px', |
| | | top: (area.top + areaOffset.top - area.angleBorderWidth) + 'px', |
| | | }, |
| | | { |
| | | 'border-width': '0 0 ' + area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px', |
| | | left: (area.left + areaOffset.left - area.angleBorderWidth) + 'px', |
| | | top: (area.bottom + areaOffset.bottom - area.angleSize) + 'px', |
| | | }, |
| | | { |
| | | 'border-width': '0 ' + area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px 0', |
| | | left: (area.right + areaOffset.right - area.angleSize) + 'px', |
| | | top: (area.bottom + areaOffset.bottom - area.angleSize) + 'px', |
| | | } |
| | | ]); |
| | | } |
| | | |
| | | // åæ´åè§æ ·å¼ |
| | | if(area.radius > 0) { |
| | | var radius = area.radius; |
| | | if(area.width === area.height && area.radius >= area.width / 2) { // åå½¢ |
| | | radius = (area.width / 2); |
| | | } else { // åè§ç©å½¢ |
| | | if(area.width !== area.height) { // éå¶åè§åå¾ä¸è½è¶
è¿çè¾¹çä¸å |
| | | radius = Math.min(area.width / 2, area.height / 2, radius); |
| | | } |
| | | } |
| | | setStyle(e.instance, 'circleBoxStyles', { |
| | | left: (area.left + areaOffset.left) + 'px', |
| | | top: (area.top + areaOffset.top) + 'px', |
| | | width: (area.width + areaOffset.right - areaOffset.left) + 'px', |
| | | height: (area.height + areaOffset.bottom - areaOffset.top) + 'px' |
| | | }); |
| | | setStyle(e.instance, 'circleStyles', { |
| | | 'box-shadow': '0 0 0 ' + Math.max(area.width, area.height) + 'px rgba(51, 51, 51, 0.8)', |
| | | 'border-radius': radius + 'px' |
| | | }); |
| | | } |
| | | }; |
| | | /** |
| | | * 缩æ¾å¾ç |
| | | * @param {Object} e å¸å±ä¿¡æ¯ |
| | | */ |
| | | function scaleImage(e) { |
| | | // console.log('scaleImage', e) |
| | | var last = scale; |
| | | scale = Math.min(Math.max(e.scale + scale, minScale), img.maxScale); |
| | | if(last !== scale) { |
| | | img.width = img.oldWidth * scale; |
| | | img.height = img.oldHeight * scale; |
| | | // åèé®é¢ï¼æä¸ä¸ªé¿4000pxã宽4000pxç忹形ABCDï¼Aç¹çåæ åºå®å¨(-2000,-2000)ï¼ |
| | | // 该åè¾¹å½¢ä¸æä¸ä¸ªç¹Eï¼åæ 为(-100,-300)ï¼å°è¯¥åæ¹å½¢å¤å¶ä¸ä»½å¹¶ç¼©å°å°90%åï¼ |
| | | // æ°å边形çAç¹åæ 为å¤å°æ¶å¯ä½¿æ°å边形çEç¹ä¸åå边形çEç¹éåï¼ |
| | | // 颿ææï¼ä»å¾ä¸éåæç¹ï¼åç
§ç©ï¼ä¸ºä¸å¿ç¹è¿è¡ç¼©æ¾ï¼ç¼©æ¾æ¶æ 论å¾åæä¹ååï¼è¯¥ç¹ä½ç½®å§ç»åºå®ä¸å |
| | | // è®¡ç®æ¹æ³ï¼ä»¥ç¸åèµ·ç¹å
计ç®ç¼©æ¾åå两ç¹é´çè·ç¦»ï¼åå ä¸åå¾ååç§»éå³å¯ |
| | | e.x = (e.x - offset.x) * (1 - scale / last); |
| | | e.y = (e.y - offset.y) * (1 - scale / last); |
| | | changeImageRect(e); |
| | | return true; |
| | | } |
| | | return false; |
| | | }; |
| | | /** |
| | | * è·å触æ¸ç¹å¨åªä¸ªè§ |
| | | * @param {number} x 触æ¸ç¹xè½´åæ |
| | | * @param {number} y 触æ¸ç¹yè½´åæ |
| | | * @return {number} è§çä½ç½®ï¼0=æ ï¼1=å·¦ä¸ï¼2=å³ä¸ï¼3=å·¦ä¸ï¼4=å³ä¸ï¼ |
| | | */ |
| | | function getToucheAngle(x, y) { |
| | | // console.log('getToucheAngle', x, y, JSON.stringify(area)) |
| | | var o = area.angleBorderWidth; // éæ©å¤§è§¦åèå´åæ o å¼å 大å³å¯ |
| | | var oy = sys.navigation ? 0 : sys.windowTop; |
| | | if(y >= area.top - o + oy && y <= area.top + area.angleSize + o + oy) { |
| | | if(x >= area.left - o && x <= area.left + area.angleSize + o) { |
| | | return 1; // å·¦ä¸è§ |
| | | } else if(x >= area.right - area.angleSize - o && x <= area.right + o) { |
| | | return 2; // å³ä¸è§ |
| | | } |
| | | } else if(y >= area.bottom - area.angleSize - o + oy && y <= area.bottom + o + oy) { |
| | | if(x >= area.left - o && x <= area.left + area.angleSize + o) { |
| | | return 3; // å·¦ä¸è§ |
| | | } else if(x >= area.right - area.angleSize - o && x <= area.right + o) { |
| | | return 4; // å³ä¸è§ |
| | | } |
| | | } |
| | | return 0; // æ 触æ¸å°è§ |
| | | }; |
| | | /** |
| | | * éç½®æ°æ® |
| | | */ |
| | | function resetData() { |
| | | offset = { x: 0, y: 0 }; |
| | | scale = 1; |
| | | minScale = 1; |
| | | rotate = 0; |
| | | }; |
| | | function getTouchs(touches) { |
| | | var result = []; |
| | | var len = touches ? touches.length : 0 |
| | | for (var i = 0; i < len; i++) { |
| | | result[i] = { |
| | | pageX: touches[i].pageX, |
| | | // h5æ æ 颿 æ¶ï¼çªå£é¡¶é¨è·ç¦»ä»ä¸ºæ 颿 é«åº¦ï¼ä¸è§¦æ¸ç¹yè½´åæ è¿æ¯ææ 颿 çå¼ï¼å³å廿 颿 é«åº¦çå¼ |
| | | pageY: touches[i].pageY + sys.windowTop |
| | | }; |
| | | } |
| | | return result; |
| | | }; |
| | | export default { |
| | | data() { |
| | | return { |
| | | imageStyles: {}, |
| | | maskStylesList: [{}, {}, {}, {}], |
| | | borderStyles: {}, |
| | | gridStylesList: [{}, {}, {}, {}], |
| | | angleStylesList: [{}, {}, {}, {}], |
| | | circleBoxStyles: {}, |
| | | circleStyles: {} |
| | | } |
| | | }, |
| | | created() { |
| | | // çå¬ PC ç«¯é¼ æ æ»è½® |
| | | // #ifdef H5 |
| | | window.addEventListener('mousewheel', (e) => { |
| | | var touchs = getTouchs([e]) |
| | | img.src && scaleImage({ |
| | | instance: this.getInstance(), |
| | | check: true, |
| | | // é¼ æ å䏿»å¨æ¶ï¼deltaY åºå® -100ï¼é¼ æ å䏿»å¨æ¶ï¼deltaY åºå® 100 |
| | | scale: e.deltaY > 0 ? -0.05 : 0.05, |
| | | x: touchs[0].pageX, |
| | | y: touchs[0].pageY |
| | | }); |
| | | }); |
| | | // #endif |
| | | }, |
| | | methods: { |
| | | getInstance() { |
| | | // #ifdef APP-PLUS |
| | | return this.$ownerInstance; |
| | | // #endif |
| | | // #ifdef H5 |
| | | return this; |
| | | // #endif |
| | | }, |
| | | /** |
| | | * åå§åï¼è§å¯æ°æ®åæ´ |
| | | * @param {Object} newVal æ°æ°æ® |
| | | * @param {Object} oldVal æ§æ°æ® |
| | | * @param {Object} o ç»ä»¶å®ä¾å¯¹è±¡ |
| | | */ |
| | | initObserver: function(newVal, oldVal, o, i) { |
| | | console.log('initObserver', newVal, oldVal, o, i) |
| | | if(newVal && (!img.src || timestamp !== newVal.timestamp)) { |
| | | timestamp = newVal.timestamp; |
| | | img = newVal.img; |
| | | sys = newVal.sys; |
| | | area = newVal.area; |
| | | resetData(); |
| | | img.src && changeImageRect({ |
| | | instance: this.getInstance(), |
| | | x: (sys.windowWidth - img.width) / 2, |
| | | y: (sys.windowHeight + sys.windowTop - sys.offsetBottom - img.height) / 2 |
| | | }); |
| | | changeAreaRect({ |
| | | instance: this.getInstance() |
| | | }); |
| | | } |
| | | }, |
| | | /** |
| | | * é¼ æ æ»è½®æ»å¨ |
| | | * @param {Object} e äºä»¶å¯¹è±¡ |
| | | * @param {Object} o ç»ä»¶å®ä¾å¯¹è±¡ |
| | | */ |
| | | mousewheel: function(e, o) { |
| | | // h5å¹³å° wheel äºä»¶æ æ³å¤ææ»è½®æ»å¨æ¹åï¼éä½¿ç¨ mousewheel |
| | | }, |
| | | /** |
| | | * 触æ¸å¼å§ |
| | | * @param {Object} e äºä»¶å¯¹è±¡ |
| | | * @param {Object} o ç»ä»¶å®ä¾å¯¹è±¡ |
| | | */ |
| | | touchstart: function(e, o) { |
| | | if(!img.src) return; |
| | | touches = getTouchs(e.touches); |
| | | activeAngle = area.showAngle ? getToucheAngle(touches[0].pageX, touches[0].pageY) : 0; |
| | | if(touches.length === 1 && activeAngle !== 0) { |
| | | touchType = 'stretch'; // 伸缩è£åªåºå |
| | | } else { |
| | | touchType = ''; |
| | | } |
| | | // console.log('touchstart', e, activeAngle) |
| | | }, |
| | | /** |
| | | * 触æ¸ç§»å¨ |
| | | * @param {Object} e äºä»¶å¯¹è±¡ |
| | | * @param {Object} o ç»ä»¶å®ä¾å¯¹è±¡ |
| | | */ |
| | | touchmove: function(e, o) { |
| | | if(!img.src) return; |
| | | // console.log('touchmove', e, o) |
| | | e.touches = getTouchs(e.touches); |
| | | if(touchType === 'stretch') { // 触æ¸å个è§è¿è¡æä¼¸ |
| | | var point = e.touches[0]; |
| | | var start = touches[0]; |
| | | var x = point.pageX - start.pageX; |
| | | var y = point.pageY - start.pageY; |
| | | if(x !== 0 || y !== 0) { |
| | | var maxX = area.width * (1 - area.minScale); |
| | | var maxY = area.height * (1 - area.minScale); |
| | | // console.log(x, y, maxX, maxY) |
| | | touches[0] = point; |
| | | switch(activeAngle) { |
| | | case 1: // å·¦ä¸è§ |
| | | x += areaOffset.left; |
| | | y += areaOffset.top; |
| | | if(x >= 0 && y >= 0) { // æææ»å¨ |
| | | if(x > y) { // 以xè½´æ»å¨è·ç¦»ä¸ºç¼©æ¾åºå |
| | | if(x > maxX) x = maxX; |
| | | y = x * area.height / area.width; |
| | | } else { // 以yè½´æ»å¨è·ç¦»ä¸ºç¼©æ¾åºå |
| | | if(y > maxY) y = maxY; |
| | | x = y * area.width / area.height; |
| | | } |
| | | areaOffset.left = x; |
| | | areaOffset.top = y; |
| | | } |
| | | break; |
| | | case 2: // å³ä¸è§ |
| | | x += areaOffset.right; |
| | | y += areaOffset.top; |
| | | if(x <= 0 && y >= 0) { // æææ»å¨ |
| | | if(-x > y) { // 以xè½´æ»å¨è·ç¦»ä¸ºç¼©æ¾åºå |
| | | if(-x > maxX) x = -maxX; |
| | | y = -x * area.height / area.width; |
| | | } else { // 以yè½´æ»å¨è·ç¦»ä¸ºç¼©æ¾åºå |
| | | if(y > maxY) y = maxY; |
| | | x = -y * area.width / area.height; |
| | | } |
| | | areaOffset.right = x; |
| | | areaOffset.top = y; |
| | | } |
| | | break; |
| | | case 3: // å·¦ä¸è§ |
| | | x += areaOffset.left; |
| | | y += areaOffset.bottom; |
| | | if(x >= 0 && y <= 0) { // æææ»å¨ |
| | | if(x > -y) { // 以xè½´æ»å¨è·ç¦»ä¸ºç¼©æ¾åºå |
| | | if(x > maxX) x = maxX; |
| | | y = -x * area.height / area.width; |
| | | } else { // 以yè½´æ»å¨è·ç¦»ä¸ºç¼©æ¾åºå |
| | | if(-y > maxY) y = -maxY; |
| | | x = -y * area.width / area.height; |
| | | } |
| | | areaOffset.left = x; |
| | | areaOffset.bottom = y; |
| | | } |
| | | break; |
| | | case 4: // å³ä¸è§ |
| | | x += areaOffset.right; |
| | | y += areaOffset.bottom; |
| | | if(x <= 0 && y <= 0) { // æææ»å¨ |
| | | if(-x > -y) { // 以xè½´æ»å¨è·ç¦»ä¸ºç¼©æ¾åºå |
| | | if(-x > maxX) x = -maxX; |
| | | y = x * area.height / area.width; |
| | | } else { // 以yè½´æ»å¨è·ç¦»ä¸ºç¼©æ¾åºå |
| | | if(-y > maxY) y = -maxY; |
| | | x = y * area.width / area.height; |
| | | } |
| | | areaOffset.right = x; |
| | | areaOffset.bottom = y; |
| | | } |
| | | break; |
| | | } |
| | | // console.log(x, y, JSON.stringify(areaOffset)) |
| | | changeAreaRect({ |
| | | instance: this.getInstance(), |
| | | }); |
| | | // this.draw(); |
| | | } |
| | | } else if (e.touches.length == 2) { // åç¹è§¦æ¸ç¼©æ¾ |
| | | var start = getDistanceByTouches(touches); |
| | | var end = getDistanceByTouches(e.touches); |
| | | scaleImage({ |
| | | instance: this.getInstance(), |
| | | check: !area.bounce, |
| | | scale: (end.c - start.c) / 100, |
| | | x: end.x, |
| | | y: end.y |
| | | }); |
| | | touchType = 'scale'; |
| | | } else if(touchType === 'scale') {// ä»åç¹è§¦æ¸åæåç¹è§¦æ¸ / ä»ç¼©æ¾åææå¨ |
| | | touchType = 'move'; |
| | | } else { |
| | | changeImageRect({ |
| | | instance: this.getInstance(), |
| | | check: !area.bounce, |
| | | x: e.touches[0].pageX - touches[0].pageX, |
| | | y: e.touches[0].pageY - touches[0].pageY |
| | | }); |
| | | touchType = 'move'; |
| | | } |
| | | touches = e.touches; |
| | | }, |
| | | /** |
| | | * 触æ¸ç»æ |
| | | * @param {Object} e äºä»¶å¯¹è±¡ |
| | | * @param {Object} o ç»ä»¶å®ä¾å¯¹è±¡ |
| | | */ |
| | | touchend: function(e, o) { |
| | | if(!img.src) return; |
| | | if(touchType === 'stretch') { // æä¼¸è£åªåºåçå个è§ç¼©æ¾ |
| | | // è£åªåºå宽度被缩æ¾å°å¤å° |
| | | var left = areaOffset.left; |
| | | var right = areaOffset.right; |
| | | var top = areaOffset.top; |
| | | var bottom = areaOffset.bottom; |
| | | var w = area.width + right - left; |
| | | var h = area.height + bottom - top; |
| | | // å¾åæ¾å¤§åæ° |
| | | var p = scale * (area.width / w) - scale; |
| | | // å¤åè£åªåºå |
| | | areaOffset = { left: 0, right: 0, top: 0, bottom: 0 }; |
| | | changeAreaRect({ |
| | | instance: this.getInstance(), |
| | | }); |
| | | scaleImage({ |
| | | instance: this.getInstance(), |
| | | scale: p, |
| | | x: area.left + left + (1 === activeAngle || 3 === activeAngle ? w : 0), |
| | | y: area.top + top + (1 === activeAngle || 2 === activeAngle ? h : 0) |
| | | }); |
| | | } else if (area.bounce) { // æ£æ¥è¾¹çå¹¶ç«æ£ï¼å®ç°æå¨å°è¾¹çæ¶æåå¼¹ææ |
| | | changeImageRect({ |
| | | instance: this.getInstance(), |
| | | check: true |
| | | }); |
| | | } |
| | | }, |
| | | /** |
| | | * 顺æ¶é翻转å¾ç90° |
| | | * @param {Object} e äºä»¶å¯¹è±¡ |
| | | * @param {Object} o ç»ä»¶å®ä¾å¯¹è±¡ |
| | | */ |
| | | rotateImage: function(e, o) { |
| | | rotate = (rotate + 90) % 360; |
| | | |
| | | // å å¾ç宽é«å¯è½ä¸çï¼ç¿»è½¬åå¾ç宽é«éè¶³å¤å¡«æ»¡è£åªåºå |
| | | var r = rotate / 90 % 2; |
| | | minScale = 1; |
| | | if(img.width < area.height) { |
| | | minScale = area.height / img.oldWidth; |
| | | } else if(img.height < area.width) { |
| | | minScale = (area.width / img.oldHeight) |
| | | } |
| | | if(minScale !== 1) { |
| | | scaleImage({ |
| | | instance: this.getInstance(), |
| | | scale: minScale - scale, |
| | | x: sys.windowWidth / 2, |
| | | y: (sys.windowHeight - sys.offsetBottom) / 2 |
| | | }); |
| | | } |
| | | |
| | | // ç±äºæå¨ç»å¸åä¼å¯¼è´å¾çä½ç½®åç§»ï¼ç¿»è½¬æ¶çæè½¬ä¸å¿ç¹éæ¯å¾çåºå+åç§»åºåçä¸å¿ç¹ |
| | | // 翻转xè½´ä¸å¿ç¹ = (è¶
åºè£åªåºåå³ä¾§çå¾ç宽度 - è¶
åºè£åªåºå左侧çå¾ç宽度) / 2 |
| | | // 翻转yè½´ä¸å¿ç¹ = (è¶
åºè£åªåºå䏿¹çå¾ç宽度 - è¶
åºè£åªåºå䏿¹çå¾ç宽度) / 2 |
| | | var ox = ((offset.x + img.width - area.right) - (area.left - offset.x)) / 2; |
| | | var oy = ((offset.y + img.height - area.bottom) - (area.top - offset.y)) / 2; |
| | | changeImageRect({ |
| | | instance: this.getInstance(), |
| | | check: true, |
| | | x: -ox - oy, |
| | | y: -oy + ox |
| | | }); |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="image-cropper" @wheel="cropper.mousewheel" v-if="show"> |
| | | <canvas v-if="use2d" type="2d" id="imgCanvas" class="img-canvas" :style="{ |
| | | width: `${canvansWidth}px`, |
| | | height: `${canvansHeight}px` |
| | | }"></canvas> |
| | | <canvas v-else id="imgCanvas" canvas-id="imgCanvas" class="img-canvas" :style="{ |
| | | width: `${canvansWidth}px`, |
| | | height: `${canvansHeight}px` |
| | | }"></canvas> |
| | | <view class="pic-preview" :change:init="cropper.initObserver" :init="initData" @touchstart="cropper.touchstart" @touchmove="cropper.touchmove" @touchend="cropper.touchend"> |
| | | <image v-if="imgSrc" id="crop-image" class="crop-image" :style="cropper.imageStyles" :src="imgSrc" webp></image> |
| | | <view v-for="(item, index) in maskList" :key="item.id" :id="item.id" class="crop-mask-block" :style="cropper.maskStylesList[index]"></view> |
| | | <view v-if="showBorder" id="crop-border" class="crop-border" :style="cropper.borderStyles"></view> |
| | | <view v-if="radius > 0" id="crop-circle-box" class="crop-circle-box" :style="cropper.circleBoxStyles"> |
| | | <view class="crop-circle" id="crop-circle" :style="cropper.circleStyles"></view> |
| | | </view> |
| | | <block v-if="showGrid"> |
| | | <view v-for="(item, index) in gridList" :key="item.id" :id="item.id" class="crop-grid" :style="cropper.gridStylesList[index]"></view> |
| | | </block> |
| | | <block v-if="showAngle"> |
| | | <view v-for="(item, index) in angleList" :key="item.id" :id="item.id" class="crop-angle" :style="cropper.angleStylesList[index]"> |
| | | <view :style="[{ |
| | | width: `${angleSize}px`, |
| | | height: `${angleSize}px` |
| | | }]"></view> |
| | | </view> |
| | | </block> |
| | | </view> |
| | | <view class="fixed-bottom safe-area-inset-bottom"> |
| | | <view v-if="rotatable && !!imgSrc" class="rotate-icon" @click="cropper.rotateImage"></view> |
| | | <view v-if="!choosable" class="choose-btn" @click="cropClick">ç¡®å®</view> |
| | | <block v-else-if="!!imgSrc"> |
| | | <view class="rechoose" @click="chooseImage">éé</view> |
| | | <button class="button" size="mini" @click="cropClick">ç¡®å®</button> |
| | | </block> |
| | | <view v-else class="choose-btn" @click="chooseImage">å½å
¥äººè¸</view> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <!-- #ifdef APP-VUE || H5 --> |
| | | <script module="cropper" lang="renderjs"> |
| | | import cropper from './qf-image-cropper.render.js'; |
| | | export default { |
| | | mixins: [ cropper ] |
| | | } |
| | | </script> |
| | | <!-- #endif --> |
| | | <!-- #ifdef MP-WEIXIN || MP-QQ --> |
| | | <script module="cropper" lang="wxs" src="./qf-image-cropper.wxs"></script> |
| | | <!-- #endif --> |
| | | <script> |
| | | /** è£åªåºåæå¤§å®½é«æå å±å¹å®½åº¦ç¾åæ¯ */ |
| | | const AREA_SIZE = 75; |
| | | /** å¾çé»è®¤å®½é« */ |
| | | const IMG_SIZE = 300; |
| | | |
| | | export default { |
| | | name:"qf-image-cropper", |
| | | // #ifdef MP-WEIXIN |
| | | options: { |
| | | // 表示å¯ç¨æ ·å¼é离ï¼å¨èªå®ä¹ç»ä»¶å
å¤ï¼ä½¿ç¨ class æå®çæ ·å¼å°ä¸ä¼ç¸äºå½±å |
| | | styleIsolation: "isolated" |
| | | }, |
| | | // #endif |
| | | props: { |
| | | /** å¾çèµæºå°å */ |
| | | src: { |
| | | type: String, |
| | | default: '' |
| | | }, |
| | | /** è£åªå®½åº¦ï¼æäºå¹³å°æè®¾å¤å¯¹äºcanvasç尺寸æéå¶ï¼è¿å¤§å¯è½ä¼å¯¼è´æ æ³æ£å¸¸ç»å¶ */ |
| | | width: { |
| | | type: Number, |
| | | default: IMG_SIZE |
| | | }, |
| | | /** è£åªé«åº¦ï¼æäºå¹³å°æè®¾å¤å¯¹äºcanvasç尺寸æéå¶ï¼è¿å¤§å¯è½ä¼å¯¼è´æ æ³æ£å¸¸ç»å¶ */ |
| | | height: { |
| | | type: Number, |
| | | default: IMG_SIZE |
| | | }, |
| | | /** æ¯å¦ç»å¶è£åªåºåè¾¹æ¡ */ |
| | | showBorder: { |
| | | type: Boolean, |
| | | default: true |
| | | }, |
| | | /** æ¯å¦ç»å¶è£åªåºåç½æ ¼åè线 */ |
| | | showGrid: { |
| | | type: Boolean, |
| | | default: true |
| | | }, |
| | | /** æ¯å¦å±ç¤ºåä¸ªæ¯æä¼¸ç¼©çè§ */ |
| | | showAngle: { |
| | | type: Boolean, |
| | | default: true |
| | | }, |
| | | /** è£åªåºåæå°ç¼©æ¾åæ° */ |
| | | areaScale: { |
| | | type: Number, |
| | | default: 0.3 |
| | | }, |
| | | /** å¾çæå¤§ç¼©æ¾åæ° */ |
| | | maxScale: { |
| | | type: Number, |
| | | default: 5 |
| | | }, |
| | | /** æ¯å¦æåå¼¹ææï¼æå¨æ¶å¯ä»¥æåºè¾¹çï¼éæ¾æ¶ä¼å¼¹åè¾¹ç */ |
| | | bounce: { |
| | | type: Boolean, |
| | | default: true |
| | | }, |
| | | /** æ¯å¦æ¯æç¿»è½¬ */ |
| | | rotatable: { |
| | | type: Boolean, |
| | | default: true |
| | | }, |
| | | /** æ¯å¦æ¯æä»æ¬å°éæ©ç´ æ */ |
| | | choosable: { |
| | | type: Boolean, |
| | | default: true |
| | | }, |
| | | /** å个è§å°ºå¯¸ï¼åä½px */ |
| | | angleSize: { |
| | | type: Number, |
| | | default: 20 |
| | | }, |
| | | /** å个è§è¾¹æ¡å®½åº¦ï¼åä½px */ |
| | | angleBorderWidth: { |
| | | type: Number, |
| | | default: 2 |
| | | }, |
| | | /** è£åªå¾çåè§åå¾ï¼åä½px */ |
| | | radius: { |
| | | type: Number, |
| | | default: 0 |
| | | }, |
| | | /** çææä»¶çç±»åï¼åªæ¯æ 'jpg' æ 'png'ãé»è®¤ä¸º 'png' */ |
| | | fileType: { |
| | | type: String, |
| | | default: 'png' |
| | | }, |
| | | /** |
| | | * å¾çä»ç»å¶å°çææéæ¶é´ï¼åä½ms |
| | | * 微信å°ç¨åºå¹³å°ä½¿ç¨ `Canvas 2D` ç»å¶æ¶ææ |
| | | * å¦ç»å¶å¤§å¾æåºç°è£åªå¾ç空ç½çæ
åµåºéå½è°å¤§è¯¥å¼ï¼å `Canvas 2d` éç¨åæ¥ç»å¶ï¼éèªå·±ææ§ç»å¶å®ææ¶é´ |
| | | */ |
| | | delay: { |
| | | type: Number, |
| | | default: 1000 |
| | | }, |
| | | // #ifdef H5 |
| | | /** |
| | | * 页颿¯å¦æ¯åçæ é¢æ |
| | | * H5å¹³å°å½ showAngle 为 true æ¶ï¼ä½¿ç¨æä»¶ç页é¢å¨ `page.json` ä¸é
ç½®äº "navigationStyle": "custom" æ¶ï¼å¿
须尿¤å¼è®¾ä¸º false ï¼å¦ååä¸ªå¯æä¼¸è§ç触åä½ç½®ä¼æåå·®ã |
| | | * 注ï¼å H5å¹³å°ççªå£é«åº¦æ¯å
嫿 颿 çï¼èå±å¹è§¦æ¸ç¹çåæ æ¯ä¸å
å«ç |
| | | */ |
| | | navigation: { |
| | | type: Boolean, |
| | | default: true |
| | | } |
| | | // #endif |
| | | }, |
| | | emits: ["crop"], |
| | | data() { |
| | | return { |
| | | // ç¨ä¸å id 使 v-for key ä¸éå¤ |
| | | maskList: [ |
| | | { id: 'crop-mask-block-1' }, |
| | | { id: 'crop-mask-block-2' }, |
| | | { id: 'crop-mask-block-3' }, |
| | | { id: 'crop-mask-block-4' }, |
| | | ], |
| | | gridList: [ |
| | | { id: 'crop-grid-1' }, |
| | | { id: 'crop-grid-2' }, |
| | | { id: 'crop-grid-3' }, |
| | | { id: 'crop-grid-4' }, |
| | | ], |
| | | angleList: [ |
| | | { id: 'crop-angle-1' }, |
| | | { id: 'crop-angle-2' }, |
| | | { id: 'crop-angle-3' }, |
| | | { id: 'crop-angle-4' }, |
| | | ], |
| | | /** æ¬å°ç¼åçå¾çè·¯å¾ */ |
| | | imgSrc: '', |
| | | /** å¾ççè£åªå®½åº¦ */ |
| | | imgWidth: IMG_SIZE, |
| | | /** å¾ççè£åªé«åº¦ */ |
| | | imgHeight: IMG_SIZE, |
| | | /** è£åªåºåæå¤§å®½åº¦æå å±å¹å®½åº¦ç¾åæ¯ */ |
| | | widthPercent: AREA_SIZE, |
| | | /** è£åªåºåæå¤§é«åº¦æå å±å¹å®½åº¦ç¾åæ¯ */ |
| | | heightPercent: AREA_SIZE, |
| | | /** è£åªåºåå¸å±ä¿¡æ¯ */ |
| | | area: {}, |
| | | /** æªè¢«ç¼©æ¾è¿çå¾ç宽 */ |
| | | oldWidth: 0, |
| | | /** æªè¢«ç¼©æ¾è¿çå¾çé« */ |
| | | oldHeight: 0, |
| | | /** ç³»ç»ä¿¡æ¯ */ |
| | | sys: uni.getSystemInfoSync(), |
| | | scaleWidth: 0, |
| | | scaleHeight: 0, |
| | | rotate: 0, |
| | | offsetX: 0, |
| | | offsetY: 0, |
| | | use2d: false, |
| | | canvansWidth: 0, |
| | | canvansHeight: 0, |
| | | show: false |
| | | // imageStyles: {}, |
| | | // maskStylesList: [{}, {}, {}, {}], |
| | | // borderStyles: {}, |
| | | // gridStylesList: [{}, {}, {}, {}], |
| | | // angleStylesList: [{}, {}, {}, {}], |
| | | // circleBoxStyles: {}, |
| | | // circleStyles: {}, |
| | | } |
| | | }, |
| | | computed: { |
| | | initData() { |
| | | // console.log('initData') |
| | | return { |
| | | timestamp: new Date().getTime(), |
| | | area: { |
| | | ...this.area, |
| | | bounce: this.bounce, |
| | | showBorder: this.showBorder, |
| | | showGrid: this.showGrid, |
| | | showAngle: this.showAngle, |
| | | angleSize: this.angleSize, |
| | | angleBorderWidth: this.angleBorderWidth, |
| | | minScale: this.areaScale, |
| | | widthPercent: this.widthPercent, |
| | | heightPercent: this.heightPercent, |
| | | radius: this.radius |
| | | }, |
| | | sys: this.sys, |
| | | img: { |
| | | maxScale: this.maxScale, |
| | | src: this.imgSrc, |
| | | width: this.oldWidth, |
| | | height: this.oldHeight, |
| | | oldWidth: this.oldWidth, |
| | | oldHeight: this.oldHeight, |
| | | } |
| | | } |
| | | }, |
| | | imgProps() { |
| | | return { |
| | | width: this.width, |
| | | height: this.height, |
| | | src: this.src, |
| | | } |
| | | } |
| | | }, |
| | | watch: { |
| | | imgProps: { |
| | | handler(val) { |
| | | // console.log('imgProps', val) |
| | | // èªå®ä¹è£åªå°ºï¼ç¤ºä¾å¦ä¸ï¼ |
| | | this.imgWidth = Number(val.width) || IMG_SIZE; |
| | | this.imgHeight = Number(val.height) || IMG_SIZE; |
| | | let use2d = true; |
| | | // #ifndef MP-WEIXIN |
| | | use2d = false; |
| | | // #endif |
| | | // if(use2d && (this.imgWidth > 1365 || this.imgHeight > 1365)) { |
| | | // use2d = false; |
| | | // } |
| | | let canvansWidth = this.imgWidth; |
| | | let canvansHeight = this.imgHeight; |
| | | let size = Math.max(canvansWidth, canvansHeight) |
| | | let scalc = 1; |
| | | if(size > 1365) { |
| | | scalc = 1365 / size; |
| | | } |
| | | this.canvansWidth = canvansWidth * scalc; |
| | | this.canvansHeight = canvansHeight * scalc; |
| | | this.use2d = use2d; |
| | | this.initArea(); |
| | | val.src && this.initImage(val.src); |
| | | }, |
| | | immediate: true |
| | | }, |
| | | }, |
| | | methods: { |
| | | open() { |
| | | this.show = true |
| | | }, |
| | | close() { |
| | | this.show = false |
| | | }, |
| | | /** æä¾ç»wxsè°ç¨ï¼ç¨æ¥æ¥æ¶å¾çåæ´æ°æ® */ |
| | | dataChange(e) { |
| | | // console.log('dataChange', e) |
| | | this.scaleWidth = e.width; |
| | | this.scaleHeight = e.height; |
| | | this.rotate = e.rotate; |
| | | this.offsetX = e.x; |
| | | this.offsetY = e.y; |
| | | }, |
| | | /** åå§åè£åªåºåå¸å±ä¿¡æ¯ */ |
| | | initArea() { |
| | | // åºé¨æä½æ é«åº¦ = åºé¨åºé¨æä½æ å
容é«åº¦ + 设å¤åºé¨å®å
¨åºåé«åº¦ |
| | | this.sys.offsetBottom = uni.upx2px(100) + this.sys.safeAreaInsets.bottom; |
| | | // #ifndef H5 |
| | | this.sys.windowTop = 0; |
| | | this.sys.navigation = true; |
| | | // #endif |
| | | // #ifdef H5 |
| | | // h5å¹³å°ççªå£é«åº¦æ¯å
嫿 颿 ç |
| | | this.sys.windowTop = this.sys.windowTop || 44; |
| | | this.sys.navigation = this.navigation; |
| | | // #endif |
| | | let wp = this.widthPercent; |
| | | let hp = this.heightPercent; |
| | | if (this.imgWidth > this.imgHeight) { |
| | | hp = hp * this.imgHeight / this.imgWidth; |
| | | } else if (this.imgWidth < this.imgHeight) { |
| | | wp = wp * this.imgWidth / this.imgHeight; |
| | | } |
| | | const size = this.sys.windowWidth > this.sys.windowHeight ? this.sys.windowHeight : this.sys.windowWidth; |
| | | const width = size * wp / 100; |
| | | const height = size * hp / 100; |
| | | const left = (this.sys.windowWidth - width) / 2; |
| | | const right = left + width; |
| | | const top = (this.sys.windowHeight + this.sys.windowTop - this.sys.offsetBottom - height) / 2; |
| | | const bottom = this.sys.windowHeight + this.sys.windowTop - this.sys.offsetBottom - top; |
| | | this.area = { width, height, left, right, top, bottom }; |
| | | this.scaleWidth = width; |
| | | this.scaleHeight = height; |
| | | }, |
| | | /** 仿¬å°éåå¾ç */ |
| | | chooseImage() { |
| | | // #ifdef MP-WEIXIN || MP-JD |
| | | if(uni.chooseMedia) { |
| | | uni.chooseMedia({ |
| | | count: 1, |
| | | mediaType: ['image'], |
| | | success: (res) => { |
| | | this.resetData(); |
| | | this.initImage(res.tempFiles[0].tempFilePath); |
| | | } |
| | | }); |
| | | return; |
| | | } |
| | | // #endif |
| | | uni.chooseImage({ |
| | | count: 1, |
| | | success: (res) => { |
| | | this.resetData(); |
| | | this.initImage(res.tempFiles[0].path); |
| | | } |
| | | }); |
| | | }, |
| | | /** éç½®æ°æ® */ |
| | | resetData() { |
| | | this.imgSrc = ''; |
| | | this.rotate = 0; |
| | | this.offsetX = 0; |
| | | this.offsetY = 0; |
| | | this.initArea(); |
| | | }, |
| | | /** |
| | | * åå§åå¾çä¿¡æ¯ |
| | | * @param {String} url å¾ç龿¥ |
| | | */ |
| | | initImage(url) { |
| | | uni.getImageInfo({ |
| | | src: url, |
| | | success: (res) => { |
| | | this.imgSrc = res.path; |
| | | let scale = res.width / res.height; |
| | | let areaScale = this.area.width / this.area.height; |
| | | if (scale > 1) { // 横åå¾ç |
| | | if (scale >= areaScale) { // å¾ç宽ä¸å°äºç®æ 宽ï¼åé«åºå®ï¼å®½èªéåº |
| | | this.scaleWidth = (this.scaleHeight / res.height) * this.scaleWidth * (res.width / this.scaleWidth); |
| | | } else { // å¦å宽åºå®ãé«èªéåº |
| | | this.scaleHeight = res.height * this.scaleWidth / res.width; |
| | | } |
| | | } else { // 纵åå¾ç |
| | | if (scale <= areaScale) { // å¾çé«ä¸å°äºç®æ é«ï¼å®½åºå®ï¼é«èªéåº |
| | | this.scaleHeight = (this.scaleWidth / res.width) * this.scaleHeight / (this.scaleHeight / res.height); |
| | | } else { // å¦åé«åºå®ï¼å®½èªéåº |
| | | this.scaleWidth = res.width * this.scaleHeight / res.height; |
| | | } |
| | | } |
| | | // è®°å½åå§å®½é«ï¼ä¸ºç¼©æ¾æ¯ååéå¶ |
| | | this.oldWidth = this.scaleWidth; |
| | | this.oldHeight = this.scaleHeight; |
| | | }, |
| | | fail: (err) => { |
| | | console.error(err) |
| | | } |
| | | }); |
| | | }, |
| | | /** |
| | | * åªåå¾çåè§ |
| | | * @param {Object} ctx canvas çç»å¾ä¸ä¸æå¯¹è±¡ |
| | | * @param {Number} radius åè§åå¾ |
| | | * @param {Number} scale çæå¾ççå®é
å°ºå¯¸ä¸æªååºåæ¯ |
| | | * @param {Function} drawImage æ§è¡åªåæ¶æè°ç¨çç»å¾æ¹æ³ï¼å
¥å为æ¯å¦æ§è¡äºåªå |
| | | */ |
| | | drawClipImage(ctx, radius, scale, drawImage) { |
| | | if(radius > 0) { |
| | | ctx.save(); |
| | | ctx.beginPath(); |
| | | const w = this.canvansWidth; |
| | | const h = this.canvansHeight; |
| | | if(w === h && radius >= w / 2) { // åå½¢ |
| | | ctx.arc(w / 2, h / 2, w / 2, 0, 2 * Math.PI); |
| | | } else { // åè§ç©å½¢ |
| | | if(w !== h) { // éå¶åè§åå¾ä¸è½è¶
è¿çè¾¹çä¸å |
| | | radius = Math.min(w / 2, h / 2, radius); |
| | | // radius = Math.min(Math.max(w, h) / 2, radius); |
| | | } |
| | | ctx.moveTo(radius, 0); |
| | | ctx.arcTo(w, 0, w, h, radius); |
| | | ctx.arcTo(w, h, 0, h, radius); |
| | | ctx.arcTo(0, h, 0, 0, radius); |
| | | ctx.arcTo(0, 0, w, 0, radius); |
| | | ctx.closePath(); |
| | | } |
| | | ctx.clip(); |
| | | drawImage && drawImage(true); |
| | | ctx.restore(); |
| | | } else { |
| | | drawImage && drawImage(false); |
| | | } |
| | | }, |
| | | /** |
| | | * æè½¬å¾ç |
| | | * @param {Object} ctx canvas çç»å¾ä¸ä¸æå¯¹è±¡ |
| | | * @param {Number} rotate æè½¬è§åº¦ |
| | | * @param {Number} scale çæå¾ççå®é
å°ºå¯¸ä¸æªååºåæ¯ |
| | | */ |
| | | drawRotateImage(ctx, rotate, scale) { |
| | | if(rotate !== 0) { |
| | | // 1. 以å¾çä¸å¿ç¹ä¸ºæè½¬ä¸å¿ç¹ |
| | | const x = this.scaleWidth * scale / 2; |
| | | const y = this.scaleHeight * scale / 2; |
| | | ctx.translate(x, y); |
| | | // 2. æè½¬ç»å¸ |
| | | ctx.rotate(rotate * Math.PI / 180); |
| | | // 3. æè½¬å®ç»å¸åæ¢å¤è®¾ç½®æè½¬ä¸å¿æ¶æåçåç§» |
| | | ctx.translate(-x, -y); |
| | | } |
| | | }, |
| | | drawImage(ctx, image, callback) { |
| | | // çæå¾ççå®é
å°ºå¯¸ä¸æªååºåæ¯ |
| | | const scale = this.canvansWidth / this.area.width; |
| | | this.drawClipImage(ctx, this.radius, scale, () => { |
| | | this.drawRotateImage(ctx, this.rotate, scale); |
| | | const r = this.rotate / 90; |
| | | ctx.drawImage( |
| | | image, |
| | | [ |
| | | (this.offsetX - this.area.left), |
| | | (this.offsetY - this.area.top), |
| | | -(this.offsetX - this.area.left), |
| | | -(this.offsetY - this.area.top) |
| | | ][r] * scale, |
| | | [ |
| | | (this.offsetY - this.area.top), |
| | | -(this.offsetX - this.area.left), |
| | | -(this.offsetY - this.area.top), |
| | | (this.offsetX - this.area.left) |
| | | ][r] * scale, |
| | | this.scaleWidth * scale, |
| | | this.scaleHeight * scale |
| | | ); |
| | | }); |
| | | }, |
| | | /** |
| | | * ç»å¾ |
| | | * @param {Object} canvas |
| | | * @param {Object} ctx canvas çç»å¾ä¸ä¸æå¯¹è±¡ |
| | | * @param {String} src å¾çè·¯å¾ |
| | | * @param {Function} callback å¼å§ç»å¶æ¶åè° |
| | | */ |
| | | draw2DImage(canvas, ctx, src, callback) { |
| | | // console.log('draw2DImage', canvas, ctx, src, callback) |
| | | if(canvas) { |
| | | const image = canvas.createImage(); |
| | | image.onload = () => { |
| | | this.drawImage(ctx, image); |
| | | // 妿è§å¾`çææ¶é´è¿é¿`æ`åºç°çæå¾ç空ç½`å¯å°è¯è°æ´å»¶è¿æ¶é´ |
| | | callback && setTimeout(callback, this.delay); |
| | | }; |
| | | image.onerror = (err) => { |
| | | console.error(err) |
| | | uni.hideLoading(); |
| | | }; |
| | | image.src = src; |
| | | } else { |
| | | this.drawImage(ctx, src); |
| | | setTimeout(() => { |
| | | ctx.draw(false, callback); |
| | | }, 200); |
| | | } |
| | | }, |
| | | /** |
| | | * ç»å¸è½¬å¾çå°æ¬å°ç¼å |
| | | * @param {Object} canvas |
| | | * @param {String} canvasId |
| | | */ |
| | | canvasToTempFilePath(canvas, canvasId) { |
| | | // console.log('canvasToTempFilePath', canvas, canvasId) |
| | | uni.canvasToTempFilePath({ |
| | | canvas, |
| | | canvasId, |
| | | x: 0, |
| | | y: 0, |
| | | width: this.canvansWidth, |
| | | height: this.canvansHeight, |
| | | destWidth: this.imgWidth, // å¿
è¦ï¼ä¿è¯çæå¾ç宽度ä¸å设å¤å辨çå½±å |
| | | destHeight: this.imgHeight, // å¿
è¦ï¼ä¿è¯çæå¾çé«åº¦ä¸å设å¤å辨çå½±å |
| | | fileType: this.fileType, // ç®æ æä»¶çç±»åï¼é»è®¤png |
| | | success: (res) => { |
| | | // çæçå¾çä¸´æ¶æä»¶è·¯å¾ |
| | | this.handleImage(res.tempFilePath); |
| | | }, |
| | | fail: (err) => { |
| | | uni.hideLoading(); |
| | | uni.showToast({ title: 'è£åªå¤±è´¥ï¼çæå¾çå¼å¸¸ï¼', icon: 'none' }); |
| | | } |
| | | }, this); |
| | | }, |
| | | /** 确认è£åª */ |
| | | cropClick() { |
| | | uni.showLoading({ title: 'è£åªä¸...', mask: true }); |
| | | if(!this.use2d) { |
| | | const ctx = uni.createCanvasContext('imgCanvas', this); |
| | | ctx.clearRect(0, 0, this.canvansWidth, this.canvansHeight); |
| | | this.draw2DImage(null, ctx, this.imgSrc, () => { |
| | | this.canvasToTempFilePath(null, 'imgCanvas'); |
| | | }); |
| | | return; |
| | | } |
| | | // #ifdef MP-WEIXIN |
| | | const query = uni.createSelectorQuery().in(this); |
| | | query.select('#imgCanvas') |
| | | .fields({ node: true, size: true }) |
| | | .exec((res) => { |
| | | const canvas = res[0].node; |
| | | |
| | | const dpr = uni.getSystemInfoSync().pixelRatio; |
| | | canvas.width = res[0].width * dpr; |
| | | canvas.height = res[0].height * dpr; |
| | | const ctx = canvas.getContext('2d'); |
| | | ctx.scale(dpr, dpr); |
| | | ctx.clearRect(0, 0, this.canvansWidth, this.canvansHeight); |
| | | |
| | | this.draw2DImage(canvas, ctx, this.imgSrc, () => { |
| | | this.canvasToTempFilePath(canvas); |
| | | }); |
| | | }); |
| | | // #endif |
| | | }, |
| | | handleImage(tempFilePath){ |
| | | // å¨H5å¹³å°ä¸ï¼tempFilePath 为 base64 |
| | | // console.log(tempFilePath) |
| | | uni.hideLoading(); |
| | | this.$emit('crop', { tempFilePath }); |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .image-cropper { |
| | | position: fixed; |
| | | left: 0; |
| | | right: 0; |
| | | top: 0; |
| | | bottom: 0; |
| | | z-index: 999999; |
| | | overflow: hidden; |
| | | display: flex; |
| | | flex-direction: column; |
| | | background-color: #000; |
| | | .img-canvas { |
| | | position: absolute !important; |
| | | transform: translateX(-100%); |
| | | } |
| | | .pic-preview { |
| | | width: 100%; |
| | | flex: 1; |
| | | position: relative; |
| | | |
| | | .crop-mask-block { |
| | | background-color: rgba(51, 51, 51, 0.8); |
| | | z-index: 2; |
| | | position: fixed; |
| | | box-sizing: border-box; |
| | | pointer-events: none; |
| | | } |
| | | .crop-circle-box { |
| | | position: fixed; |
| | | box-sizing: border-box; |
| | | z-index: 2; |
| | | pointer-events: none; |
| | | overflow: hidden; |
| | | .crop-circle { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | } |
| | | .crop-image { |
| | | padding: 0 !important; |
| | | margin: 0 !important; |
| | | border-radius: 0 !important; |
| | | display: block !important; |
| | | } |
| | | .crop-border { |
| | | position: fixed; |
| | | border: 1px solid #fff; |
| | | box-sizing: border-box; |
| | | z-index: 3; |
| | | pointer-events: none; |
| | | } |
| | | .crop-grid { |
| | | position: fixed; |
| | | z-index: 3; |
| | | border-style: dashed; |
| | | border-color: #fff; |
| | | pointer-events: none; |
| | | opacity: 0.5; |
| | | } |
| | | .crop-angle { |
| | | position: fixed; |
| | | z-index: 3; |
| | | border-style: solid; |
| | | border-color: #fff; |
| | | pointer-events: none; |
| | | } |
| | | } |
| | | |
| | | .fixed-bottom { |
| | | position: fixed; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | z-index: 99; |
| | | display: flex; |
| | | flex-direction: row; |
| | | background-color: $uni-bg-color-grey; |
| | | |
| | | .rotate-icon { |
| | | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAABCFJREFUaEPtml3IpVMUx3//ko/ChTIyiGFSMyhllI8bc4F85yuNC2FCqLmQC1+FZORiEkUMNW7UjKjJULgxV+NzSkxDhEkZgwsyigv119J63p7zvOc8z37OmXdOb51dz82711r7/99r7bXXXucVi3xokeNnRqCvB20fDmwAlgK/5bcD+FTSr33tHXQP2H4MeHQE0A+B5yRtLiUyDQJrgVc6AAaBpyV93kXkoBMIQLbfBS5NcK8BRwDXNcD+AdwnaVMbiWkRCPBBohpxHuK7M7865sclRdgNHVMhkF6IMIpwirFEUhzo8M7lwIvASTXEqyVtH8ZgagQSbOzsDknv18HZXpHn5IL8+94IOUm7miSmSqAttjPdbgGuTrnNktYsGgLpoYuAD2qg1zRTbG8P2D4SOC6/Q7vSHPALsE/S7wWy80RsPw/ckxMfSTq/LtRJwPbxwF3ASiCUTxwHCPAnEBfVF8AWSTtL7Ng+LfWOTfmlkn6udFsJ5K15R6a4kvX6yGyUFBvTOWzHXXFzCt4g6c1OArYj9iIGh43YgR+BvztXh1PSa4cMkd0jaVmXDduPAE+k3HpJD7cSGFKvfAc8FQUX8IOk/V2L1udtB/hTgdOBW4Aba/M7Ja1qs2f7euCNlHlZUlx4/495IWQ7Jl+qGbxX0gt9AHfJ2o6zFBVoNVrDKe+F3Sm8VdK1bQQ+A85JgXckXdkFaJx527cC9TpnVdvBtl3h2iapuhsGPdBw1b9xnUvaNw7AEh3bnwDnpuwGSfeP0rN9NvAMELXRXFkxEEK2nwQeSiOtRVQJwC4Z29cAW1Nuu6TVXTrN+SaBt4ErUug2Sa/2NdhH3vZy4NvU2S/p6D768w5xI3WOrAD7LtISFpGdIhVXKfaYvjd20wP13L9M0p4DBbaFRKToSLExVkr6qs+aIwlI6iwz+izUQqC+ab29PiMwqRcmPXczD8w8MFj1zg7xXEqbpdHCw7FgWSjafZL+KcQxtpjteCeflwYulFR/J3TabSslVkj6utPChAK2f6q9uZdLitKieLQRuExSvX9ZbLRUMFs09efpUZL+KtUfVo1GW/umNHC3pOhRLtiwfSbwZS6wV9IJfRdreuBBYH0a2STp9r4G+8jbXgc8mzoDT8VSO00ClwDv1ZR7XyylC4ec7ejaLUmdsV6Aw7oSbwFXpdFdks7qA6pU1na0aR6owgeIR/1cx63UzjAC0YXYVjMQHlkn6ZtSo21ytuPZGKFagQ/xsXZ/3iGuFrYdjafXG0DiQMeBi47c9/GV3BO247UV38n5o0UAP6xmu7jFOGxjRr66On5NPBDOCBsDTapxjHY1dyOcolNXnYlx1himE53p2PmNkxosevfavhg4Izt2k7TXPwZ2S6p6QZPin/2rwcQ7OKmBohCadJGF1P8PG6aaQBKVX/8AAAAASUVORK5CYII='); |
| | | background-size: 60% 60%; |
| | | background-repeat: no-repeat; |
| | | background-position:center; |
| | | width: 80rpx; |
| | | height: 80rpx; |
| | | position: absolute; |
| | | top: -90rpx; |
| | | left: 10rpx; |
| | | transform: rotateY(180deg); |
| | | } |
| | | |
| | | .rechoose { |
| | | color: $uni-color-primary; |
| | | padding: 0 $uni-spacing-row-lg; |
| | | line-height: 100rpx; |
| | | } |
| | | |
| | | .choose-btn { |
| | | color: $uni-color-primary; |
| | | text-align: center; |
| | | line-height: 100rpx; |
| | | flex: 1; |
| | | } |
| | | |
| | | .button { |
| | | margin: auto $uni-spacing-row-lg auto auto; |
| | | background-color: $uni-color-primary; |
| | | color: #fff; |
| | | } |
| | | } |
| | | |
| | | .safe-area-inset-bottom { |
| | | padding-bottom: 0; |
| | | padding-bottom: constant(safe-area-inset-bottom); // å
¼å®¹ IOS<11.2 |
| | | padding-bottom: env(safe-area-inset-bottom); // å
¼å®¹ IOS>=11.2 |
| | | } |
| | | |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | /** |
| | | * å¾çç¼è¾å¨-æå¿çå¬ |
| | | * 1. wxs æä¸æ¯æ es6 è¯æ³ |
| | | * 2. æ¯æç¼è¯å°å¾®ä¿¡å°ç¨åºãQQå°ç¨åºãapp-vueãH5ä¸ï¼uni-app 2.2.5å以ä¸çæ¬ï¼ |
| | | */ |
| | | /** å¾çåç§»é */ |
| | | var offset = { x: 0, y: 0 }; |
| | | /** å¾çç¼©æ¾æ¯ä¾ */ |
| | | var scale = 1; |
| | | /** å¾çæå°ç¼©æ¾æ¯ä¾ */ |
| | | var minScale = 1; |
| | | /** å¾çæè½¬è§åº¦ */ |
| | | var rotate = 0; |
| | | /** 触æ¸ç¹ */ |
| | | var touches = []; |
| | | /** å¾çå¸å±ä¿¡æ¯ */ |
| | | var img = {}; |
| | | /** ç³»ç»ä¿¡æ¯ */ |
| | | var sys = {}; |
| | | /** è£åªåºåå¸å±ä¿¡æ¯ */ |
| | | var area = {}; |
| | | /** 触æ¸è¡ä¸ºç±»å */ |
| | | var touchType = ''; |
| | | /** æä½è§çä½ç½® */ |
| | | var activeAngle = 0; |
| | | /** è£åªåºåå¸å±ä¿¡æ¯åç§»é */ |
| | | var areaOffset = { left: 0, right: 0, top: 0, bottom: 0 }; |
| | | /** |
| | | * 计ç®ä¸¤ç¹é´è· |
| | | * @param {Object} touches 触æ¸ç¹ä¿¡æ¯ |
| | | */ |
| | | function getDistanceByTouches(touches) { |
| | | // æ ¹æ®å¾è¡å®çæ±ä¸¤ç¹é´è·ç¦» |
| | | var a = touches[1].pageX - touches[0].pageX; |
| | | var b = touches[1].pageY - touches[0].pageY; |
| | | var c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2)); |
| | | // æ±ä¸¤ç¹é´çä¸ç¹åæ |
| | | // 1. aãbå¯è½ä¸ºè´å¼ |
| | | // 2. 卿±aãbæ¶ï¼å¦ç¨touches[1]åtouches[0]ï¼åæ±ä¸ç¹åæ ä¹å¾ç¨touches[1]åa/2ãb/2 |
| | | // 3. åçï¼å¨æ±aãbæ¶ï¼ä¹å¯ç¨touches[0]åtouches[1]ï¼åæ±ä¸ç¹åæ ä¹å¾ç¨touches[0]åa/2ãb/2 |
| | | var x = touches[1].pageX - a / 2; |
| | | var y = touches[1].pageY - b / 2; |
| | | return { c, x, y }; |
| | | }; |
| | | /** |
| | | * æ£æ¥è¾¹çï¼éå¶ xãy æå¨èå´ï¼ç¦æ¢æ»åºè¾¹ç |
| | | * @param {Object} e ç¹åæ |
| | | */ |
| | | function checkRange(e) { |
| | | var r = rotate / 90 % 2; |
| | | if(r === 1) { // å å¾ç宽é«å¯è½ä¸çï¼ç¿»è½¬ 90° æ 270° åå¾ç宽é«éåç计ç®ï¼ä¸å·¦å³åä¸ä¸è¾¹çè¦æ ¹æ®å·®å¼ååç§» |
| | | var o = (img.height - img.width) / 2; // 宽é«å·®å¼ä¸å |
| | | return { |
| | | x: Math.min(Math.max(e.x, -img.height + o + area.width + area.left), area.left + o), |
| | | y: Math.min(Math.max(e.y, -img.width - o + area.height + area.top), area.top - o) |
| | | } |
| | | } |
| | | return { |
| | | x: Math.min(Math.max(e.x, -img.width + area.width + area.left), area.left), |
| | | y: Math.min(Math.max(e.y, -img.height + area.height + area.top), area.top) |
| | | } |
| | | }; |
| | | /** |
| | | * åæ´å¾çå¸å±ä¿¡æ¯ |
| | | * @param {Object} e å¸å±ä¿¡æ¯ |
| | | */ |
| | | function changeImageRect(e) { |
| | | offset.x += e.x || 0; |
| | | offset.y += e.y || 0; |
| | | var image = e.instance.selectComponent('.crop-image'); |
| | | if(e.check) { // æ£æ¥è¾¹ç |
| | | var point = checkRange(offset); |
| | | if(offset.x !== point.x || offset.y !== point.y) { |
| | | offset = point; |
| | | } |
| | | } |
| | | // image.setStyle({ |
| | | // width: img.width + 'px', |
| | | // height: img.height + 'px', |
| | | // transform: 'translate(' + offset.x + 'px, ' + offset.y + 'px) rotate(' + rotate +'deg)' |
| | | // }); |
| | | var ox = (img.width - img.oldWidth) / 2; |
| | | var oy = (img.height - img.oldHeight) / 2; |
| | | image.setStyle({ |
| | | width: img.oldWidth + 'px', |
| | | height: img.oldHeight + 'px', |
| | | transform: 'translate(' + (offset.x + ox) + 'px, ' + (offset.y + oy) + 'px) rotate(' + rotate +'deg) scale(' + scale + ')' |
| | | }); |
| | | |
| | | e.instance.callMethod('dataChange', { |
| | | width: img.width, |
| | | height: img.height, |
| | | x: offset.x, |
| | | y: offset.y, |
| | | rotate: rotate |
| | | }); |
| | | }; |
| | | /** |
| | | * åæ´è£åªåºåå¸å±ä¿¡æ¯ |
| | | * @param {Object} e å¸å±ä¿¡æ¯ |
| | | */ |
| | | function changeAreaRect(e) { |
| | | // åæ´èçæ ·å¼ |
| | | var masks = e.instance.selectAllComponents('.crop-mask-block'); |
| | | var maskStyles = [ |
| | | { |
| | | left: 0, |
| | | width: (area.left + areaOffset.left) + 'px', |
| | | top: 0, |
| | | bottom: 0, |
| | | }, |
| | | { |
| | | left: (area.right + areaOffset.right) + 'px', |
| | | right: 0, |
| | | top: 0, |
| | | bottom: 0, |
| | | }, |
| | | { |
| | | left: (area.left + areaOffset.left) + 'px', |
| | | width: (area.width + areaOffset.right - areaOffset.left) + 'px', |
| | | top: 0, |
| | | height: (area.top + areaOffset.top) + 'px', |
| | | }, |
| | | { |
| | | left: (area.left + areaOffset.left) + 'px', |
| | | width: (area.width + areaOffset.right - areaOffset.left) + 'px', |
| | | top: (area.bottom + areaOffset.bottom) + 'px', |
| | | // height: (area.top - areaOffset.bottom + sys.offsetBottom) + 'px', |
| | | bottom: 0, |
| | | } |
| | | ]; |
| | | var len = masks.length; |
| | | for (var i = 0; i < len; i++) { |
| | | masks[i].setStyle(maskStyles[i]); |
| | | } |
| | | |
| | | // åæ´è¾¹æ¡æ ·å¼ |
| | | if(area.showBorder) { |
| | | var border = e.instance.selectComponent('.crop-border'); |
| | | border.setStyle({ |
| | | left: (area.left + areaOffset.left) + 'px', |
| | | top: (area.top + areaOffset.top) + 'px', |
| | | width: (area.width + areaOffset.right - areaOffset.left) + 'px', |
| | | height: (area.height + areaOffset.bottom - areaOffset.top) + 'px', |
| | | }); |
| | | } |
| | | |
| | | // åæ´åèçº¿æ ·å¼ |
| | | if(area.showGrid) { |
| | | var grids = e.instance.selectAllComponents('.crop-grid'); |
| | | var gridStyles = [ |
| | | { |
| | | 'border-width': '1px 0 0 0', |
| | | left: (area.left + areaOffset.left) + 'px', |
| | | right: (area.right + areaOffset.right) + 'px', |
| | | top: (area.top + areaOffset.top + (area.height + areaOffset.bottom - areaOffset.top) / 3 - 0.5) + 'px', |
| | | width: (area.width + areaOffset.right - areaOffset.left) + 'px' |
| | | }, |
| | | { |
| | | 'border-width': '1px 0 0 0', |
| | | left: (area.left + areaOffset.left) + 'px', |
| | | right: (area.right + areaOffset.right) + 'px', |
| | | top: (area.top + areaOffset.top + (area.height + areaOffset.bottom - areaOffset.top) * 2 / 3 - 0.5) + 'px', |
| | | width: (area.width + areaOffset.right - areaOffset.left) + 'px' |
| | | }, |
| | | { |
| | | 'border-width': '0 1px 0 0', |
| | | top: (area.top + areaOffset.top) + 'px', |
| | | bottom: (area.bottom + areaOffset.bottom) + 'px', |
| | | left: (area.left + areaOffset.left + (area.width + areaOffset.right - areaOffset.left) / 3 - 0.5) + 'px', |
| | | height: (area.height + areaOffset.bottom - areaOffset.top) + 'px' |
| | | }, |
| | | { |
| | | 'border-width': '0 1px 0 0', |
| | | top: (area.top + areaOffset.top) + 'px', |
| | | bottom: (area.bottom + areaOffset.bottom) + 'px', |
| | | left: (area.left + areaOffset.left + (area.width + areaOffset.right - areaOffset.left) * 2 / 3 - 0.5) + 'px', |
| | | height: (area.height + areaOffset.bottom - areaOffset.top) + 'px' |
| | | } |
| | | ]; |
| | | var len = grids.length; |
| | | for (var i = 0; i < len; i++) { |
| | | grids[i].setStyle(gridStyles[i]); |
| | | } |
| | | } |
| | | |
| | | // åæ´åä¸ªä¼¸ç¼©è§æ ·å¼ |
| | | if(area.showAngle) { |
| | | var angles = e.instance.selectAllComponents('.crop-angle'); |
| | | var angleStyles = [ |
| | | { |
| | | 'border-width': area.angleBorderWidth + 'px 0 0 ' + area.angleBorderWidth + 'px', |
| | | left: (area.left + areaOffset.left - area.angleBorderWidth) + 'px', |
| | | top: (area.top + areaOffset.top - area.angleBorderWidth) + 'px', |
| | | }, |
| | | { |
| | | 'border-width': area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px 0 0', |
| | | left: (area.right + areaOffset.right - area.angleSize) + 'px', |
| | | top: (area.top + areaOffset.top - area.angleBorderWidth) + 'px', |
| | | }, |
| | | { |
| | | 'border-width': '0 0 ' + area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px', |
| | | left: (area.left + areaOffset.left - area.angleBorderWidth) + 'px', |
| | | top: (area.bottom + areaOffset.bottom - area.angleSize) + 'px', |
| | | }, |
| | | { |
| | | 'border-width': '0 ' + area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px 0', |
| | | left: (area.right + areaOffset.right - area.angleSize) + 'px', |
| | | top: (area.bottom + areaOffset.bottom - area.angleSize) + 'px', |
| | | } |
| | | ]; |
| | | var len = angles.length; |
| | | for (var i = 0; i < len; i++) { |
| | | angles[i].setStyle(angleStyles[i]); |
| | | } |
| | | } |
| | | |
| | | // åæ´åè§æ ·å¼ |
| | | if(area.radius > 0) { |
| | | var circleBox = e.instance.selectComponent('.crop-circle-box'); |
| | | var circle = e.instance.selectComponent('.crop-circle'); |
| | | var radius = area.radius; |
| | | if(area.width === area.height && area.radius >= area.width / 2) { // åå½¢ |
| | | radius = (area.width / 2); |
| | | } else { // åè§ç©å½¢ |
| | | if(area.width !== area.height) { // éå¶åè§åå¾ä¸è½è¶
è¿çè¾¹çä¸å |
| | | radius = Math.min(area.width / 2, area.height / 2, radius); |
| | | } |
| | | } |
| | | circleBox.setStyle({ |
| | | left: (area.left + areaOffset.left) + 'px', |
| | | top: (area.top + areaOffset.top) + 'px', |
| | | width: (area.width + areaOffset.right - areaOffset.left) + 'px', |
| | | height: (area.height + areaOffset.bottom - areaOffset.top) + 'px' |
| | | }); |
| | | circle.setStyle({ |
| | | 'box-shadow': '0 0 0 ' + Math.max(area.width, area.height) + 'px rgba(51, 51, 51, 0.8)', |
| | | 'border-radius': radius + 'px' |
| | | }); |
| | | } |
| | | }; |
| | | /** |
| | | * 缩æ¾å¾ç |
| | | * @param {Object} e å¸å±ä¿¡æ¯ |
| | | */ |
| | | function scaleImage(e) { |
| | | var last = scale; |
| | | scale = Math.min(Math.max(e.scale + scale, minScale), img.maxScale); |
| | | if(last !== scale) { |
| | | img.width = img.oldWidth * scale; |
| | | img.height = img.oldHeight * scale; |
| | | // åèé®é¢ï¼æä¸ä¸ªé¿4000pxã宽4000pxç忹形ABCDï¼Aç¹çåæ åºå®å¨(-2000,-2000)ï¼ |
| | | // 该åè¾¹å½¢ä¸æä¸ä¸ªç¹Eï¼åæ 为(-100,-300)ï¼å°è¯¥åæ¹å½¢å¤å¶ä¸ä»½å¹¶ç¼©å°å°90%åï¼ |
| | | // æ°å边形çAç¹åæ 为å¤å°æ¶å¯ä½¿æ°å边形çEç¹ä¸åå边形çEç¹éåï¼ |
| | | // 颿ææï¼ä»å¾ä¸éåæç¹ï¼åç
§ç©ï¼ä¸ºä¸å¿ç¹è¿è¡ç¼©æ¾ï¼ç¼©æ¾æ¶æ 论å¾åæä¹ååï¼è¯¥ç¹ä½ç½®å§ç»åºå®ä¸å |
| | | // è®¡ç®æ¹æ³ï¼ä»¥ç¸åèµ·ç¹å
计ç®ç¼©æ¾åå两ç¹é´çè·ç¦»ï¼åå ä¸åå¾ååç§»éå³å¯ |
| | | e.x = (e.x - offset.x) * (1 - scale / last); |
| | | e.y = (e.y - offset.y) * (1 - scale / last); |
| | | changeImageRect(e); |
| | | return true; |
| | | } |
| | | return false; |
| | | }; |
| | | /** |
| | | * è·å触æ¸ç¹å¨åªä¸ªè§ |
| | | * @param {number} x 触æ¸ç¹xè½´åæ |
| | | * @param {number} y 触æ¸ç¹yè½´åæ |
| | | * @return {number} è§çä½ç½®ï¼0=æ ï¼1=å·¦ä¸ï¼2=å³ä¸ï¼3=å·¦ä¸ï¼4=å³ä¸ï¼ |
| | | */ |
| | | function getToucheAngle(x, y) { |
| | | // console.log('getToucheAngle', x, y, JSON.stringify(area)) |
| | | var o = area.angleBorderWidth; // éæ©å¤§è§¦åèå´åæ o å¼å 大å³å¯ |
| | | if(y >= area.top - o && y <= area.top + area.angleSize + o) { |
| | | if(x >= area.left - o && x <= area.left + area.angleSize + o) { |
| | | return 1; // å·¦ä¸è§ |
| | | } else if(x >= area.right - area.angleSize - o && x <= area.right + o) { |
| | | return 2; // å³ä¸è§ |
| | | } |
| | | } else if(y >= area.bottom - area.angleSize - o && y <= area.bottom + o) { |
| | | if(x >= area.left - o && x <= area.left + area.angleSize + o) { |
| | | return 3; // å·¦ä¸è§ |
| | | } else if(x >= area.right - area.angleSize - o && x <= area.right + o) { |
| | | return 4; // å³ä¸è§ |
| | | } |
| | | } |
| | | return 0; // æ 触æ¸å°è§ |
| | | }; |
| | | /** |
| | | * éç½®æ°æ® |
| | | */ |
| | | function resetData() { |
| | | offset = { x: 0, y: 0 }; |
| | | scale = 1; |
| | | minScale = 1; |
| | | rotate = 0; |
| | | }; |
| | | module.exports = { |
| | | /** |
| | | * åå§åï¼è§å¯æ°æ®åæ´ |
| | | * @param {Object} newVal æ°æ°æ® |
| | | * @param {Object} oldVal æ§æ°æ® |
| | | * @param {Object} o ç»ä»¶å®ä¾å¯¹è±¡ |
| | | */ |
| | | initObserver: function(newVal, oldVal, o, i) { |
| | | if(newVal) { |
| | | img = newVal.img; |
| | | sys = newVal.sys; |
| | | area = newVal.area; |
| | | resetData(); |
| | | img.src && changeImageRect({ |
| | | instance: o, |
| | | x: (sys.windowWidth - img.width) / 2, |
| | | y: (sys.windowHeight - sys.offsetBottom - img.height) / 2 |
| | | }); |
| | | changeAreaRect({ |
| | | instance: o |
| | | }); |
| | | // console.log('initRect', JSON.stringify(newVal)) |
| | | } |
| | | }, |
| | | /** |
| | | * é¼ æ æ»è½®æ»å¨ |
| | | * @param {Object} e äºä»¶å¯¹è±¡ |
| | | * @param {Object} o ç»ä»¶å®ä¾å¯¹è±¡ |
| | | */ |
| | | mousewheel: function(e, o) { |
| | | if(!img.src) return; |
| | | scaleImage({ |
| | | instance: o, |
| | | check: true, |
| | | // é¼ æ å䏿»å¨æ¶ï¼deltaY åºå® -100ï¼é¼ æ å䏿»å¨æ¶ï¼deltaY åºå® 100 |
| | | scale: e.detail.deltaY > 0 ? -0.05 : 0.05, |
| | | x: e.touches[0].pageX, |
| | | y: e.touches[0].pageY |
| | | }); |
| | | }, |
| | | /** |
| | | * 触æ¸å¼å§ |
| | | * @param {Object} e äºä»¶å¯¹è±¡ |
| | | * @param {Object} o ç»ä»¶å®ä¾å¯¹è±¡ |
| | | */ |
| | | touchstart: function(e, o) { |
| | | if(!img.src) return; |
| | | touches = e.touches; |
| | | activeAngle = area.showAngle ? getToucheAngle(touches[0].pageX, touches[0].pageY) : 0; |
| | | if(touches.length === 1 && activeAngle !== 0) { |
| | | touchType = 'stretch'; // 伸缩è£åªåºå |
| | | } else { |
| | | touchType = ''; |
| | | } |
| | | // console.log('touchstart', JSON.stringify(e), activeAngle) |
| | | }, |
| | | /** |
| | | * 触æ¸ç§»å¨ |
| | | * @param {Object} e äºä»¶å¯¹è±¡ |
| | | * @param {Object} o ç»ä»¶å®ä¾å¯¹è±¡ |
| | | */ |
| | | touchmove: function(e, o) { |
| | | if(!img.src) return; |
| | | // console.log('touchmove', JSON.stringify(e), JSON.stringify(o)) |
| | | if(touchType === 'stretch') { // 触æ¸å个è§è¿è¡æä¼¸ |
| | | var point = e.touches[0]; |
| | | var start = touches[0]; |
| | | var x = point.pageX - start.pageX; |
| | | var y = point.pageY - start.pageY; |
| | | if(x !== 0 || y !== 0) { |
| | | var maxX = area.width * (1 - area.minScale); |
| | | var maxY = area.height * (1 - area.minScale); |
| | | // console.log(x, y, maxX, maxY) |
| | | touches[0] = point; |
| | | switch(activeAngle) { |
| | | case 1: // å·¦ä¸è§ |
| | | x += areaOffset.left; |
| | | y += areaOffset.top; |
| | | if(x >= 0 && y >= 0) { // æææ»å¨ |
| | | if(x > y) { // 以xè½´æ»å¨è·ç¦»ä¸ºç¼©æ¾åºå |
| | | if(x > maxX) x = maxX; |
| | | y = x * area.height / area.width; |
| | | } else { // 以yè½´æ»å¨è·ç¦»ä¸ºç¼©æ¾åºå |
| | | if(y > maxY) y = maxY; |
| | | x = y * area.width / area.height; |
| | | } |
| | | areaOffset.left = x; |
| | | areaOffset.top = y; |
| | | } |
| | | break; |
| | | case 2: // å³ä¸è§ |
| | | x += areaOffset.right; |
| | | y += areaOffset.top; |
| | | if(x <= 0 && y >= 0) { // æææ»å¨ |
| | | if(-x > y) { // 以xè½´æ»å¨è·ç¦»ä¸ºç¼©æ¾åºå |
| | | if(-x > maxX) x = -maxX; |
| | | y = -x * area.height / area.width; |
| | | } else { // 以yè½´æ»å¨è·ç¦»ä¸ºç¼©æ¾åºå |
| | | if(y > maxY) y = maxY; |
| | | x = -y * area.width / area.height; |
| | | } |
| | | areaOffset.right = x; |
| | | areaOffset.top = y; |
| | | } |
| | | break; |
| | | case 3: // å·¦ä¸è§ |
| | | x += areaOffset.left; |
| | | y += areaOffset.bottom; |
| | | if(x >= 0 && y <= 0) { // æææ»å¨ |
| | | if(x > -y) { // 以xè½´æ»å¨è·ç¦»ä¸ºç¼©æ¾åºå |
| | | if(x > maxX) x = maxX; |
| | | y = -x * area.height / area.width; |
| | | } else { // 以yè½´æ»å¨è·ç¦»ä¸ºç¼©æ¾åºå |
| | | if(-y > maxY) y = -maxY; |
| | | x = -y * area.width / area.height; |
| | | } |
| | | areaOffset.left = x; |
| | | areaOffset.bottom = y; |
| | | } |
| | | break; |
| | | case 4: // å³ä¸è§ |
| | | x += areaOffset.right; |
| | | y += areaOffset.bottom; |
| | | if(x <= 0 && y <= 0) { // æææ»å¨ |
| | | if(-x > -y) { // 以xè½´æ»å¨è·ç¦»ä¸ºç¼©æ¾åºå |
| | | if(-x > maxX) x = -maxX; |
| | | y = x * area.height / area.width; |
| | | } else { // 以yè½´æ»å¨è·ç¦»ä¸ºç¼©æ¾åºå |
| | | if(-y > maxY) y = -maxY; |
| | | x = y * area.width / area.height; |
| | | } |
| | | areaOffset.right = x; |
| | | areaOffset.bottom = y; |
| | | } |
| | | break; |
| | | } |
| | | // console.log(x, y, JSON.stringify(areaOffset)) |
| | | changeAreaRect({ |
| | | instance: o, |
| | | }); |
| | | // this.draw(); |
| | | } |
| | | } else if (e.touches.length == 2) { // åç¹è§¦æ¸ç¼©æ¾ |
| | | var start = getDistanceByTouches(touches); |
| | | var end = getDistanceByTouches(e.touches); |
| | | scaleImage({ |
| | | instance: o, |
| | | check: !area.bounce, |
| | | scale: (end.c - start.c) / 100, |
| | | x: end.x, |
| | | y: end.y |
| | | }); |
| | | touchType = 'scale'; |
| | | } else if(touchType === 'scale') {// ä»åç¹è§¦æ¸åæåç¹è§¦æ¸ / ä»ç¼©æ¾åææå¨ |
| | | touchType = 'move'; |
| | | } else { |
| | | changeImageRect({ |
| | | instance: o, |
| | | check: !area.bounce, |
| | | x: e.touches[0].pageX - touches[0].pageX, |
| | | y: e.touches[0].pageY - touches[0].pageY |
| | | }); |
| | | touchType = 'move'; |
| | | } |
| | | touches = e.touches; |
| | | }, |
| | | /** |
| | | * 触æ¸ç»æ |
| | | * @param {Object} e äºä»¶å¯¹è±¡ |
| | | * @param {Object} o ç»ä»¶å®ä¾å¯¹è±¡ |
| | | */ |
| | | touchend: function(e, o) { |
| | | if(!img.src) return; |
| | | if(touchType === 'stretch') { // æä¼¸è£åªåºåçå个è§ç¼©æ¾ |
| | | // è£åªåºå宽度被缩æ¾å°å¤å° |
| | | var left = areaOffset.left; |
| | | var right = areaOffset.right; |
| | | var top = areaOffset.top; |
| | | var bottom = areaOffset.bottom; |
| | | var w = area.width + right - left; |
| | | var h = area.height + bottom - top; |
| | | // å¾åæ¾å¤§åæ° |
| | | var p = scale * (area.width / w) - scale; |
| | | // å¤åè£åªåºå |
| | | areaOffset = { left: 0, right: 0, top: 0, bottom: 0 }; |
| | | changeAreaRect({ |
| | | instance: o, |
| | | }); |
| | | scaleImage({ |
| | | instance: o, |
| | | scale: p, |
| | | x: area.left + left + (1 === activeAngle || 3 === activeAngle ? w : 0), |
| | | y: area.top + top + (1 === activeAngle || 2 === activeAngle ? h : 0) |
| | | }); |
| | | } else if (area.bounce) { // æ£æ¥è¾¹çå¹¶ç«æ£ï¼å®ç°æå¨å°è¾¹çæ¶æåå¼¹ææ |
| | | changeImageRect({ |
| | | instance: o, |
| | | check: true |
| | | }); |
| | | } |
| | | }, |
| | | /** |
| | | * 顺æ¶é翻转å¾ç90° |
| | | * @param {Object} e äºä»¶å¯¹è±¡ |
| | | * @param {Object} o ç»ä»¶å®ä¾å¯¹è±¡ |
| | | */ |
| | | rotateImage: function(e, o) { |
| | | rotate = (rotate + 90) % 360; |
| | | |
| | | // å å¾ç宽é«å¯è½ä¸çï¼ç¿»è½¬åå¾ç宽é«éè¶³å¤å¡«æ»¡è£åªåºå |
| | | var r = rotate / 90 % 2; |
| | | minScale = 1; |
| | | if(img.width < area.height) { |
| | | minScale = area.height / img.oldWidth; |
| | | } else if(img.height < area.width) { |
| | | minScale = (area.width / img.oldHeight) |
| | | } |
| | | if(minScale !== 1) { |
| | | scaleImage({ |
| | | instance: o, |
| | | scale: minScale - scale, |
| | | x: sys.windowWidth / 2, |
| | | y: (sys.windowHeight - sys.offsetBottom) / 2 |
| | | }); |
| | | } |
| | | |
| | | // ç±äºæå¨ç»å¸åä¼å¯¼è´å¾çä½ç½®åç§»ï¼ç¿»è½¬æ¶çæè½¬ä¸å¿ç¹éæ¯å¾çåºå+åç§»åºåçä¸å¿ç¹ |
| | | // 翻转xè½´ä¸å¿ç¹ = (è¶
åºè£åªåºåå³ä¾§çå¾ç宽度 - è¶
åºè£åªåºå左侧çå¾ç宽度) / 2 |
| | | // 翻转yè½´ä¸å¿ç¹ = (è¶
åºè£åªåºå䏿¹çå¾ç宽度 - è¶
åºè£åªåºå䏿¹çå¾ç宽度) / 2 |
| | | var ox = ((offset.x + img.width - area.right) - (area.left - offset.x)) / 2; |
| | | var oy = ((offset.y + img.height - area.bottom) - (area.top - offset.y)) / 2; |
| | | changeImageRect({ |
| | | instance: o, |
| | | check: true, |
| | | x: -ox - oy, |
| | | y: -oy + ox |
| | | }); |
| | | }, |
| | | // æ¤å¤åªç¨äºå¯¹é½å
¶ä»å¹³å°ç«¯çæ ·å¼åæ°ï¼é²æ¢å¼å¸¸ï¼æ ä½ç¨ |
| | | imageStyles: {}, |
| | | maskStylesList: [{}, {}, {}, {}], |
| | | borderStyles: {}, |
| | | gridStylesList: [{}, {}, {}, {}], |
| | | angleStylesList: [{}, {}, {}, {}], |
| | | circleBoxStyles: {}, |
| | | circleStyles: {}, |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | { |
| | | "id": "qf-image-cropper", |
| | | "displayName": "å¾çè£åªæä»¶", |
| | | "version": "2.1.6", |
| | | "description": "å¾çè£åªæä»¶ï¼æ¯æèªå®ä¹å°ºå¯¸ãå®ç¹çæ¯ä¾ç¼©æ¾ãæå¨ãå¾ç翻转ãåªååå½¢/åè§å¾çãå®å¶æ ·å¼ï¼åè½å¤æ§è½é«ä½éªå¥½æ³¨éå
¨ã", |
| | | "keywords": [ |
| | | "qf-image-cropper", |
| | | "å¾çè£åª", |
| | | "å¾çç¼è¾", |
| | | "头åè£åª", |
| | | "å°ç¨åº" |
| | | ], |
| | | "repository": "", |
| | | "engines": { |
| | | "HBuilderX": "^3.1.0" |
| | | }, |
| | | "dcloudext": { |
| | | "type": "component-vue", |
| | | "sale": { |
| | | "regular": { |
| | | "price": "0.00" |
| | | }, |
| | | "sourcecode": { |
| | | "price": "0.00" |
| | | } |
| | | }, |
| | | "contact": { |
| | | "qq": "" |
| | | }, |
| | | "declaration": { |
| | | "ads": "æ ", |
| | | "data": "æä»¶ä¸éé任使°æ®", |
| | | "permissions": "æ " |
| | | }, |
| | | "npmurl": "" |
| | | }, |
| | | "uni_modules": { |
| | | "dependencies": [], |
| | | "encrypt": [], |
| | | "platforms": { |
| | | "client": { |
| | | "Vue": { |
| | | "vue2": "y", |
| | | "vue3": "y" |
| | | }, |
| | | "App": { |
| | | "app-vue": "y", |
| | | "app-nvue": "n" |
| | | }, |
| | | "H5-mobile": { |
| | | "Safari": "y", |
| | | "Android Browser": "y", |
| | | "微信æµè§å¨(Android)": "y", |
| | | "QQæµè§å¨(Android)": "u" |
| | | }, |
| | | "H5-pc": { |
| | | "Chrome": "u", |
| | | "IE": "u", |
| | | "Edge": "u", |
| | | "Firefox": "u", |
| | | "Safari": "u" |
| | | }, |
| | | "å°ç¨åº": { |
| | | "微信": "y", |
| | | "é¿é": "n", |
| | | "ç¾åº¦": "n", |
| | | "åèè·³å¨": "n", |
| | | "QQ": "u", |
| | | "éé": "n", |
| | | "å¿«æ": "n", |
| | | "é£ä¹¦": "n", |
| | | "京ä¸": "n" |
| | | }, |
| | | "å¿«åºç¨": { |
| | | "å为": "n", |
| | | "èç": "n" |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # qf-image-cropper |
| | | ## å¾çè£åªæä»¶ |
| | | uniapp微信å°ç¨åºå¾çè£åªæä»¶ï¼æ¯æèªå®ä¹å°ºå¯¸ãå®ç¹çæ¯ä¾ç¼©æ¾ãæå¨ãå¾ç翻转ãåªååå½¢/åè§å¾çãå®å¶æ ·å¼ï¼åè½å¤æ§è½é«ä½éªå¥½æ³¨éå
¨ã |
| | | |
| | | ### 平尿¯æï¼ |
| | | 1. æ¯æå¾®ä¿¡å°ç¨åºï¼ç§»å¨ç«¯ãPC端ãå¼åè
å·¥å
· |
| | | 2. æ¯æH5å¹³å°ï¼2.1.0çæ¬èµ·ï¼ |
| | | 3. æ¯æAPPå¹³å°ï¼2.1.5çæ¬èµ·ï¼ï¼AndroidãIOS |
| | | 4. å
¶ä»å¹³å°ææªæµè¯å
¼å®¹æ§æªç¥ |
| | | |
| | | ### æ¯æåè½ï¼ |
| | | 1. èªå®ä¹è£åªå°ºå¯¸ |
| | | 2. å®ç¹çæ¯ä¾ç¼©æ¾ï¼ç§»å¨ç«¯ä»¥åæè§¦æ¸ä¸å¿ç¹ä¸ºç¼©æ¾ä¸å¿ç¹ï¼PCç«¯ä»¥é¼ æ æå¨ç¹ä¸ºç¼©æ¾ä¸å¿ç¹ |
| | | 3. èªç±æå¨ï¼æ¯æéå¶æ»åºè¾¹çï¼ä¹æ¯æåå¼¹ææï¼æ»å¨æ¶å¯æ»åºè¾¹çï¼éæ¾æ¶åå¼¹å°è¾¹çï¼ |
| | | 4. å¾ç翻转ï¼å¨è£åªå°ºå¯¸é 1:1 çæ
åµä¸ï¼ç¿»è½¬æ¶å®½é«æ æ³éºæ»¡è£åªåºåæ¶ï¼å¾çä¼èªå¨æ¾å¤§å°åé尺寸 |
| | | 5. è£åªçææ°å¾ç |
| | | 6. æ¬å°éæ©å¾ç |
| | | 7. å¯å®å¶æ ·å¼ï¼å¯èªç±éæ©æ¯å¦æ¸²æè£åªè¾¹æ¡ãå¯ä¼¸ç¼©è£åªé¡¶è§ãåè线 |
| | | 8. è£åªåè§å¾çï¼åå½¢ãåè§ç©å½¢ |
| | | |
| | | ### 屿§è¯´æ |
| | | | 屿§å | ç±»å | é»è®¤å¼ | 说æ | |
| | | |:---|:---|:---|:---| |
| | | | src | String | | å¾çèµæºå°å | |
| | | | width | Number | 300 | è£åªå®½åº¦ | |
| | | | height | Number | 300 | è£åªé«åº¦ | |
| | | | showBorder | Boolean | true | æ¯å¦ç»å¶è£åªåºåè¾¹æ¡ | |
| | | | showGrid | Boolean | true | æ¯å¦ç»å¶è£åªåºåç½æ ¼åè线 | |
| | | | showAngle | Boolean | true | æ¯å¦å±ç¤ºåä¸ªæ¯æä¼¸ç¼©çè§ | |
| | | | areaScale | Number | 0.3 | è£åªåºåæå°ç¼©æ¾åæ° | |
| | | | maxScale | Number | 5 | å¾çæå¤§ç¼©æ¾åæ° | |
| | | | bounce | Boolean | true | æ¯å¦æåå¼¹ææï¼æå¨æ¶å¯ä»¥æåºè¾¹çï¼éæ¾æ¶ä¼å¼¹åè¾¹ç | |
| | | | rotatable | Boolean | true | æ¯å¦æ¯æç¿»è½¬ | |
| | | | choosable | Boolean | true | æ¯å¦æ¯æä»æ¬å°éæ©ç´ æ | |
| | | | angleSize | Number | 20 | å个è§å°ºå¯¸ï¼åä½px | |
| | | | angleBorderWidth | Number | 2 | å个è§è¾¹æ¡å®½åº¦ï¼åä½px | |
| | | | radius | Number | | è£åªå¾çåè§åå¾ï¼åä½px | |
| | | | fileType | String | png | çææä»¶çç±»åï¼åªæ¯æ 'jpg' æ 'png'ãé»è®¤ä¸º 'png' | |
| | | | delay | Number | 1000 | å¾çä»ç»å¶å°çææéæ¶é´ï¼åä½ms<br>微信å°ç¨åºå¹³å°ä½¿ç¨ `Canvas 2D` ç»å¶æ¶ææ<br>å¦ç»å¶å¤§å¾æåºç°è£åªå¾ç空ç½çæ
åµåºéå½è°å¤§è¯¥å¼ï¼å `Canvas 2d` éç¨åæ¥ç»å¶ï¼éèªå·±ææ§ç»å¶å®ææ¶é´ | |
| | | | navigation | Boolean | true | 页颿¯å¦æ¯åçæ é¢æ ï¼<br>H5å¹³å°å½ showAngle 为 true æ¶ï¼ä½¿ç¨æä»¶ç页é¢å¨ `page.json` ä¸é
ç½®äº `"navigationStyle": "custom"` æ¶ï¼å¿
须尿¤å¼è®¾ä¸º false ï¼å¦ååä¸ªå¯æä¼¸è§ç触åä½ç½®ä¼æåå·®ã<br>注ï¼å H5å¹³å°ççªå£é«åº¦æ¯å
嫿 颿 çï¼èå±å¹è§¦æ¸ç¹çåæ æ¯ä¸å
å«ç | |
| | | | @crop | EventHandle | | åªè£å®æå触åï¼event = { tempFilePath }ãå¨H5å¹³å°ä¸ï¼tempFilePath 为 base64 | |
| | | |
| | | ### åºæ¬ç¨æ³ |
| | | ``` |
| | | <template> |
| | | <div> |
| | | <qf-image-cropper :width="500" :height="500" :radius="30" @crop="handleCrop"></qf-image-cropper> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import QfImageCropper from '@/components/qf-image-cropper/qf-image-cropper.vue'; |
| | | export default { |
| | | components: { |
| | | QfImageCropper |
| | | }, |
| | | methods: { |
| | | handleCrop(e) { |
| | | uni.previewImage({ |
| | | urls: [e.tempFilePath], |
| | | current: 0 |
| | | }); |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | ``` |
| | | ### 使ç¨è¯´æ |
| | | 1.建议å¨`pages.json`ä¸å°å¼ç¨æä»¶ç页颿·»å ä¸ä¸é
ç½®ç¦æ¢ä¸æå·æ°åç¦æ¢é¡µé¢æ»å¨ï¼é²æ¢åºç°æ§è½æé¡µé¢æå¨çé®é¢ã |
| | | ``` |
| | | { |
| | | "enablePullDownRefresh": false, |
| | | "disableScroll": true |
| | | } |
| | | ``` |
| | | 2.å»ºè®®ä½¿ç¨æ¬æä»¶ä¸è¦è®¾ç½®è¿å¤§å®½é«çç®æ å¾ç尺寸ï¼å»ºè®®1365x1365以å
ï¼å¦åå¯è½ä¼å¯¼è´å¦ä¸é®é¢ï¼ |
| | | ``` |
| | | 1.çé¢å¡é¡¿ï¼å
åå ç¨è¿é« |
| | | 2.çæå¾ç失çï¼æ¨¡ç³ï¼ |
| | | 3.ç¡®å®è£åªåä¸ç´æ¾ç¤º `è£åªä¸...`ï¼è¯¥é®é¢æ¯ç± `uni.canvasToTempFilePath` æ æ³åè°å¯¼è´ï¼ä¸åå¹³å°ä¸å设å¤éå¶å¯è½ææä¸åã |
| | | ``` |
| | | 3.å¦è£åªåçå¾çåå¨åç§»çé®é¢ï¼è¯·æ£æ¥æ¯å¦åèªå·±é¡¹ç®ä¸ç¶ç»ä»¶æå
¨å±æ ·å¼å½±åã |
| | | 4.src屿§è®¾ç½®ç½ç»å¾çæ¶ï¼å¾çèµæºå¿
é¡»æ¯è½è§¦å `getImageInfo` API ç success åè°æå¯ç¨äºæä»¶è£åªãå æ¤å°ç¨åºå¹³å°è·åç½ç»å¾çä¿¡æ¯éå
é
ç½®downloadååç½ååæè½çæã |