精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

圖形編輯器開發(fā):參考線吸附效功能,讓圖形自動(dòng)對(duì)齊

開發(fā) 前端
參考線吸附的實(shí)現(xiàn),就是找出最近的垂直線和水平線,計(jì)算出OffsetX 和 OffsetY,修正被移動(dòng)圖形的 x 和 y,并記錄并繪制出最終重合的參考線。

最近我給圖形編輯器增加了參照線吸附功能,講講我的實(shí)現(xiàn)思路。

我正在開發(fā)的圖形設(shè)計(jì)工具:

https://github.com/F-star/suika

線上體驗(yàn):

https://blog.fstars.wang/app/suika/

效果是被移動(dòng)的圖形會(huì)參考周圍圖形,自動(dòng)與它們進(jìn)行吸附對(duì)齊。

不得不說,很酷炫。

感覺這個(gè)圖形編輯器突然變得靈動(dòng)起來,有了靈魂一般。

為什么需要參照線吸附功能?

這里的參照線,指的是在移動(dòng)目標(biāo)圖形時(shí),當(dāng)靠近其他圖形的包圍盒的延長(zhǎng)線(看不見)時(shí),會(huì)(1)繪制出最近的延長(zhǎng)線和延長(zhǎng)線上的點(diǎn),(2)并將目標(biāo)圖形吸附上去,輕松實(shí)現(xiàn)(3)對(duì)齊的效果。

可以看到,通過參照線,我們很容易就能實(shí)現(xiàn)各種對(duì)齊,比如兩圖形的底邊和定邊對(duì)齊、右下角和左上角對(duì)齊。

這在 以對(duì)齊為基本要素 的視覺設(shè)計(jì)中,是非常好用的功能。

整體思路

整體思路為:

  • 記錄參照線。
  • 找出目標(biāo)圖形最靠近的水平參照線和垂直參照線。
  • 計(jì)算出偏移值 offsetX、offsetY。
  • 標(biāo)記要繪制的所有參照線段(不是兩端無限延長(zhǎng)的)。
  • 修正圖形的 x、y。
  • 繪制參照線和點(diǎn)。

記錄參照線

首先是確定能夠作為 “參照” 的參照?qǐng)D形。

通常來說,參照?qǐng)D形為視口內(nèi)的圖形,并排除掉被移動(dòng)的目標(biāo)圖形。視口外的圖形通常都不在設(shè)計(jì)師的關(guān)注區(qū)域內(nèi)。

確認(rèn)好參照?qǐng)D形后,計(jì)算出它們的包圍盒(bbox)。

這次的包圍盒有點(diǎn)特殊,要多給一個(gè)中點(diǎn)坐標(biāo),因?yàn)橹芯€也要作為參照線。

接口簽名為:

export interface IBoxWithMid {
  minX: number;
  minY: number;
  midX: number;
  midY: number;
  maxX: number;
  maxY: number;
}

它們組成了參照?qǐng)D形的 8 個(gè)點(diǎn),沿著這些點(diǎn)繪制豎線和橫線,就是被移動(dòng)的目標(biāo)圖形對(duì)應(yīng)要吸附的參照線。

被移動(dòng)的圖形也要計(jì)算包圍盒,并得到 5 個(gè)點(diǎn)。

基于這些點(diǎn)的產(chǎn)生的水平線和垂直線,在靠近參照線時(shí)會(huì)吸附到最近的參照線上,分為水平移動(dòng)和垂直移動(dòng)兩個(gè)維度。

編輯器上的效果:

我們首先要把所有的參照線記錄下來,在圖形準(zhǔn)備移動(dòng)(mousedown)的時(shí)候。大致有以下這幾個(gè)操作:

  • 遍歷參照?qǐng)D形(在視口內(nèi),且不為被移動(dòng)目標(biāo)圖形);
  • 計(jì)算出它們的包圍盒,得到 8 個(gè)點(diǎn),3 條垂直線和 3 條水平線。在一條垂直線上的多個(gè)點(diǎn),其 x 值是相同的,y 不同,我們 x 作為 key,y 的數(shù)組為 value,保存到 hLineMap 映射對(duì)象中。每一項(xiàng)代表一條垂直線;
  • 水平線同理,保存在 vLineMap 中。
  • 然后對(duì)這兩個(gè) map 的 key 保存到 sortedXs 或 sortedYs 數(shù)組中,并排序,方便之后二分查找提高查找效率。

抽象一個(gè) RefLine(參照線)類。

interface IVerticalLine { // 有多個(gè)端點(diǎn)的垂直線
  x: number;
  ys: number[];
}

interface IHorizontalLine { // 有多個(gè)端點(diǎn)的水平線
  y: number;
  xs: number[];
}


class RefLine {
  // 參照?qǐng)D形產(chǎn)生的垂直參照線,y 相同(作為 key),x 值不同(作為 value)
  private hLineMap = new Map<number, number[]>();
  // 參照?qǐng)D形產(chǎn)生的水平照線,x 相同(作為 key),y 值不同(作為 value)
  private vLineMap = new Map<number, number[]>(); 

  // 對(duì) hLineMap 的 key 排序,方便高效二分查找,找到最近的線
  private sortedXs: number[] = []; 
  // 對(duì) vLineMap 的 key 排序
  private sortedYs: number[] = []; 

  private toDrawVLines: IVerticalLine[] = []; // 等待繪制的垂直參照線
  private toDrawHLines: IHorizontalLine[] = []; // 等待繪制的水平參照線

  constructor(private editor: Editor) {}

  cacheXYToBbox() {
    this.clear();

    const hLineMap = this.hLineMap;
    const vLineMap = this.vLineMap;

    const selectIdSet = this.editor.selectedElements.getIdSet();
    const viewportBbox = this.editor.viewportManager.getBbox2();
    for (const graph of this.editor.sceneGraph.children) {
      // 排除掉被移動(dòng)的圖形
      if (selectIdSet.has(graph.id)) {
        continue;
      }

      const bbox = bboxToBboxWithMid(graph.getBBox2());
      // 排除在視口外的圖形
      if (!isRectIntersect2(viewportBbox, bbox)) {
        continue;
      }
   
      // 將參照?qǐng)D形記錄下來
   
      // 這里是水平線,特點(diǎn)是 x 相同。
      this.addBboxToMap(hLineMap, bbox.minX, [bbox.minY, bbox.maxY]);
      this.addBboxToMap(hLineMap, bbox.midX, [bbox.minY, bbox.maxY]);
      this.addBboxToMap(hLineMap, bbox.maxX, [bbox.minY, bbox.maxY]);

      this.addBboxToMap(vLineMap, bbox.minY, [bbox.minX, bbox.maxX]);
      this.addBboxToMap(vLineMap, bbox.midY, [bbox.minX, bbox.maxX]);
      this.addBboxToMap(vLineMap, bbox.maxY, [bbox.minX, bbox.maxX]);
    }

    this.sortedXs = Array.from(hLineMap.keys()).sort((a, b) => a - b);
    this.sortedYs = Array.from(vLineMap.keys()).sort((a, b) => a - b);
  }
  
  private addBboxToMap(
    m: Map<number, number[]>,
    xOrY: number,
    xsOrYs: number[],
  ) {
    const line = m.get(xOrY);
    if (line) {
      line.push(...xsOrYs);
    } else {
      m.set(xOrY, [...xsOrYs]);
    }
  }
  
  // ...
}

找出最近參照線

然后是找出目標(biāo)圖形最靠近的水平參照線和垂直參照線。

這一步是在圖形移動(dòng)(mousemove)時(shí)做的,是動(dòng)態(tài)變化的。

首先我們分別找到目標(biāo)圖形的 minX、midX、maxX 的最近垂直參照線,然后計(jì)算出它們各自的絕對(duì)距離,最后找出這里面最小的一個(gè)。

class RefLinet {
  updateRefLine(_targetBbox: IBox2): {
    offsetX: number;
    offsetY: number;
  } {
    // 重置
    this.toDrawVLines = [];
    this.toDrawHLines = [];
    
    // 目標(biāo)對(duì)象的包圍盒,這里補(bǔ)上 midX,midY
    const targetBbox = bboxToBboxWithMid(_targetBbox);

    const hLineMap = this.hLineMap;
    const vLineMap = this.vLineMap;
    const sortedXs = this.sortedXs;
    const sortedYs = this.sortedYs;

    // 一個(gè)參照?qǐng)D形都沒有,結(jié)束
    if (sortedXs.length === 0 && sortedYs.length === 0) {
      return { offsetX: 0, offsetY: 0 };
    }

    // 如果 offsetX 到最后還是 undefined,說明沒有找到最靠近的垂直參照線
    let offsetX: number | undefined = undefined;
    let offsetY: number | undefined = undefined;

    // 分別找到目標(biāo)圖形的 minX、midX、maxX 的最近垂直參照線
    const closestMinX = getClosestValInSortedArr(sortedXs, targetBbox.minX);
    const closestMidX = getClosestValInSortedArr(sortedXs, targetBbox.midX);
    const closestMaxX = getClosestValInSortedArr(sortedXs, targetBbox.maxX);

    // 分別計(jì)算出距離
    const distMinX = Math.abs(closestMinX - targetBbox.minX);
    const distMidX = Math.abs(closestMidX - targetBbox.midX);
    const distMaxX = Math.abs(closestMaxX - targetBbox.maxX);

    // 找到最近距離
    const closestXDist = Math.min(distMinX, distMidX, distMaxX);
    
    // y 同理
  }
}

這里有一個(gè)比較重要的算法,就是找出排序數(shù)組中,離目標(biāo)值最近的數(shù)組元素。

該算法為二分查找的變體,雖然原理不復(fù)雜,但一次能寫對(duì)卻不容易。這里我是找 gpt 幫我寫的,非常完美。

實(shí)現(xiàn)如下:

const getClosestValInSortedArr = (
  sortedArr: number[],
  target: number,
) => {
  if (sortedArr.length === 0) {
    throw new Error('sortedArr can not be empty');
  }
  if (sortedArr.length === 1) {
    return sortedArr[0];
  }

  let left = 0;
  let right = sortedArr.length - 1;

  while (left <= right) {
    const mid = Math.floor((left + right) / 2);

    if (sortedArr[mid] === target) {
      return sortedArr[mid];
    } else if (sortedArr[mid] < target) {
      left = mid + 1;
    } else {
      right = mid - 1;
    }
  }

  // check if left or right is out of bound
  if (left >= sortedArr.length) {
    return sortedArr[right];
  }
  if (right < 0) {
    return sortedArr[left];
  }

  // check which one is closer
  return Math.abs(sortedArr[right] - target) <=
    Math.abs(sortedArr[left] - target)
    ? sortedArr[right]
    : sortedArr[left];
};

計(jì)算偏移值

前面我們得到了最小距離 closestXDist。

接著我們要判斷其是否小于一個(gè)特定的臨界值 tol。不可能你離著十米開外,移動(dòng)一下就千里迢迢吸附過來了吧。

如果滿足,在臨界值內(nèi),我們就繼續(xù)。

offsetX 還差一步就能算出來了:確定正負(fù),因?yàn)?closestXDist 是一個(gè)絕對(duì)值,不能直接用。

那我們就拿這個(gè)最小距離和之前計(jì)算出的三個(gè)距離 distMinX、distMidX、distMaxX對(duì)比,找到相等的,就能計(jì)算出 offsetX 了。

const isEqualNum = (a: number, b: number) => Math.abs(a - b) < 0.00001;
    
const tol = 5 / zoom; // 最小距離不能超過這個(gè)

// 確認(rèn)偏移值 offsetX
if (closestXDist <= tol) {
  // 這里考慮了一下浮點(diǎn)數(shù)誤差
  if (isEqualNum(closestXDist, distMinX)) {
    offsetX = closestMinX - targetBbox.minX;
  } else if (isEqualNum(closestXDist, distMidX)) {
    offsetX = closestMidX - targetBbox.midX;
  } else if (isEqualNum(closestXDist, distMaxX)) {
    offsetX = closestMaxX - targetBbox.maxX;
  } else {
    throw new Error('it should not reach here, please put a issue to us');
  }
}

offsetY 同理,不贅述。

標(biāo)記需繪制參照線段

計(jì)算出了 offsetX 和 offsetY。

接下來要修正一下我們的 targetBbox。

const correctedTargetBbox = { ...targetBbox };
if (offsetX !== undefined) {
  correctedTargetBbox.minX += offsetX;
  correctedTargetBbox.midX += offsetX;
  correctedTargetBbox.maxX += offsetX;
}
if (offsetY !== undefined) {
  correctedTargetBbox.minY += offsetY;
  correctedTargetBbox.midY += offsetY;
  correctedTargetBbox.maxY += offsetY;
}

修正后的目標(biāo)圖形的包圍盒,它的邊就和一些參照線發(fā)生了對(duì)齊。

對(duì)齊的參照線,可能一條沒有,可能只有一條,也可能有最多的 6 條。

基于新的目標(biāo)圖形,我們來找它落在的參照線有哪些。

// offsetX 不為 undefined,說明落在了臨界值內(nèi)
if (offsetX !== undefined) {
  /*************** 左垂直的參考線 ************/
  // 對(duì)比 “offset” 和 “離 minX 最近的垂直線到 minX 的距離(不是絕對(duì)值)”
  if (isEqualNum(offsetX, closestMinX - targetBbox.minX)) {
    // 創(chuàng)建一個(gè)垂直線對(duì)象(特點(diǎn)是這些點(diǎn)的 x 相同)
    const vLine: IVerticalLine = {
      x: closestMinX,
      ys: [],
    };

    // 修正后的目標(biāo)圖形的對(duì)應(yīng)點(diǎn)。
    vLine.ys.push(correctedTargetBbox.minY);
    vLine.ys.push(correctedTargetBbox.maxY);
    // 參照?qǐng)D形上的點(diǎn)
    vLine.ys.push(...hLineMap.get(closestMinX)!);

    // 添加到 “待繪制垂線集合”
    this.toDrawVLines.push(vLine);
  }
  /*************** 中間垂直的參考線 ************/
  if (isEqualNum(offsetX, closestMidX - targetBbox.midX)
  ) {
    const vLine: IVerticalLine = {
      x: closestMidX,
      ys: [],
    };

    vLine.ys.push(correctedTargetBbox.midY);
    vLine.ys.push(...hLineMap.get(closestMidX)!);

    this.toDrawVLines.push(vLine);
  }
  /*************** 右垂直的參考線 ************/
  // ...
}

// 水平線同理
if (offsetY !== undefined) {
  /*************** 上水平的參考線 ************/
  /*************** 中間水平的參考線 ************/
  /*************** 下水平的參考線 ************/
}

修正圖形的 x、y

計(jì)算出的 offsetX 和 offsetY,記得拿去修正被移動(dòng)目標(biāo)圖形的 x 和 y。

const onMousemove = (e) => {
  // ...

  const { offsetX, offsetY } = this.editor.refLine.updateRefLine(
    bboxToBbox2(this.editor.selectedElements.getBBox()!),
  );

  // 修正
  for (let i = 0, len = selectedElements.length; i < len; i++) {
    selectedElements[i].x = startPoints[i].x + dx + offsetX;
    selectedElements[i].y = startPoints[i].y + dy + offsetY;
  }
}

繪制參照線和點(diǎn)

最后是繪制參照線,以繪制垂直線為例。

for (const vLine of this.toDrawVLines) {
  let minY = Infinity;
  let maxY = -Infinity;

  // 這個(gè)是世界坐標(biāo)系轉(zhuǎn)視口坐標(biāo)系
  const { x } = this.editor.sceneCoordsToViewport(vLine.x, 0);
  
  // 遍歷繪制點(diǎn)
  for (const y_ of vLine.ys) {
    // TODO: optimize
    const { y } = this.editor.sceneCoordsToViewport(0, y_);
    minY = Math.min(minY, y);
    maxY = Math.max(maxY, y);

    // 可能有重復(fù)的點(diǎn),用備忘錄排除掉
    const key = `${x},${y}`;
    if (pointsSet.has(key)) {
      continue;
    }
    pointsSet.add(key);

    // 繪制點(diǎn)
    drawXShape(ctx, x, y, pointSize);
  }

  // 所有點(diǎn)中的 minY 和 maxY,繪制線段
  drawLine(ctx, x, minY, x, maxY);
}

水平線同理。

優(yōu)化點(diǎn)

  • 這里的實(shí)現(xiàn),在圖形有旋轉(zhuǎn)角度的時(shí)候,參照線會(huì)過多顯得冗余,可以精簡(jiǎn)一些,減少要對(duì)比的參照線。
  • 對(duì)齊到像素網(wǎng)格的時(shí)候,包圍盒的值要取整。
  • 考慮和按住 Shift 固定 x 或 y 平移的情況,此時(shí)有一個(gè) offset 不能去進(jìn)行校正。

最后

總結(jié)一下,參考線吸附的實(shí)現(xiàn),就是找出最近的垂直線和水平線,計(jì)算出 offsetX 和 offsetY,修正被移動(dòng)圖形的 x 和 y,并記錄并繪制出最終重合的參考線。

另外很感謝 Github Copilot,幫我寫了很多模板代碼。如果讓我自己復(fù)制然后改改的話,很容易寫錯(cuò)。

責(zé)任編輯:姜華 來源: 前端西瓜哥
相關(guān)推薦

2023-04-07 08:02:30

圖形編輯器對(duì)齊功能

2023-10-19 10:12:34

圖形編輯器開發(fā)縮放圖形

2023-09-07 08:24:35

圖形編輯器開發(fā)繪制圖形工具

2023-08-31 11:32:57

圖形編輯器contain

2023-02-01 09:21:59

圖形編輯器標(biāo)尺

2023-02-02 14:07:00

圖形編輯器Canvas

2023-09-26 07:39:21

2023-04-10 08:45:44

圖形編輯器排列移動(dòng)功能

2024-01-08 08:30:05

光標(biāo)圖形編輯器開發(fā)游標(biāo)

2023-09-11 09:02:31

圖形編輯器模塊間的通信

2023-10-10 16:04:30

圖形編輯器格式轉(zhuǎn)換

2023-10-08 08:11:40

圖形編輯器快捷鍵操作

2023-08-28 08:10:50

Hex圖形編輯器

2023-02-09 07:02:30

圖形編輯器修改圖形

2023-02-06 16:59:57

Canvas編輯器

2023-01-18 08:30:40

圖形編輯器元素

2023-07-07 13:56:01

圖形編輯器畫布縮放

2024-01-03 08:43:17

圖形編輯器旋轉(zhuǎn)控制點(diǎn)縮放控制點(diǎn)

2023-05-09 08:15:32

圖形編輯器撤銷重做功能

2023-06-12 08:22:56

圖形編輯器工具
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

麻豆映画在线观看| 成人精品一区二区三区| 日韩人妻无码一区二区三区| 偷拍视频一区二区三区| 国产精品高潮久久久久无| 亚洲自拍偷拍在线| 影音先锋在线国产| 亚洲国产日韩欧美在线| 亚洲国产成人精品久久| 韩国日本美国免费毛片| 日本高清在线观看| 国产蜜臀av在线一区二区三区| 亚洲精品国产美女| 成人观看免费完整观看| 国产激情视频在线观看| 久久久久国产免费免费| 91久久国产自产拍夜夜嗨| 中文字幕av影院| 欧美一区二区| 亚洲国产精品久久久久久| 欧美精品videosex极品1| 亚洲欧美日韩中文在线制服| 91视频免费版污| 毛片网站在线看| 国产精品麻豆欧美日韩ww| 激情伦成人综合小说| 国产精品无码免费播放| 久久久xxx| 午夜免费在线观看精品视频| 艳妇荡乳欲伦69影片| 久操国产精品| 亚洲精品第一国产综合精品| 三级网站免费看| 欧美美女福利视频| 日本久久一区二区三区| 免费在线a视频| 国内高清免费在线视频| 亚洲免费观看高清完整版在线观看 | 91精品国产综合久久久久久丝袜| 一级片黄色录像| 亚洲电影一级片| 亚洲第一免费播放区| 伊人五月天婷婷| 精品123区| 色老汉一区二区三区| 久久久亚洲精品无码| a级片在线免费| 亚洲视频一区二区在线| 亚洲一区二区在线免费观看| 91在线不卡| 欧美激情综合五月色丁香小说| 成人h猎奇视频网站| 中国女人一级一次看片| 石原莉奈在线亚洲二区| 51午夜精品视频| 国产成人在线播放视频| 在线视频观看日韩| 韩国19禁主播vip福利视频| 麻豆91精品91久久久| 国产一区二区三区四区老人| 欧美成人一区在线| 青娱乐在线视频免费观看| 中文字幕亚洲综合久久五月天色无吗''| 精品国产凹凸成av人导航| 国产探花一区二区三区| 伊人久久影院| 亚洲精品av在线| www.av欧美| 欧美日韩有码| 中文字幕亚洲无线码a| 欧美日韩生活片| 香蕉久久网站| 欧美第一页在线| 亚洲男人的天堂在线视频| 国产精品va| 97视频在线免费观看| 亚洲天堂视频网站| 男人的天堂亚洲一区| 成人有码在线播放| 免费观看国产视频| 国产欧美一区二区三区在线老狼| 国产精品9999久久久久仙踪林| 波多野结衣毛片| 免费一级片91| 成人信息集中地欧美| 亚洲成人第一区| www日韩大片| 亚洲图片都市激情| 日本aa在线| 色婷婷精品大在线视频| 国产性生活一级片| 久久九九热re6这里有精品| 亚洲欧美日韩在线一区| 国产精品白丝喷水在线观看| 亚洲日本久久| 国产日韩精品在线播放| 成人免费公开视频| 中文字幕不卡在线| www.好吊操| 国产精品蜜月aⅴ在线| 欧美变态tickling挠脚心| 亚洲一区二区三区蜜桃| 国产精品第十页| 国产精品久久久久久久久久尿| 国产成人在线免费视频| 麻豆精品在线视频| 久久er99热精品一区二区三区 | 美女18一级毛片一品久道久久综合| 一区二区三区色| 黄色a级片免费| 日本免费精品| 最近2019中文字幕大全第二页| 97人妻精品一区二区免费| 欧美3p在线观看| 欧美亚洲伦理www| 国产高中女学生第一次| 久久久www成人免费无遮挡大片| 欧美日韩无遮挡| 欧美人与动牲性行为| 欧美日韩久久久一区| 欧美bbbbb性bbbbb视频| 欧美激情视频一区二区三区在线播放| 久久精品国产亚洲| 在线观看日本网站| 国产69精品一区二区亚洲孕妇| 国产精品中出一区二区三区| freemovies性欧美| 日韩欧美综合在线视频| 91精品又粗又猛又爽| 一区二区三区网站| 国产日韩欧美日韩| 不卡在线视频| 在线亚洲免费视频| 久久久久久久久久久国产精品| 久久av超碰| 国产91ⅴ在线精品免费观看| 亚洲国产日韩在线观看| 一区二区三区不卡视频在线观看 | 日韩精品一区二| 婷婷丁香综合网| 奇米影视一区二区三区小说| 免费亚洲精品视频| 五月天国产在线| 亚洲国产精品一区二区久| 精品一区在线观看视频| 国产一区二区三区观看| 最新欧美日韩亚洲| 日韩电影精品| 精品国偷自产在线视频99| 最新黄色网址在线观看| 欧美国产禁国产网站cc| 欧美精品aaaa| 日本欧美视频| 国产日韩中文字幕在线| 国产在线1区| 欧美成人猛片aaaaaaa| 久久久一二三区| av不卡在线观看| ww国产内射精品后入国产| 欧美人妖视频| 国产999精品久久久| 精品无人乱码| 欧美视频精品在线| 国产激情无码一区二区三区| 国产美女精品一区二区三区| 欧美一级免费在线观看| 精品一区二区三区中文字幕 | 欧美女子与性| 欧美午夜xxx| 久久久免费看片| 国产综合久久久久久鬼色| 黄色一级大片免费| 欧美三级电影在线| 国产精品亚洲精品| 在线中文字幕视频观看| 亚洲精品国精品久久99热| 6080午夜伦理| 亚洲手机成人高清视频| 老熟女高潮一区二区三区| 国产一级久久| 亚洲一区精彩视频| 大陆精大陆国产国语精品| 日本久久久久久久久久久| 麻豆tv在线| 亚洲国产成人精品电影| 中文字幕第31页| 一区二区三区四区不卡在线| 久久人妻少妇嫩草av无码专区 | 欧美黑人xxx| 天堂资源中文在线| 8x福利精品第一导航| 国产无套在线观看| 国产精品伦理在线| 久久久久久久无码| 久久se精品一区二区| 日本午夜激情视频| 日韩中文首页| 激情视频在线观看一区二区三区| 特级毛片在线| 亚洲香蕉伊综合在人在线视看| 亚洲欧美精品一区二区三区| 国产精品久久影院| 在线免费观看污视频| 久久9热精品视频| 男人操女人逼免费视频| 97视频热人人精品免费| 精品一区二区三区日本| 国产精品3区| 日韩av电影院| av3级在线| 久久手机免费视频| 国产福利电影在线| 亚洲第一视频网站| 国产精品一级视频| 在线观看国产精品网站| 一区二区三区视频免费看| 亚洲三级电影网站| 农村老熟妇乱子伦视频| 久久嫩草精品久久久精品一| 亚洲熟妇一区二区| 韩国成人在线视频| 超碰在线播放91| 午夜宅男久久久| 日韩国产一级片| 欧美/亚洲一区| 咪咪色在线视频| 禁断一区二区三区在线| 精品综合久久| 国产一区丝袜| 国产欧美一区二区三区另类精品| 欧美调教sm| 色综合久久中文字幕综合网小说| 亚洲乱码国产乱码精品精软件| 亚洲国产视频网站| 国产精品视频一区二区三 | 亚洲自拍偷拍一区二区| 国产久卡久卡久卡久卡视频精品| 国内精品视频一区二区三区| 女人香蕉久久**毛片精品| 艳母动漫在线免费观看| 999国产精品视频| 亚洲一区二区三区精品在线观看 | 亚洲wwwww| 欧美v日韩v国产v| 精品国产乱码一区二区三| 欧美日韩免费不卡视频一区二区三区 | 国产精品扒开腿做爽爽爽男男| 日本在线观看免费| 中文字幕一区二区三区电影| 精彩国产在线| 在线播放国产一区二区三区| av黄色在线观看| 日韩中文第一页| 黄色成人在线观看| 欧美精品少妇videofree| 亚洲综合影视| 久久理论片午夜琪琪电影网| 男人添女人下部高潮视频在线观看| 亚洲日本成人网| 爱爱爱免费视频在线观看| 日韩中文字幕精品视频| 黄在线免费看| 色综合男人天堂| 水蜜桃在线视频| 日本欧美一二三区| 久草综合在线| 国产美女久久精品| 精品欧美视频| 精品欧美国产| 欧美精品一区二区三区中文字幕| 成人91视频| 精品综合久久88少妇激情| 久久久国产精品一区二区三区| 国产精品一区三区在线观看| 91pron在线| 香蕉国产成人午夜av影院| 日韩欧美一区二区三区四区五区 | 国产精品美女在线播放| 午夜精品剧场| 国产成人a亚洲精v品无码| 奇米在线7777在线精品| 美女日批在线观看| 91在线视频官网| 亚洲av毛片基地| 亚洲综合一区二区三区| 人人妻人人爽人人澡人人精品| 亚洲成人综合视频| 久久精品久久久久久久| 91麻豆精品国产91久久久 | 午夜欧美性电影| 国产精品88久久久久久| 国产九色porny| 免费国产亚洲视频| 99riav国产精品视频| 国产欧美日韩视频一区二区 | 精品欧美一区二区精品少妇| 亚洲第一二三四五区| 在线视频三区| 69久久夜色精品国产69乱青草| 成全电影大全在线观看| 国产精品成人免费电影| 97久久综合区小说区图片区| 日韩一区二区三区高清| 亚洲91视频| 不卡av免费在线| 不卡av免费在线观看| 永久免费看片直接| 欧美日韩亚洲高清| 国产草草影院ccyycom| 亚洲日本aⅴ片在线观看香蕉| 国产午夜在线观看| 欧美劲爆第一页| av日韩一区| 欧美在线一区二区三区四区| 好看的亚洲午夜视频在线| 日本 片 成人 在线| 26uuu亚洲| 中文字幕第28页| 91精品久久久久久蜜臀| av在线电影免费观看| 17婷婷久久www| 中文无码日韩欧| 99精品视频网站| 久久精品国产精品亚洲精品| 91av在线免费| 亚洲国产wwwccc36天堂| 99热这里只有精品在线观看| 日韩视频第一页| 99热播精品免费| 五月天综合网| 久久婷婷麻豆| 国产传媒第一页| 亚洲成人动漫精品| 男人天堂综合网| 久久久久久久网站| av成人app永久免费| 8x8ⅹ国产精品一区二区二区| 99在线精品免费视频九九视| 国产ts在线观看| 亚洲精选在线视频| 国产伦精品一区二区三区四区| 亚洲国产精品成人一区二区| 中中文字幕av在线| 91久久久一线二线三线品牌| 91免费精品| 中文字幕一区二区三区四| 一区二区中文视频| 国产免费不卡av| 欧美成人小视频| 6080成人| 精品视频在线观看一区| 99视频超级精品| 久久亚洲精品国产| 亚洲一级黄色av| 亚洲国产精选| 超级碰在线观看| 国产91精品精华液一区二区三区| 久久久久久久久福利| 欧美视频精品在线观看| 男人的天堂在线视频免费观看 | 欧美狂野激情性xxxx在线观| 国产美女在线观看一区| 欧美日韩在线视频免费| 精品福利一区二区三区免费视频| 永久免费在线观看视频| 91精品啪在线观看麻豆免费| 在线观看日韩| 亚洲av成人精品一区二区三区 | 国产精品一区二区免费不卡| 天海翼在线视频| 亚洲成人久久网| 韩国精品主播一区二区在线观看| 97人人干人人| 亚洲深夜激情| 992在线观看| 精品国产一区二区精华| 欧美男体视频| 综合网五月天| 91麻豆免费观看| 成人小视频在线播放| 久久成人这里只有精品| 欧美日韩大片免费观看| 日韩一区二区三区不卡视频| 一区二区三区精密机械公司| 男女视频在线观看免费| 91色在线观看| 性欧美精品高清| 51精品免费网站| 日韩h在线观看| 伊人久久大香| 国产毛片视频网站| 国产精品国产自产拍在线| 懂色av一区二区三区四区| 国产成人一区二区在线| 欧美久久一区| www.涩涩爱| 精品视频久久久久久久| 欧美一区在线观看视频| 无需播放器的av| 亚洲国产裸拍裸体视频在线观看乱了|