js 某宽高(img)以相等的比例缩放至规定的大小
废话在后文讲, 具体的 javascript 实现代码:
1 /* 把 target 以相等的比例缩放至 result 大小 2 target, result: Object{width, height}; //也可以是img元素 3 */ 4 setSizeToSameScale(target, result = {width: 100, height: 100}){ 5 if(!target) return result; 6 7 const width = target.width, 8 height = target.height, 9 ratio = width / height, 10 scale = ratio < 1 ? ratio * result.width / width : result.width / width; 11 12 result.width = width * scale; 13 result.height = height * scale; 14 15 return result; 16 }
思路:
根据 target 与 result 的宽高比计算出 scale
然后 result 的宽高乘以这个 scale 就ok了
这里我用此方法处理某些功能: (空降至 234 行 的
setScaleToSameScaleFromBox 方法
)
这个类不能直接使用, 只当做示例
1 /* CanvasImage 2 parameter: 3 image (构造器会调用一次 .setImage(image) 来处理 image 参数) 4 5 attribute: 6 opacity: Float; //透明度; 值0至1之间; 默认1; 7 visible: Boolean; //默认true; 完全隐藏(既不绘制视图, 也不触发绑定的事件) 8 box: Box; //.x.y 图像的位置, .w.h 图像的宽高; 9 rotate: Roate; //旋转; 默认 null (注意: 旋转的原点是相对于 box.x.y 的) 10 scale: Box; //缩放; .x.y中心点, .w.h缩放; 默认 null; (注意: 缩放的原点是相对于 box.x.y 的) 11 x, y: Number; //this.box 的 .x.y 12 13 //以下属性不建议直接修改 14 overlap: Object; //CanvasImageRender.computeOverlaps(ca) 方法更新 15 index: Integer; //CanvasImageRender.index(ca) 修改 16 17 //只读 18 width, height, image; isRotate, isScale 19 20 method: 21 setImage(image): this; //设置图像 (image 如果是 CanvasImage 并它正在加载图像时, 则会在它加载完成时自动设置 image); 22 load(src, onload): this; //加载并设置图像 (onload 如果是 CanvasImageRender 则加载完后自动调用一次 redraw 或 render 方法); 23 pos(x, y): this; //设置位置; x 可以是: Number, Object{x,y} 24 25 //以nx,ny为原点缩放; ratio 小于1为缩, 大于1是放 26 setScale(nx = 0, ny = 0, ratio = 1): this; 27 28 //设置 this.scale 的宽为 newWidth, 29 //然后以 this.image 的相等比例缩放至 newWidth; 30 //newWidth 默认为 this.box 的宽 31 setScaleToSameScaleFromBox(newWidth): this; 32 33 //设置 this.scale 的位置在 this.box 中居中 34 setScaleToCenterFromBox(): this; 35 36 demo: 37 //CanvasImageRender 38 const cir = new CanvasImageRender({width: WORLD.width, height: WORLD.height}); 39 cir.domElement.style = ` 40 position: absolute; 41 z-index: 9999; 42 background: rgb(127,127,127); 43 `; 44 45 //values 46 const ciA = cir.add(new CanvasImage()).pos(59, 59).load("view/examples/img/test.png", cir); 47 ciA.opacity = 0.2; //设置透明度 48 49 const ciB = cir.add(new CanvasImage(ciA)).pos(59, 120); 50 ciB.rotate = new Rotate().toAngle(45); //旋转45度 51 52 //event 53 const cie = new CanvasImageEvent(cir); //注意: CanvasImage 的缩放和旋转都会影响到 CanvasImageEvent 54 cie.add(ciB, "click", event => { //ciB 添加 点击事件 55 console.log("click ciB: ", event); 56 }); 57 */ 58 class CanvasImage{ 59 60 static bindBox(obj, box){ 61 var _x = box.x, _y = box.y, _w = box.w, _h = box.h, oldV; 62 63 Object.defineProperties(box, { 64 65 x: { 66 get: () => {return _x;}, 67 set: v => { 68 oldV = _x; 69 _x = v; 70 if(obj.writeBoxX !== null) obj.writeBoxX(v+_w, oldV+_w); 71 } 72 }, 73 74 y: { 75 get: () => {return _y;}, 76 set: v => { 77 oldV = _y; 78 _y = v; 79 if(obj.writeBoxY !== null) obj.writeBoxY(v+_h, oldV+_h); 80 } 81 }, 82 83 w: { 84 get: () => {return _w;}, 85 set: v => { 86 oldV = _w; 87 _w = v; 88 if(obj.writeBoxX !== null) obj.writeBoxX(v+_x, oldV+_x); 89 } 90 }, 91 92 h: { 93 get: () => {return _h;}, 94 set: v => { 95 oldV = _h; 96 _h = v; 97 if(obj.writeBoxY !== null) obj.writeBoxY(v+_y, oldV+_y); 98 } 99 }, 100 101 }); 102 } 103 104 #box = new Box(); 105 #image = null; 106 #isLoadImage = false; 107 #__bindObj = { 108 writeBoxX: null, 109 writeBoxY: null, 110 } 111 112 get box(){return this.#box;} 113 get image(){return this.#image;} 114 get isScale(){return this.#image.width !== this.box.w || this.#image.height !== this.box.h;} 115 get width(){return this.#image !== null ? this.#image.width : 0;} 116 get height(){return this.#image !== null ? this.#image.height : 0;} 117 get isLoadImage(){return this.#isLoadImage;} 118 get __bindObj(){return this.#__bindObj;} 119 120 get x(){return this.box.x;} 121 get y(){return this.box.y;} 122 set x(v){this.box.x = v;} 123 set y(v){this.box.y = v;} 124 125 constructor(image){ 126 this.opacity = 1; 127 this.visible = true; 128 this.rotate = null; 129 this.scale = null; 130 131 //以下属性不建议直接修改 132 this.overlap = null; 133 this.index = -1; 134 135 CanvasImage.bindBox(this.#__bindObj, this.#box); 136 this.setImage(image); 137 } 138 139 pos(x, y){ 140 if(UTILS.isNumber(x)){ 141 this.box.x = x; 142 this.box.y = y; 143 } 144 else if(UTILS.isObject(x)){ 145 this.box.x = x.x; 146 this.box.y = x.y; 147 } 148 return this; 149 } 150 151 setImage(image){ 152 if(CanvasImageRender.isCanvasImage(image)){ 153 this.box.size(image.width, image.height); 154 this.#image = image; 155 } 156 else if(CanvasImage.prototype.isPrototypeOf(image)){ 157 if(image.isLoadImage){ 158 if(Array.isArray(image.loadImage_cis)) image.loadImage_cis.push(this); 159 else image.loadImage_cis = [this]; 160 } 161 else this.setImage(image.image); 162 } 163 else{ 164 this.box.size(0, 0); 165 this.#image = null; 166 } 167 return this; 168 } 169 170 loadImage(src, onload){ 171 this.#isLoadImage = true; 172 const image = new Image(); 173 image.onload = () => this._loadSuccess(image, onload); 174 image.src = src; 175 return this; 176 } 177 178 loadVideo(src, onload, type = "mp4"){ 179 /* video 加载事件 的顺序 180 onloadstart 181 ondurationchange 182 onloadedmetadata //元数据加载完成包含: 时长,尺寸大小(视频),文本轨道。 183 onloadeddata 184 onprogress 185 oncanplay 186 oncanplaythrough 187 188 //控制事件: 189 onended //播放结束 190 onpause //暂停播放 191 onplay //开始播放 192 */ 193 this.#isLoadImage = true; 194 const video = document.createElement("video"), 195 source = document.createElement("source"); 196 video.appendChild(source); 197 source.type = `video/${type}`; 198 199 video.onloadedmetadata = () => { 200 //video 的 width, height 属性如果不设的话永远都是0 201 video.width = video.videoWidth; 202 video.height = video.videoHeight; 203 this._loadSuccess(video, onload); 204 }; 205 206 source.src = src; 207 return this; 208 } 209 210 _loadSuccess(image, onload){ 211 this.setImage(image); 212 this.#isLoadImage = false; 213 214 if(Array.isArray(this.loadImage_cis)){ 215 this.loadImage_cis.forEach(ci => ci.setImage(image)); 216 delete this.loadImage_cis; 217 } 218 219 if(typeof onload === "function") onload(this); 220 else if(CanvasImageRender.prototype.isPrototypeOf(onload)){ 221 if(onload.domElement.parentElement !== null) onload.redraw(); 222 else onload.render(); 223 } 224 } 225 226 setScale(nx = 0, ny = 0, ratio = 1){ 227 this.scale.w = this.#box.w * ratio; 228 this.scale.h = this.#box.h * ratio; 229 this.scale.x = nx - ((nx - this.scale.x) * ratio + this.scale.x) + this.scale.x; 230 this.scale.y = ny - ((ny - this.scale.y) * ratio + this.scale.y) + this.scale.y; 231 return this; 232 } 233 234 setScaleToSameScaleFromBox(newWidth = this.#box.w){ 235 if(this.#image === null || this.scale === null) return this; 236 237 const width = this.#image.width, 238 height = this.#image.height, 239 ratio = width / height, 240 scale = ratio < 1 ? ratio * newWidth / width : newWidth / width; 241 242 this.scale.w = width * scale; 243 this.scale.h = height * scale; 244 245 return this; 246 } 247 248 setScaleToCenterFromBox(){ 249 if(this.scale === null) return this; 250 251 this.scale.x = (this.#box.w - this.scale.w) / 2; 252 this.scale.y = (this.#box.h - this.scale.h) / 2; 253 254 return this; 255 } 256 257 }