vue delaunay实现狗脸变成猫脸变形动画效果代码
代码语言:html
所属分类:动画
代码描述:vue delaunay实现狗脸变成猫脸变形动画效果代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <style> body { margin: 0; font-family: Georgia, sans-serif; background: orange; } body h1 { margin: 0; padding: 1em 0; text-align: center; background: steelblue; color: lightcyan; text-shadow: 0.2em 0.2em 0 rgba(0, 0, 0, 0.2); } body button { padding: 1em; font: inherit; } body footer { padding: 2em 1em; background: orangered; color: lightgoldenrodyellow; } body footer a { color: gold; } #app { text-align: center; padding: .5em 0; background: aliceblue; } #app .group { display: inline-block; vertical-align: top; margin: .5em .8em; } #app .group button { display: block; margin: auto; margin-bottom: .5em; } #app .image-container { position: relative; display: inline-block; background: white; } #app .image-container .draw-area { text-align: left; overflow: hidden; } #app .image-container input { position: absolute; z-index: -1; opacity: 0; width: 0; } #app .image-container input + span { position: relative; display: block; padding: .5em; box-sizing: border-box; background: purple; color: white; cursor: pointer; } #app .image-container input:focus + span, #app .image-container input:active + span, #app .image-container input + span:hover { background: darkviolet; outline: 2px solid violet; } #app #morph { position: relative; display: table; } #app #morph canvas { background: white; } #app #morph canvas + canvas { position: absolute; top: 0; left: 0; } #app .image-container, #app #morph { box-shadow: 0 0 0 1px paleturquoise; } #app svg { position: absolute; top: 0; left: 0; } #app svg .connector { stroke: rgba(30, 144, 255, 0.5); stroke-width: 1; stroke-dasharray: 2; pointer-events: none; } #app svg [data-draggable] { stroke: black; fill: rgba(255, 255, 255, 0.2); fill: url(#point-grad); cursor: move; } #app svg [data-draggable].selected { fill: rgba(255, 255, 0, 0.5); } #app pre { -webkit-box-flex: 1; flex: 1 1 auto; margin: .5em 1em; background: white; color: #888; border: 1px solid gainsboro; overflow: auto; } </style> </head> <body> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/vue@2.6.1.js"></script> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/delaunay-fast.1.js"></script> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/abo-utils.0.3.js"></script> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/drag-tracker.1.js"></script> <h1>HyperMorph 3000™</h1> <svg width="0" height="0" style="position:absolute;"> <defs> <radialGradient id="point-grad"> <stop offset="80%" stop-color="transparent"/> <stop offset="81%" stop-color="white"/> </radialGradient> </defs> </svg> <section id="app"> <div id="prepare" class="group"> <button @click="clear">Clear</button> <div id="image1" class="image-container"> <div class="draw-area" :style="sizer()"> <canvas class="img"></canvas> <triangulator :model="state.tri1" :selected-index="state.selectedIndex" @added="onAdded" @selected="onSelected" @deleted="onDeleted"></triangulator> </div> <label> <input type="file" accept="image/*"> <span>Change image</span> </label> </div> <div id="image2" class="image-container"> <div class="draw-area" :style="sizer()"> <canvas class="img"></canvas> <triangulator :model="state.tri2" :selected-index="state.selectedIndex" @added="onAdded" @selected="onSelected" @deleted="onDeleted"></triangulator> </div> <label> <input type="file" accept="image/*"> <span>Change image</span> </label> </div> </div> <div id="apply" class="group"> <button @click="warp">Morph</button> <div id="morph"> <canvas id="c1" :width="state.size.w" :height="state.size.h"></canvas> <canvas id="c2" :width="state.size.w" :height="state.size.h"></canvas> </div> </div> <!----> <pre>{{ state | prettyCompact }}</pre> </section> <!-- SVG UI --> <script> Vue.component('drag-node', { template: '<circle data-draggable @dragging="onDragging" :cx="absCoord[0]" :cy="absCoord[1]" :r="r" />', props: { r: { default: 16 }, coord: Array, //If 'coord' is relative to some other point: offsetCenter: Array, }, model: { prop: 'coord', event: 'do_it', }, computed: { absCoord() { const point = this.coord, center = this.offsetCenter, absCoord = center ? [ point[0] + center[0], point[1] + center[1] ] : point; return absCoord; }, }, methods: { onDragging(e) { const point = e.detail.pos, center = this.offsetCenter, relCoord = center ? [ point[0] - center[0], point[1] - center[1] ] : point; this.$emit('do_it', relCoord); }, }, }); Vue.component('connector', { template: '<line class="connector" :x1="start[0]" :y1="start[1]" :x2="absEnd[0]" :y2="absEnd[1]" />', props: ['start', 'end', 'endIsRel'], computed: { absEnd() { const start = this.start, end = this.end, absEnd = this.endIsRel ? [ start[0] + end[0], start[1] + end[1] ] : end; return absEnd; } } }); </script> <script> /** * Uses Delaunay triangulation to divide a rectangle into triangles. */ class Triangulator { constructor(size, points) { this.size = size; this.points = points || []; } getEffectivePoints() { const { w, h } = this.size, corners = [ Triangulator.createPoint([0,0]), Triangulator.createPoint([w,0]), Triangulator.createPoint([0,h]), Triangulator.createPoint([w,h]), ]; return corners.concat(this.points.filter(p => !p.toDelete)); } getTriangles(indexes) { const coords = this.getEffectivePoints().map(p => p.coord), triangles = Delaunay.triangulate(coords), trisList = []; //"...it will return you a giant array, arranged in triplets, // representing triangles by indices into the passed array." let a, b, c; for(let i = 0; i < triangles.length; i += 3) { a = triangles[i]; b = triangles[i+1]; c = triangles[i+2]; trisList.push( indexes ? [a, b, c] : [coords[a], coords[b], coords[c]] ); } return trisList; } getEdges() { const drawn = {}, edges = []; function addIfNew(p1, p2) { var key = (p1 < p2) ? (p1 + '_' + p2) : (p2 + '_' + p1); if(drawn[key]) { return; } drawn[key] = true; edges.push([p1, p2]); } this.getTriangles().forEach(t => { addIfNew(t[0], t[1]); addIfNew(t[1], t[2]); addIfNew(t[2], t[0]); }); return edges; } addPoint(coord) { this.points.push(Triangulator.createPoint(coord)); } static createPoint(coord) { return { coord: coord.map(Math.round), //toDelete: false, } } } /** * Renders an image on a canvas, within a maximum bounding box. */ class ImageRenderer { constructor(canvas, onImgLoad) { this.canvas = canvas; const img = this.image = new Image(); img.addEventListener('load', e => { const w = img.naturalWidth, h = img.naturalHeight, aspect = w/h; this.info = { width: w, height: h, aspect, }; onImgLoad(this); }, false); } setSrc(src) { this.image.src = src; } clampSize(maxW, maxH) { const info = this.info; if(!info) { throw new Error(`No size info yet (${this.image.src})`); } const w = info.width, h = info.height, shrinkageW = maxW / w, shrinkageH = maxH / h, shrinkage = Math.min(shrinkageW, shrinkageH), clamped = (shrinkage < 1) ? [w * shrinkage, h * shrinkage] : [w, h]; return clamped; } render(canvSize) { const canvas = this.canvas; if(canvSize) { canvas.width = canvSize[0]; canvas.height = canvSize[1]; } const w = canvas.width, h = canvas.height, [imgW, imgH] = this.clampSize(w, h), padW = (w - imgW) / 2, padH = (h - imgH) / 2; const ctx = canvas.getContext('2d'); ctx.drawImage(this.image, padW, padH, imgW, imgH); } } /** * Draws a warped image on a canvas by comparing a normal and a warped triangulation. */ function warpImage(img, triSource, triTarget, canvas, lerpT) { const um = ABOUtils.Math, uc = ABOUtils.Canvas, ug = ABOUtils.Geom; function drawTriangle(s1, s2, s3, d1, d2, d3) { //TODO: Expand dest ~.5, and source similarly based on area difference.. //Overlap the destination areas a little //to avoid hairline cracks when drawing mulitiple connected triangles. const [d1x, d2x, d3x] = [d1, d2, d3], //ug.expandTriangle(d1, d2, d3, .3), [s1x, s2x, s3x] = [s1, s2, s3]; //ug.expandTriangle(s1, s2, s3, .3); uc.drawImageTriangle(img, ctx, s1x, s2x, s3x, d1x, d2x, d3x, true); } const { w, h } = triTarget.size, ctx = canvas.getContext('2d'), tri1 = triSource.getTriangles(true), tri2 = triTarget.getTriangles(true), co1 = triSource.getEffectivePoints().map(p => p.coord); let co2 = triTarget.getEffectivePoints().map(p => p.coord); if(lerpT || (lerpT === 0)) { co2 = um.lerp(co1, co2, lerpT); } ctx.clearRect(0,0, w,h); tri1.forEach((t1, i) => { const corners1 = t1.map(i => co1[i]), corners2 = t1.map(i => co2[i]); drawTriangle(corners1[0], corners1[1], corners1[2], corners2[0], corners2[1], corners2[2]); }); } (function() { "use strict"; console.clear(); const um = ABOUtils.Math, ud = ABOUtils.DOM, [$, $$] = ud.selectors(); let _loader1, _loader2; const _srcA = 'data:image/jpeg;base64,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.........完整代码请登录后点击上方下载按钮下载查看
网友评论0