首页 > 其他分享 >SolidJS-每日小知识(9/24)

SolidJS-每日小知识(9/24)

时间:2024-09-24 19:33:58浏览次数:1  
标签:24 const attr 知识 height width svgSize SolidJS imageSize

对图片指定范围的区域进行填充显示

1 定义变量,svg和image

  // 用于保存SVG元素的引用
  const [svgRef, setSvgRef] = createSignal<SVGSVGElement | null>(null);

  // 图像原始尺寸
  const imageSize = { width: 11920, height: 16850 };
  // 裁剪区域
  const croppedScope = { x: 5000, y: 10000, width: 5000, height: 5000 };
  // SVG显示区域尺寸
  const svgSize = { width: 500, height: 400 };

  // 用于计算当前图像在SVG中的显示区域
  let imageInScopeX, imageInScopeY, imageInScopeW, imageInScopeH;
  // 用于定义裁剪区域
  let clipX, clipY, clipW, clipH;

  // 添加图像元素
  const addImageElement = (g) => {
    g.append('image')
      .attr('href', './src/assets/creatives/page_1_highres.jpg')
      .attr('x', imageInScopeX)
      .attr('y', imageInScopeY)
      .attr('width', imageInScopeW)
      .attr('height', imageInScopeH)
      .attr('clip-path', 'url(#clip)');
  };

  // 在组件挂载时初始化SVG和图像
  onMount(() => {
    const svg = d3.select(svgRef())
      .attr('width', svgSize.width)
      .attr('height', svgSize.height);
  
    // 创建外层g元素
    const outerGroup = svg.append('g').attr('id', 'outerGroup'); // 新增外层 g
  
    // 内部的 g 元素 (现有的 g)
    const innerGroup = outerGroup.append('g').attr('id', 'innerGroup'); // 设置 ID 为 innerGroup
  
    const scale = calculateScale();
    calculateImageAttributes(scale);
    calculateClipAttributes();
  
    addImageElement(innerGroup); // 修改为使用 innerGroup
  });

  // 渲染SVG和按钮
  return (
    <div style={{ display: 'flex', flexDirection: 'column' }}>
      <svg ref={setSvgRef} style={{ border: '1px solid black' }} />
    </div>
  );

2 计算缩放比例,显示区域范围

  // 计算缩放比例
  const calculateScale = () => {
    const imageW2H = imageSize.width / imageSize.height;
    const svgW2H = svgSize.width / svgSize.height;

    return imageW2H > svgW2H 
      ? svgSize.width / imageSize.width 
      : svgSize.height / imageSize.height;
  };

  // 根据缩放比例计算图像显示属性
  const calculateImageAttributes = (scale) => {
    imageInScopeW = imageSize.width * scale;
    imageInScopeH = imageSize.height * scale;
    imageInScopeX = (svgSize.width - imageInScopeW) / 2;
    imageInScopeY = (svgSize.height - imageInScopeH) / 2;
  };

  // 计算裁剪区域属性
  const calculateClipAttributes = () => {
    clipX = imageInScopeX + (croppedScope.x / imageSize.width) * imageInScopeW;
    clipY = imageInScopeY + (croppedScope.y / imageSize.height) * imageInScopeH;
    clipW = (croppedScope.width / imageSize.width) * imageInScopeW;
    clipH = (croppedScope.height / imageSize.height) * imageInScopeH;
  };

  // 应用缩放和平移变换
  const applyTransformations = (g) => {
    const zoomScaleWidth = svgSize.width / clipW; 
    const zoomScaleHeight = svgSize.height / clipH;
    const zoomScale = Math.min(zoomScaleWidth, zoomScaleHeight);

    g.attr("transform", `scale(${zoomScale}) translate(-${clipX}, -${clipY})`);
  };

  // 添加裁剪路径
  const addClipPath = (g) => {
    g.append('defs').append('clipPath')
      .attr('id', 'clip')
      .append('rect')
      .attr('x', clipX)
      .attr('y', clipY)
      .attr('width', clipW)
      .attr('height', clipH);
  };

对图片进行旋转

1 定义信号量

const [angle, setAngle] = createSignal(0);

2 定义相应函数

  // 旋转图像
  const rotateG = () => {
    const g = d3.select(svgRef()).select('#innerGroup'); // 使用 ID 选择 innerGroup
    const currentAngle = angle();
    const newAngle = currentAngle + 90;

    const zoomScaleWidth = svgSize.width / clipW;
    const zoomScaleHeight = svgSize.height / clipH;
    const zoomScale = Math.min(zoomScaleWidth, zoomScaleHeight);

    g.attr('transform', `rotate(${newAngle}, ${svgSize.width / 2}, ${svgSize.height / 2}) scale(${zoomScale}) translate(-${clipX}, -${clipY})`);
    setAngle(newAngle);
  };

3 绑定到按钮中

<button onClick={rotateG}>旋转图像</button>

绑定zoom事件

技巧:当svg中某元素已经绑定了缩放、拖拽等事件,可在这些元素外包裹一层g元素,对g元素进行的zoom操作不会和其中元素已定义的zoom操作相冲突

1 导入d3-zoom

import { zoom } from 'd3-zoom';

2 包裹新的g元素

const outerGroup = svg.append('g').attr('id', 'outerGroup'); // 新增外层 g

3 添加zoom事件监听器,绑定到svg中

// 添加缩放事件监听器
const zoomBehavior = zoom()
.scaleExtent([0.5, 5]) // 设置缩放范围
.on('zoom', (event) => {
  outerGroup.attr('transform', event.transform); // 应用缩放变换
});

svg.call(zoomBehavior); // 将缩放行为应用到SVG元素

完整代码

import { createSignal, onMount } from 'solid-js';
import * as d3 from 'd3';
import { zoom } from 'd3-zoom';

// 图像加载器组件
const ImageLoader = () => {
  // 用于保存SVG元素的引用
  const [svgRef, setSvgRef] = createSignal<SVGSVGElement | null>(null);
  // 保存当前旋转角度
  const [angle, setAngle] = createSignal(0);

  // 图像原始尺寸
  const imageSize = { width: 11920, height: 16850 };
  // 裁剪区域
  const croppedScope = { x: 5000, y: 10000, width: 5000, height: 5000 };
  // SVG显示区域尺寸
  const svgSize = { width: 500, height: 400 };

  // 用于计算当前图像在SVG中的显示区域
  let imageInScopeX, imageInScopeY, imageInScopeW, imageInScopeH;
  // 用于定义裁剪区域
  let clipX, clipY, clipW, clipH;

  // 计算缩放比例
  const calculateScale = () => {
    const imageW2H = imageSize.width / imageSize.height;
    const svgW2H = svgSize.width / svgSize.height;

    return imageW2H > svgW2H 
      ? svgSize.width / imageSize.width 
      : svgSize.height / imageSize.height;
  };

  // 根据缩放比例计算图像显示属性
  const calculateImageAttributes = (scale) => {
    imageInScopeW = imageSize.width * scale;
    imageInScopeH = imageSize.height * scale;
    imageInScopeX = (svgSize.width - imageInScopeW) / 2;
    imageInScopeY = (svgSize.height - imageInScopeH) / 2;
  };

  // 计算裁剪区域属性
  const calculateClipAttributes = () => {
    clipX = imageInScopeX + (croppedScope.x / imageSize.width) * imageInScopeW;
    clipY = imageInScopeY + (croppedScope.y / imageSize.height) * imageInScopeH;
    clipW = (croppedScope.width / imageSize.width) * imageInScopeW;
    clipH = (croppedScope.height / imageSize.height) * imageInScopeH;
  };

  // 应用缩放和平移变换
  const applyTransformations = (g) => {
    const zoomScaleWidth = svgSize.width / clipW; 
    const zoomScaleHeight = svgSize.height / clipH;
    const zoomScale = Math.min(zoomScaleWidth, zoomScaleHeight);

    g.attr("transform", `scale(${zoomScale}) translate(-${clipX}, -${clipY})`);
  };

  // 添加图像元素
  const addImageElement = (g) => {
    g.append('image')
      .attr('href', './src/assets/creatives/_1.jpg')
      .attr('x', imageInScopeX)
      .attr('y', imageInScopeY)
      .attr('width', imageInScopeW)
      .attr('height', imageInScopeH)
      .attr('clip-path', 'url(#clip)');
  };

  // 添加裁剪路径
  const addClipPath = (g) => {
    g.append('defs').append('clipPath')
      .attr('id', 'clip')
      .append('rect')
      .attr('x', clipX)
      .attr('y', clipY)
      .attr('width', clipW)
      .attr('height', clipH);
  };

  // 在组件挂载时初始化SVG和图像
  onMount(() => {
    const svg = d3.select(svgRef())
      .attr('width', svgSize.width)
      .attr('height', svgSize.height);
  
    // 创建外层g元素
    const outerGroup = svg.append('g').attr('id', 'outerGroup'); // 新增外层 g
  
    // 内部的 g 元素 (现有的 g)
    const innerGroup = outerGroup.append('g').attr('id', 'innerGroup'); // 设置 ID 为 innerGroup
  
    const scale = calculateScale();
    calculateImageAttributes(scale);
    calculateClipAttributes();
  
    addImageElement(innerGroup); // 修改为使用 innerGroup
    addClipPath(innerGroup); // 修改为使用 innerGroup
    applyTransformations(innerGroup); // 修改为使用 innerGroup

    // 添加缩放事件监听器
    const zoomBehavior = zoom()
    .scaleExtent([0.5, 5]) // 设置缩放范围
    .on('zoom', (event) => {
      outerGroup.attr('transform', event.transform); // 应用缩放变换
    });

    svg.call(zoomBehavior); // 将缩放行为应用到SVG元素
  });
  

  // 旋转图像
  const rotateG = () => {
    const g = d3.select(svgRef()).select('#innerGroup'); // 使用 ID 选择 innerGroup
    const currentAngle = angle();
    const newAngle = currentAngle + 90;

    const zoomScaleWidth = svgSize.width / clipW;
    const zoomScaleHeight = svgSize.height / clipH;
    const zoomScale = Math.min(zoomScaleWidth, zoomScaleHeight);

    g.attr('transform', `rotate(${newAngle}, ${svgSize.width / 2}, ${svgSize.height / 2}) scale(${zoomScale}) translate(-${clipX}, -${clipY})`);
    setAngle(newAngle);
  };

  // 渲染SVG和按钮
  return (
    <div style={{ display: 'flex', flexDirection: 'column' }}>
      <button onClick={rotateG}>旋转图像</button>
      <svg ref={setSvgRef} style={{ border: '1px solid black' }} />
    </div>
  );
};

export default ImageLoader;

标签:24,const,attr,知识,height,width,svgSize,SolidJS,imageSize
From: https://www.cnblogs.com/Frey-Li/p/18429867

相关文章

  • 2024.9.24 思维导图与PDF
    哈哈哈终于有我也用过的东西啦~Xmind一款打工人用了都说好的软件(#.#)【知识小课堂1】不同款式的思维导图:【知识小课堂2】PDF转换器!1、PDF(便携式文档格式),这种文件格式与操作系统平台无关——PDF文件不管是在Windows还是别的操作系统中都是通用的。2、这一特点使它成为在I......
  • 计算机知识科普问答--16(76-80)
    文章目录76、什么是处理机调度?调度算法主要有哪几种?1.**处理机调度(ProcessorScheduling)**2.**处理机调度的分类**3.**常见的调度算法**(1)**先来先服务(First-Come,First-Served,FCFS)**(2)**短作业优先(ShortestJobFirst,SJF)**(3)**优先级调度(PrioritySch......
  • 【软考机考问答】—2024软考机考时间注意事项
    一、2024各地软考机考报名时间地区      报名时间 报名入口  免费题库  备考培训广东8月21日9:00-8月29日17:00报名入口免费题库备考培训江西8月20日9:00-9月13日17:00报名入口 免费题库备考培训安徽8月23日9:00-9月3日16:00报名入口免费题库备考培训甘肃8月26......
  • 2024 天池云原生编程挑战赛决赛名单出炉,冠军来自中山大学、昆仑数智战队
    9月20日,2024天池云原生编程挑战赛决赛答辩完美落幕,12支进入决赛的团队用精彩的答辩,为历时3个月的大赛画下了圆满的句号。其中,来自中山大学的陈泓仰以及来自昆仑数智的冉旭欣、沈鑫糠、武鹏鹏,以出色的方案、创新的优化思路、过硬的技术实力分获赛道一和赛道二的冠军。赛道一......
  • 2024 天池云原生编程挑战赛决赛名单出炉,冠军来自中山大学、昆仑数智战队
    9月20日,2024天池云原生编程挑战赛决赛答辩完美落幕,12支进入决赛的团队用精彩的答辩,为历时3个月的大赛画下了圆满的句号。其中,来自中山大学的陈泓仰以及来自昆仑数智的冉旭欣、沈鑫糠、武鹏鹏,以出色的方案、创新的优化思路、过硬的技术实力分获赛道一和赛道二的冠军。赛道......
  • 2024.9.24
    下周这时候我就回家了啊。国庆后大概就得寒假再回去了,要连着在宿舍呆三个月。有点害怕国庆结束后万一撑不下去怎么办,不过应该不会那么脆弱吧。高代课感觉啥都没讲,就是很重要但太基础的东西嘛。我其实不太懂这些交换律结合律啊之类的东西,是直接背下来每个结构有啥样的性质,还是......
  • Vue router 4 基础知识讲解
    1.Vuerouter4基础在构建现代Web应用时,单页应用(SPA)因其流畅的用户体验和快速的页面切换能力,成为了众多项目的首选架构。然而,在SPA中,随着应用功能的日益复杂,权限控制成为了一个不可忽视的问题。如何确保不同用户只能访问其被授权的资源,是保障应用安全和数据一致性的......
  • 中秋献礼!2024年中科院一区极光优化算法+分解对比!VMD-PLO-Transformer-LSTM多变量时间
    中秋献礼!2024年中科院一区极光优化算法+分解对比!VMD-PLO-Transformer-LSTM多变量时间序列光伏功率预测目录中秋献礼!2024年中科院一区极光优化算法+分解对比!VMD-PLO-Transformer-LSTM多变量时间序列光伏功率预测效果一览基本介绍程序设计参考资料效果一览基本介绍1.中秋献礼!2024年......
  • 论文速递!Knowledge-driven+Informer! 联合知识和数据驱动的混合模型,用于NOx排放浓度预
    论文标题:PredictionofNOxemissionconcentrationfromcoal-firedpowerplantbasedonjointknowledgeanddatadriven期刊信息:Energy(中科院1区,JCRQ1TOP,IF=9)引用:WuZ,ZhangY,DongZ.PredictionofNOxemissionconcentrationfromcoal-firedpowerplantbas......
  • Wordpress Plugins插件巡礼 [Updated: 2024-09-24]
    1.0前言因玩startup比賽,所以用到很多low-code和Wordpressplugins來建立網站/APP。有些工具確真提高了生產力,很符合我的“低投入高產出”風格,因此在這總結一下很好用的Wordpress plugins。2.0 wordpressstartertemplatewordpress有很多免費又好看的模板,用來快速建立自己......